mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3336fb5b55 | ||
|
|
418a0b27df | ||
|
|
938fa5a012 | ||
|
|
0eb187958d | ||
|
|
26e506f130 | ||
|
|
07888e5efd | ||
|
|
08da2cda0b | ||
|
|
b4ba7b5533 | ||
|
|
bcf91bcd16 | ||
|
|
028936334c | ||
|
|
2e6fd4af4a |
@@ -221,19 +221,17 @@
|
||||
|
||||
"react/display-name": 0,
|
||||
"react/jsx-boolean-value": 0,
|
||||
"react/jsx-no-duplicate-props": 2,
|
||||
"react/jsx-no-undef": 1,
|
||||
"react/jsx-sort-props": 0,
|
||||
"react/jsx-uses-react": 1,
|
||||
"react/jsx-uses-react": 0,
|
||||
"react/jsx-uses-vars": 1,
|
||||
"react/no-did-mount-set-state": [1, "allow-in-func"],
|
||||
"react/no-did-update-set-state": [1, "allow-in-func"],
|
||||
"react/no-multi-comp": 0,
|
||||
"react/no-string-refs": 1,
|
||||
"react/no-unknown-property": 0,
|
||||
"react/prop-types": 0,
|
||||
"react/react-in-jsx-scope": 1,
|
||||
"react/react-in-jsx-scope": 0,
|
||||
"react/self-closing-comp": 1,
|
||||
"react/wrap-multilines": 0,
|
||||
"react/wrap-multilines": 0
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -15,6 +15,8 @@
|
||||
# Ignore react and fbjs where there are overlaps, but don't ignore
|
||||
# anything that react-native relies on
|
||||
.*/node_modules/fbjs/lib/Map.js
|
||||
.*/node_modules/fbjs/lib/fetch.js
|
||||
.*/node_modules/fbjs/lib/ExecutionEnvironment.js
|
||||
.*/node_modules/fbjs/lib/ErrorUtils.js
|
||||
|
||||
# Flow has a built-in definition for the 'react' module which we prefer to use
|
||||
@@ -46,9 +48,6 @@
|
||||
# Ignore BUCK generated folders
|
||||
.*\.buckd/
|
||||
|
||||
# Ignore RNPM
|
||||
.*/local-cli/rnpm/.*
|
||||
|
||||
.*/node_modules/is-my-json-valid/test/.*\.json
|
||||
.*/node_modules/iconv-lite/encodings/tables/.*\.json
|
||||
.*/node_modules/y18n/test/.*\.json
|
||||
@@ -82,15 +81,15 @@ esproposal.class_instance_fields=enable
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\)$' -> 'RelativeImageStub'
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FixMe
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-5]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-5]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-3]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-3]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
|
||||
[version]
|
||||
^0.25.0
|
||||
0.23.0
|
||||
|
||||
@@ -49,6 +49,3 @@ node_modules
|
||||
|
||||
# OS X
|
||||
.DS_Store
|
||||
|
||||
# Test generated files
|
||||
/ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# rnpm
|
||||
/local-cli/rnpm
|
||||
+4
-3
@@ -3,12 +3,13 @@ language: objective-c
|
||||
osx_image: xcode7.3
|
||||
|
||||
install:
|
||||
- brew update
|
||||
- brew reinstall nvm xctool
|
||||
- mkdir -p /Users/travis/build/facebook/.nvm
|
||||
- export NVM_DIR="/Users/travis/build/facebook/.nvm"
|
||||
- brew install nvm
|
||||
- source $(brew --prefix nvm)/nvm.sh
|
||||
# testing with npm@2 for diversity, Circle tests with npm@3
|
||||
- nvm install 4.4.3
|
||||
- nvm install 4.4.0
|
||||
- rm -Rf "${TMPDIR}/jest_preprocess_cache"
|
||||
- npm config set spin=false
|
||||
- npm config set progress=false
|
||||
@@ -16,7 +17,7 @@ install:
|
||||
|
||||
script:
|
||||
- if [[ "$TEST_TYPE" = objc ]]; then travis_retry ./scripts/objc-test.sh; fi
|
||||
- if [[ "$TEST_TYPE" = e2e-objc ]]; then node ./scripts/run-ci-e2e-tests.js --ios --js --retries 3; fi
|
||||
- if [[ "$TEST_TYPE" = e2e-objc ]]; then travis_retry node ./scripts/run-ci-e2e-tests.js --ios --js; fi
|
||||
- if [[ "$TEST_TYPE" = js ]]; then npm run flow check; fi
|
||||
- if [[ "$TEST_TYPE" = js ]]; then npm test -- --maxWorkers=1; fi
|
||||
|
||||
|
||||
@@ -267,10 +267,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/2048/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = 2048;
|
||||
};
|
||||
@@ -288,10 +285,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/2048/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = 2048;
|
||||
};
|
||||
|
||||
@@ -45,6 +45,9 @@ var MovieCell = React.createClass({
|
||||
onShowUnderlay={this.props.onHighlight}
|
||||
onHideUnderlay={this.props.onUnhighlight}>
|
||||
<View style={styles.row}>
|
||||
{/* $FlowIssue #7363964 - There's a bug in Flow where you cannot
|
||||
* omit a property or set it to undefined if it's inside a shape,
|
||||
* even if it isn't required */}
|
||||
<Image
|
||||
source={getImageSource(this.props.movie, 'det')}
|
||||
style={styles.cellImage}
|
||||
|
||||
@@ -34,6 +34,9 @@ var MovieScreen = React.createClass({
|
||||
return (
|
||||
<ScrollView contentContainerStyle={styles.contentContainer}>
|
||||
<View style={styles.mainSection}>
|
||||
{/* $FlowIssue #7363964 - There's a bug in Flow where you cannot
|
||||
* omit a property or set it to undefined if it's inside a shape,
|
||||
* even if it isn't required */}
|
||||
<Image
|
||||
source={getImageSource(this.props.movie, 'det')}
|
||||
style={styles.detailsImage}
|
||||
|
||||
@@ -357,10 +357,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Movies/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Movies;
|
||||
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**";
|
||||
@@ -379,10 +376,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Movies/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Movies;
|
||||
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
jest.unmock('../getImageSource');
|
||||
jest.dontMock('../getImageSource');
|
||||
|
||||
var getImageSource = require('../getImageSource');
|
||||
|
||||
|
||||
@@ -327,10 +327,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/TicTacToe/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = TicTacToe;
|
||||
};
|
||||
@@ -348,10 +345,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/TicTacToe/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = TicTacToe;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
StyleSheet,
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
Image,
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {
|
||||
LayoutAnimation,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
TouchableOpacity,
|
||||
} = ReactNative;
|
||||
|
||||
const AddRemoveExample = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
views: [],
|
||||
};
|
||||
},
|
||||
|
||||
componentWillUpdate() {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
},
|
||||
|
||||
_onPressAddView() {
|
||||
this.setState((state) => ({views: [...state.views, {}]}));
|
||||
},
|
||||
|
||||
_onPressRemoveView() {
|
||||
this.setState((state) => ({views: state.views.slice(0, -1)}));
|
||||
},
|
||||
|
||||
render() {
|
||||
const views = this.state.views.map((view, i) =>
|
||||
<View key={i} style={styles.view}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
);
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={this._onPressAddView}>
|
||||
<View style={styles.button}>
|
||||
<Text>Add view</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={this._onPressRemoveView}>
|
||||
<View style={styles.button}>
|
||||
<Text>Remove view</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<View style={styles.viewContainer}>
|
||||
{views}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const GreenSquare = () =>
|
||||
<View style={styles.greenSquare}>
|
||||
<Text>Green square</Text>
|
||||
</View>;
|
||||
|
||||
const BlueSquare = () =>
|
||||
<View style={styles.blueSquare}>
|
||||
<Text>Blue square</Text>
|
||||
</View>;
|
||||
|
||||
const CrossFadeExample = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
toggled: false,
|
||||
};
|
||||
},
|
||||
|
||||
_onPressToggle() {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
this.setState((state) => ({toggled: !state.toggled}));
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={this._onPressToggle}>
|
||||
<View style={styles.button}>
|
||||
<Text>Toggle</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<View style={styles.viewContainer}>
|
||||
{
|
||||
this.state.toggled ?
|
||||
<GreenSquare /> :
|
||||
<BlueSquare />
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
button: {
|
||||
borderRadius: 5,
|
||||
backgroundColor: '#eeeeee',
|
||||
padding: 10,
|
||||
marginBottom: 10,
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 16,
|
||||
},
|
||||
viewContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
view: {
|
||||
height: 54,
|
||||
width: 54,
|
||||
backgroundColor: 'red',
|
||||
margin: 8,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
greenSquare: {
|
||||
width: 150,
|
||||
height: 150,
|
||||
backgroundColor: 'green',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
blueSquare: {
|
||||
width: 150,
|
||||
height: 150,
|
||||
backgroundColor: 'blue',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = 'Layout Animation';
|
||||
exports.description = 'Layout animation';
|
||||
exports.examples = [{
|
||||
title: 'Add and remove views',
|
||||
render(): ReactElement {
|
||||
return <AddRemoveExample />;
|
||||
},
|
||||
}, {
|
||||
title: 'Cross fade views',
|
||||
render(): ReactElement {
|
||||
return <CrossFadeExample />;
|
||||
},
|
||||
}];
|
||||
@@ -58,20 +58,17 @@ var ListViewSimpleExample = React.createClass({
|
||||
dataSource={this.state.dataSource}
|
||||
renderRow={this._renderRow}
|
||||
renderScrollComponent={props => <RecyclerViewBackedScrollView {...props} />}
|
||||
renderSeparator={this._renderSeperator}
|
||||
renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`} style={styles.separator} />}
|
||||
/>
|
||||
</UIExplorerPage>
|
||||
);
|
||||
},
|
||||
|
||||
_renderRow: function(rowData: string, sectionID: number, rowID: number, highlightRow: (sectionID: number, rowID: number) => void) {
|
||||
_renderRow: function(rowData: string, sectionID: number, rowID: number) {
|
||||
var rowHash = Math.abs(hashCode(rowData));
|
||||
var imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
|
||||
return (
|
||||
<TouchableHighlight onPress={() => {
|
||||
this._pressRow(rowID);
|
||||
highlightRow(sectionID, rowID);
|
||||
}}>
|
||||
<TouchableHighlight onPress={() => this._pressRow(rowID)}>
|
||||
<View>
|
||||
<View style={styles.row}>
|
||||
<Image style={styles.thumb} source={imgSource} />
|
||||
@@ -99,18 +96,6 @@ var ListViewSimpleExample = React.createClass({
|
||||
this._genRows(this._pressData)
|
||||
)});
|
||||
},
|
||||
|
||||
_renderSeperator: function(sectionID: number, rowID: number, adjacentRowHighlighted: bool) {
|
||||
return (
|
||||
<View
|
||||
key={`${sectionID}-${rowID}`}
|
||||
style={{
|
||||
height: adjacentRowHighlighted ? 4 : 1,
|
||||
backgroundColor: adjacentRowHighlighted ? '#3B5998' : '#CCCCCC',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var THUMB_URLS = [
|
||||
@@ -145,6 +130,10 @@ var styles = StyleSheet.create({
|
||||
padding: 10,
|
||||
backgroundColor: '#F6F6F6',
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
backgroundColor: '#CCCCCC',
|
||||
},
|
||||
thumb: {
|
||||
width: 64,
|
||||
height: 64,
|
||||
|
||||
@@ -66,7 +66,7 @@ var Button = React.createClass({
|
||||
var ModalExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
animationType: 'none',
|
||||
animated: true,
|
||||
modalVisible: false,
|
||||
transparent: false,
|
||||
};
|
||||
@@ -76,8 +76,8 @@ var ModalExample = React.createClass({
|
||||
this.setState({modalVisible: visible});
|
||||
},
|
||||
|
||||
_setAnimationType(type) {
|
||||
this.setState({animationType: type});
|
||||
_toggleAnimated() {
|
||||
this.setState({animated: !this.state.animated});
|
||||
},
|
||||
|
||||
_toggleTransparent() {
|
||||
@@ -91,21 +91,18 @@ var ModalExample = React.createClass({
|
||||
var innerContainerTransparentStyle = this.state.transparent
|
||||
? {backgroundColor: '#fff', padding: 20}
|
||||
: null;
|
||||
var activeButtonStyle = {
|
||||
backgroundColor: '#ddd'
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Modal
|
||||
animationType={this.state.animationType}
|
||||
animated={this.state.animated}
|
||||
transparent={this.state.transparent}
|
||||
visible={this.state.modalVisible}
|
||||
onRequestClose={() => {this._setModalVisible(false)}}
|
||||
>
|
||||
<View style={[styles.container, modalBackgroundStyle]}>
|
||||
<View style={[styles.innerContainer, innerContainerTransparentStyle]}>
|
||||
<Text>This modal was presented {this.state.animationType === 'none' ? 'without' : 'with'} animation.</Text>
|
||||
<Text>This modal was presented {this.state.animated ? 'with' : 'without'} animation.</Text>
|
||||
<Button
|
||||
onPress={this._setModalVisible.bind(this, false)}
|
||||
style={styles.modalButton}>
|
||||
@@ -114,17 +111,10 @@ var ModalExample = React.createClass({
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
<View style={styles.row}>
|
||||
<Text style={styles.rowTitle}>Animation Type</Text>
|
||||
<Button onPress={this._setAnimationType.bind(this, 'none')} style={this.state.animationType === 'none' ? activeButtonStyle : {}}>
|
||||
none
|
||||
</Button>
|
||||
<Button onPress={this._setAnimationType.bind(this, 'slide')} style={this.state.animationType === 'slide' ? activeButtonStyle : {}}>
|
||||
slide
|
||||
</Button>
|
||||
<Button onPress={this._setAnimationType.bind(this, 'fade')} style={this.state.animationType === 'fade' ? activeButtonStyle : {}}>
|
||||
fade
|
||||
</Button>
|
||||
<Text style={styles.rowTitle}>Animated</Text>
|
||||
<Switch value={this.state.animated} onValueChange={this._toggleAnimated} />
|
||||
</View>
|
||||
|
||||
<View style={styles.row}>
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
NavigationExperimental,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity
|
||||
} = ReactNative;
|
||||
|
||||
var _getRandomRoute = function() {
|
||||
return {
|
||||
title: '#' + Math.ceil(Math.random() * 1000),
|
||||
};
|
||||
};
|
||||
|
||||
var Navigator = NavigationExperimental.LegacyNavigator;
|
||||
|
||||
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 BreadcrumbNavSample = React.createClass({
|
||||
|
||||
componentWillMount: function() {
|
||||
this._navBarRouteMapper = {
|
||||
rightContentForRoute: function(route, navigator) {
|
||||
return null;
|
||||
},
|
||||
titleContentForRoute: function(route, navigator) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => navigator.push(_getRandomRoute())}>
|
||||
<Text style={styles.titleText}>{route.title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
},
|
||||
iconForRoute: function(route, navigator) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => { navigator.popToRoute(route); }}
|
||||
style={styles.crumbIconPlaceholder}
|
||||
/>
|
||||
);
|
||||
},
|
||||
separatorForRoute: function(route, navigator) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={navigator.pop}
|
||||
style={styles.crumbSeparatorPlaceholder}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
_renderScene: function(route, navigator) {
|
||||
return (
|
||||
<ScrollView style={styles.scene}>
|
||||
<NavButton
|
||||
onPress={() => { navigator.push(_getRandomRoute()); }}
|
||||
text="Push"
|
||||
/>
|
||||
<NavButton
|
||||
onPress={() => { navigator.immediatelyResetRouteStack([_getRandomRoute(), _getRandomRoute()]); }}
|
||||
text="Reset w/ 2 scenes"
|
||||
/>
|
||||
<NavButton
|
||||
onPress={() => { navigator.popToTop(); }}
|
||||
text="Pop to top"
|
||||
/>
|
||||
<NavButton
|
||||
onPress={() => { navigator.replace(_getRandomRoute()); }}
|
||||
text="Replace"
|
||||
/>
|
||||
<NavButton
|
||||
onPress={() => { this.props.navigator.pop(); }}
|
||||
text="Close breadcrumb example"
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<Navigator
|
||||
style={styles.container}
|
||||
initialRoute={_getRandomRoute()}
|
||||
renderScene={this._renderScene}
|
||||
navigationBar={
|
||||
<Navigator.BreadcrumbNavigationBar
|
||||
routeMapper={this._navBarRouteMapper}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
scene: {
|
||||
paddingTop: 50,
|
||||
flex: 1,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: 'white',
|
||||
padding: 15,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: '#CDCDCD',
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
},
|
||||
container: {
|
||||
overflow: 'hidden',
|
||||
backgroundColor: '#dddddd',
|
||||
flex: 1,
|
||||
},
|
||||
titleText: {
|
||||
fontSize: 18,
|
||||
color: '#666666',
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
lineHeight: 32,
|
||||
},
|
||||
crumbIconPlaceholder: {
|
||||
flex: 1,
|
||||
backgroundColor: '#666666',
|
||||
},
|
||||
crumbSeparatorPlaceholder: {
|
||||
flex: 1,
|
||||
backgroundColor: '#aaaaaa',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = BreadcrumbNavSample;
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
NavigationExperimental,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TabBarIOS,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
} = ReactNative;
|
||||
|
||||
var _getRandomRoute = function() {
|
||||
return {
|
||||
randNumber: Math.ceil(Math.random() * 1000),
|
||||
};
|
||||
};
|
||||
|
||||
var Navigator = NavigationExperimental.LegacyNavigator;
|
||||
|
||||
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 = [
|
||||
_getRandomRoute(),
|
||||
_getRandomRoute(),
|
||||
_getRandomRoute(),
|
||||
];
|
||||
var INIT_ROUTE_INDEX = 1;
|
||||
|
||||
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() {
|
||||
return (
|
||||
<View style={styles.tabs}>
|
||||
<TabBarIOS>
|
||||
<TabBarIOS.Item
|
||||
icon={require('image!tabnav_notification')}
|
||||
selected={this.state.tabIndex === 0}
|
||||
onPress={() => {
|
||||
this.props.onTabIndex(0);
|
||||
this.setState({ tabIndex: 0, });
|
||||
}}>
|
||||
<View />
|
||||
</TabBarIOS.Item>
|
||||
<TabBarIOS.Item
|
||||
icon={require('image!tabnav_list')}
|
||||
selected={this.state.tabIndex === 1}
|
||||
onPress={() => {
|
||||
this.props.onTabIndex(1);
|
||||
this.setState({ tabIndex: 1, });
|
||||
}}>
|
||||
<View />
|
||||
</TabBarIOS.Item>
|
||||
<TabBarIOS.Item
|
||||
icon={require('image!tabnav_settings')}
|
||||
selected={this.state.tabIndex === 2}
|
||||
onPress={() => {
|
||||
this.props.onTabIndex(2);
|
||||
this.setState({ tabIndex: 2, });
|
||||
}}>
|
||||
<View />
|
||||
</TabBarIOS.Item>
|
||||
</TabBarIOS>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var JumpingNavSample = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<Navigator
|
||||
debugOverlay={false}
|
||||
style={styles.appContainer}
|
||||
ref={(navigator) => {
|
||||
this._navigator = navigator;
|
||||
}}
|
||||
initialRoute={ROUTE_STACK[INIT_ROUTE_INDEX]}
|
||||
initialRouteStack={ROUTE_STACK}
|
||||
renderScene={this.renderScene}
|
||||
configureScene={() => ({
|
||||
...Navigator.SceneConfigs.HorizontalSwipeJump,
|
||||
})}
|
||||
navigationBar={
|
||||
<JumpingNavBar
|
||||
ref={(navBar) => { this.navBar = navBar; }}
|
||||
initTabIndex={INIT_ROUTE_INDEX}
|
||||
routeStack={ROUTE_STACK}
|
||||
onTabIndex={(index) => {
|
||||
this._navigator.jumpTo(ROUTE_STACK[index]);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
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({
|
||||
button: {
|
||||
backgroundColor: 'white',
|
||||
padding: 15,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: '#CDCDCD',
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
},
|
||||
appContainer: {
|
||||
overflow: 'hidden',
|
||||
backgroundColor: '#dddddd',
|
||||
flex: 1,
|
||||
},
|
||||
messageText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
padding: 15,
|
||||
marginTop: 50,
|
||||
marginLeft: 15,
|
||||
},
|
||||
scene: {
|
||||
flex: 1,
|
||||
paddingTop: 20,
|
||||
backgroundColor: '#EAEAEA',
|
||||
},
|
||||
tabs: {
|
||||
height: 50,
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = JumpingNavSample;
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
NavigationExperimental,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
} = ReactNative;
|
||||
|
||||
var BreadcrumbNavSample = require('./BreadcrumbNavSample');
|
||||
var NavigationBarSample = require('./NavigationBarSample');
|
||||
var JumpingNavSample = require('./JumpingNavSample');
|
||||
|
||||
var Navigator = NavigationExperimental.LegacyNavigator;
|
||||
|
||||
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 {
|
||||
render() {
|
||||
return (
|
||||
<ScrollView style={styles.scene}>
|
||||
<Text style={styles.messageText}>{this.props.message}</Text>
|
||||
<NavButton
|
||||
onPress={() => {
|
||||
this.props.navigator.push({
|
||||
message: 'Swipe right to dismiss',
|
||||
sceneConfig: Navigator.SceneConfigs.FloatFromRight,
|
||||
});
|
||||
}}
|
||||
text="Float in from right"
|
||||
/>
|
||||
<NavButton
|
||||
onPress={() => {
|
||||
this.props.navigator.push({
|
||||
message: 'Swipe down to dismiss',
|
||||
sceneConfig: Navigator.SceneConfigs.FloatFromBottom,
|
||||
});
|
||||
}}
|
||||
text="Float in from bottom"
|
||||
/>
|
||||
<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 <LegacyNavigator> Example"
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var TabBarExample = React.createClass({
|
||||
|
||||
statics: {
|
||||
title: '<LegacyNavigator> (Experimental)',
|
||||
description: 'Experimental navigator that ports the API of the current ' +
|
||||
'Navigator component',
|
||||
},
|
||||
|
||||
renderScene: function(route, nav) {
|
||||
switch (route.id) {
|
||||
case 'navbar':
|
||||
return <NavigationBarSample navigator={nav} />;
|
||||
case 'breadcrumbs':
|
||||
return <BreadcrumbNavSample navigator={nav} />;
|
||||
case 'jumping':
|
||||
return <JumpingNavSample navigator={nav} />;
|
||||
default:
|
||||
return (
|
||||
<NavMenu
|
||||
message={route.message}
|
||||
navigator={nav}
|
||||
onExampleExit={this.props.onExampleExit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<Navigator
|
||||
ref={this._setNavigatorRef}
|
||||
style={styles.container}
|
||||
initialRoute={{ message: 'First Scene', }}
|
||||
renderScene={this.renderScene}
|
||||
configureScene={(route) => {
|
||||
if (route.sceneConfig) {
|
||||
return route.sceneConfig;
|
||||
}
|
||||
return Navigator.SceneConfigs.FloatFromBottom;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this._listeners && this._listeners.forEach(listener => listener.remove());
|
||||
},
|
||||
|
||||
_setNavigatorRef: function(navigator) {
|
||||
if (navigator !== this._navigator) {
|
||||
this._navigator = navigator;
|
||||
|
||||
if (navigator) {
|
||||
var callback = (event) => {
|
||||
console.log(
|
||||
`LegacyNavigator: event ${event.type}`,
|
||||
{
|
||||
route: JSON.stringify(event.data.route),
|
||||
target: event.target,
|
||||
type: event.type,
|
||||
}
|
||||
);
|
||||
};
|
||||
// Observe focus change events from the owner.
|
||||
this._listeners = [
|
||||
navigator.navigationContext.addListener('willfocus', callback),
|
||||
navigator.navigationContext.addListener('didfocus', callback),
|
||||
];
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
messageText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
padding: 15,
|
||||
marginTop: 50,
|
||||
marginLeft: 15,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: 'white',
|
||||
padding: 15,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: '#CDCDCD',
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
},
|
||||
scene: {
|
||||
flex: 1,
|
||||
paddingTop: 20,
|
||||
backgroundColor: '#ccc',
|
||||
}
|
||||
});
|
||||
|
||||
TabBarExample.external = true;
|
||||
|
||||
module.exports = TabBarExample;
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
NavigationExperimental,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
} = ReactNative;
|
||||
|
||||
var Navigator = NavigationExperimental.LegacyNavigator;
|
||||
|
||||
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 = {
|
||||
|
||||
LeftButton: function(route, navigator, index, navState) {
|
||||
if (index === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var previousRoute = navState.routeStack[index - 1];
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => navigator.pop()}
|
||||
style={styles.navBarLeftButton}>
|
||||
<Text style={[styles.navBarText, styles.navBarButtonText]}>
|
||||
{previousRoute.title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
},
|
||||
|
||||
RightButton: function(route, navigator, index, navState) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => navigator.push(newRandomRoute())}
|
||||
style={styles.navBarRightButton}>
|
||||
<Text style={[styles.navBarText, styles.navBarButtonText]}>
|
||||
Next
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
},
|
||||
|
||||
Title: function(route, navigator, index, navState) {
|
||||
return (
|
||||
<Text style={[styles.navBarText, styles.navBarTitleText]}>
|
||||
{route.title} [{index}]
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
function newRandomRoute() {
|
||||
return {
|
||||
title: '#' + Math.ceil(Math.random() * 1000),
|
||||
};
|
||||
}
|
||||
|
||||
var NavigationBarSample = React.createClass({
|
||||
|
||||
componentWillMount: function() {
|
||||
var navigator = this.props.navigator;
|
||||
|
||||
var callback = (event) => {
|
||||
console.log(
|
||||
`NavigationBarSample : event ${event.type}`,
|
||||
{
|
||||
route: JSON.stringify(event.data.route),
|
||||
target: event.target,
|
||||
type: event.type,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Observe focus change events from this component.
|
||||
this._listeners = [
|
||||
navigator.navigationContext.addListener('willfocus', callback),
|
||||
navigator.navigationContext.addListener('didfocus', callback),
|
||||
];
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this._listeners && this._listeners.forEach(listener => listener.remove());
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<Navigator
|
||||
debugOverlay={false}
|
||||
style={styles.appContainer}
|
||||
initialRoute={newRandomRoute()}
|
||||
renderScene={(route, navigator) => (
|
||||
<ScrollView style={styles.scene}>
|
||||
<Text style={styles.messageText}>{route.content}</Text>
|
||||
<NavButton
|
||||
onPress={() => {
|
||||
navigator.immediatelyResetRouteStack([
|
||||
newRandomRoute(),
|
||||
newRandomRoute(),
|
||||
newRandomRoute(),
|
||||
]);
|
||||
}}
|
||||
text="Reset w/ 3 scenes"
|
||||
/>
|
||||
<NavButton
|
||||
onPress={() => {
|
||||
this.props.navigator.pop();
|
||||
}}
|
||||
text="Exit NavigationBar Example"
|
||||
/>
|
||||
</ScrollView>
|
||||
)}
|
||||
navigationBar={
|
||||
<Navigator.NavigationBar
|
||||
routeMapper={NavigationBarRouteMapper}
|
||||
style={styles.navBar}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
messageText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
padding: 15,
|
||||
marginTop: 50,
|
||||
marginLeft: 15,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: 'white',
|
||||
padding: 15,
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: '#CDCDCD',
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '500',
|
||||
},
|
||||
navBar: {
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
navBarText: {
|
||||
fontSize: 16,
|
||||
marginVertical: 10,
|
||||
},
|
||||
navBarTitleText: {
|
||||
color: '#373E4D',
|
||||
fontWeight: '500',
|
||||
marginVertical: 9,
|
||||
},
|
||||
navBarLeftButton: {
|
||||
paddingLeft: 10,
|
||||
},
|
||||
navBarRightButton: {
|
||||
paddingRight: 10,
|
||||
},
|
||||
navBarButtonText: {
|
||||
color: '#5890FF',
|
||||
},
|
||||
scene: {
|
||||
flex: 1,
|
||||
paddingTop: 20,
|
||||
backgroundColor: '#EAEAEA',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = NavigationBarSample;
|
||||
@@ -37,9 +37,10 @@ const {
|
||||
Card: NavigationCard,
|
||||
Header: NavigationHeader,
|
||||
Reducer: NavigationReducer,
|
||||
RootContainer: NavigationRootContainer,
|
||||
} = NavigationExperimental;
|
||||
|
||||
const ExampleReducer = NavigationReducer.StackReducer({
|
||||
const NavigationBasicReducer = NavigationReducer.StackReducer({
|
||||
getPushedReducerForAction: (action) => {
|
||||
if (action.type === 'push') {
|
||||
return (state) => state || {key: action.key};
|
||||
@@ -57,41 +58,37 @@ const ExampleReducer = NavigationReducer.StackReducer({
|
||||
});
|
||||
|
||||
class NavigationAnimatedExample extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = ExampleReducer();
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._renderCard = this._renderCard.bind(this);
|
||||
this._renderHeader = this._renderHeader.bind(this);
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._renderTitleComponent = this._renderTitleComponent.bind(this);
|
||||
this._handleAction = this._handleAction.bind(this);
|
||||
}
|
||||
|
||||
_handleAction(action): boolean {
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
const newState = ExampleReducer(this.state, action);
|
||||
if (newState === this.state) {
|
||||
return false;
|
||||
}
|
||||
this.setState(newState);
|
||||
return true;
|
||||
}
|
||||
|
||||
handleBackAction(): boolean {
|
||||
return this._handleAction({ type: 'BackAction', });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<NavigationRootContainer
|
||||
reducer={NavigationBasicReducer}
|
||||
ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
|
||||
persistenceKey="NavigationAnimExampleState"
|
||||
renderNavigation={this._renderNavigation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
handleBackAction() {
|
||||
return (
|
||||
this.navRootContainer &&
|
||||
this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
|
||||
);
|
||||
}
|
||||
_renderNavigation(navigationState, onNavigate) {
|
||||
if (!navigationState) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<NavigationAnimatedView
|
||||
navigationState={this.state}
|
||||
navigationState={navigationState}
|
||||
style={styles.animatedView}
|
||||
onNavigate={this._handleAction}
|
||||
renderOverlay={this._renderHeader}
|
||||
applyAnimation={(pos, navState) => {
|
||||
Animated.timing(pos, {toValue: navState.index, duration: 500}).start();
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -29,10 +22,12 @@ const {
|
||||
} = ReactNative;
|
||||
const NavigationExampleRow = require('./NavigationExampleRow');
|
||||
const {
|
||||
RootContainer: NavigationRootContainer,
|
||||
Reducer: NavigationReducer,
|
||||
} = NavigationExperimental;
|
||||
const StackReducer = NavigationReducer.StackReducer;
|
||||
|
||||
const ExampleReducer = NavigationReducer.StackReducer({
|
||||
const NavigationBasicReducer = NavigationReducer.StackReducer({
|
||||
getPushedReducerForAction: (action) => {
|
||||
if (action.type === 'push') {
|
||||
return (state) => state || {key: action.key};
|
||||
@@ -50,51 +45,47 @@ const ExampleReducer = NavigationReducer.StackReducer({
|
||||
});
|
||||
|
||||
const NavigationBasicExample = React.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return ExampleReducer();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<ScrollView style={styles.topView}>
|
||||
<NavigationExampleRow
|
||||
text={`Current page: ${this.state.children[this.state.index].key}`}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text={`Push page #${this.state.children.length}`}
|
||||
onPress={() => {
|
||||
this._handleAction({ type: 'push', key: 'page #' + this.state.children.length });
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="pop"
|
||||
onPress={() => {
|
||||
this._handleAction({ type: 'BackAction' });
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Exit Basic Nav Example"
|
||||
onPress={this.props.onExampleExit}
|
||||
/>
|
||||
</ScrollView>
|
||||
<NavigationRootContainer
|
||||
reducer={NavigationBasicReducer}
|
||||
persistenceKey="NavigationBasicExampleState"
|
||||
ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
|
||||
renderNavigation={(navState, onNavigate) => {
|
||||
if (!navState) { return null; }
|
||||
return (
|
||||
<ScrollView style={styles.topView}>
|
||||
<NavigationExampleRow
|
||||
text={`Current page: ${navState.children[navState.index].key}`}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text={`Push page #${navState.children.length}`}
|
||||
onPress={() => {
|
||||
onNavigate({ type: 'push', key: 'page #' + navState.children.length });
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="pop"
|
||||
onPress={() => {
|
||||
onNavigate(NavigationRootContainer.getBackAction());
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Exit Basic Nav Example"
|
||||
onPress={this.props.onExampleExit}
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
_handleAction(action) {
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
const newState = ExampleReducer(this.state, action);
|
||||
if (newState === this.state) {
|
||||
return false;
|
||||
}
|
||||
this.setState(newState);
|
||||
return true;
|
||||
},
|
||||
|
||||
handleBackAction() {
|
||||
return this._handleAction({ type: 'BackAction' });
|
||||
handleBackAction: function() {
|
||||
return (
|
||||
this.navRootContainer &&
|
||||
this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
|
||||
);
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
@@ -33,15 +33,18 @@ const {
|
||||
const {
|
||||
CardStack: NavigationCardStack,
|
||||
StateUtils: NavigationStateUtils,
|
||||
RootContainer: NavigationRootContainer,
|
||||
} = NavigationExperimental;
|
||||
|
||||
function createReducer(initialState) {
|
||||
return (currentState = initialState, action) => {
|
||||
return (currentState, action) => {
|
||||
switch (action.type) {
|
||||
case 'RootContainerInitialAction':
|
||||
return initialState;
|
||||
|
||||
case 'push':
|
||||
return NavigationStateUtils.push(currentState, {key: action.key});
|
||||
|
||||
case 'BackAction':
|
||||
case 'back':
|
||||
case 'pop':
|
||||
return currentState.index > 0 ?
|
||||
@@ -64,46 +67,35 @@ class NavigationCardStackExample extends React.Component {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
isHorizontal: true,
|
||||
navState: ExampleReducer(undefined, {}),
|
||||
};
|
||||
this.state = {isHorizontal: true};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._toggleDirection = this._toggleDirection.bind(this);
|
||||
this._handleAction = this._handleAction.bind(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<NavigationCardStack
|
||||
direction={this.state.isHorizontal ? 'horizontal' : 'vertical'}
|
||||
navigationState={this.state.navState}
|
||||
onNavigate={this._handleAction}
|
||||
renderScene={this._renderScene}
|
||||
<NavigationRootContainer
|
||||
reducer={ExampleReducer}
|
||||
renderNavigation={this._renderNavigation}
|
||||
style={styles.main}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_handleAction(action): boolean {
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
const newState = ExampleReducer(this.state.navState, action);
|
||||
if (newState === this.state.navState) {
|
||||
return false;
|
||||
}
|
||||
this.setState({
|
||||
navState: newState,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
handleBackAction(): boolean {
|
||||
return this._handleAction({ type: 'BackAction', });
|
||||
_renderNavigation(navigationState, onNavigate) {
|
||||
return (
|
||||
<NavigationCardStack
|
||||
direction={this.state.isHorizontal ? 'horizontal' : 'vertical'}
|
||||
navigationState={navigationState}
|
||||
onNavigate={onNavigate}
|
||||
renderScene={this._renderScene}
|
||||
style={styles.main}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(/*NavigationSceneRendererProps*/ props) {
|
||||
|
||||
@@ -36,8 +36,11 @@ const {
|
||||
|
||||
const {
|
||||
CardStack: NavigationCardStack,
|
||||
Container: NavigationContainer,
|
||||
Header: NavigationHeader,
|
||||
Reducer: NavigationReducer,
|
||||
RootContainer: NavigationRootContainer,
|
||||
View: NavigationView,
|
||||
} = NavigationExperimental;
|
||||
|
||||
|
||||
@@ -174,7 +177,6 @@ class ExampleTabScreen extends React.Component {
|
||||
<NavigationCardStack
|
||||
style={styles.tabContent}
|
||||
navigationState={this.props.navigationState}
|
||||
onNavigate={this.props.onNavigate}
|
||||
renderOverlay={this._renderHeader}
|
||||
renderScene={this._renderScene}
|
||||
/>
|
||||
@@ -223,42 +225,40 @@ class ExampleTabScreen extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
ExampleTabScreen = NavigationContainer.create(ExampleTabScreen);
|
||||
|
||||
class NavigationCompositionExample extends React.Component {
|
||||
state: NavigationParentState;
|
||||
constructor() {
|
||||
super();
|
||||
this.state = ExampleAppReducer(undefined, {});
|
||||
}
|
||||
handleAction(action: Object): boolean {
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
const newState = ExampleAppReducer(this.state, action);
|
||||
if (newState === this.state) {
|
||||
return false;
|
||||
}
|
||||
this.setState(newState);
|
||||
return true;
|
||||
navRootContainer: NavigationRootContainer;
|
||||
|
||||
render() {
|
||||
return (
|
||||
<NavigationRootContainer
|
||||
reducer={ExampleAppReducer}
|
||||
persistenceKey="NavigationCompositionState"
|
||||
ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
|
||||
renderNavigation={this.renderApp.bind(this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
handleBackAction(): boolean {
|
||||
return this.handleAction({ type: 'BackAction' });
|
||||
return (
|
||||
this.navRootContainer &&
|
||||
this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
|
||||
);
|
||||
}
|
||||
render() {
|
||||
if (!this.state) {
|
||||
renderApp(navigationState: NavigationParentState, onNavigate: Function) {
|
||||
if (!navigationState) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View style={styles.topView}>
|
||||
<ExampleMainView
|
||||
navigationState={this.state}
|
||||
navigationState={navigationState}
|
||||
onExampleExit={this.props.onExampleExit}
|
||||
onNavigate={this.handleAction.bind(this)}
|
||||
/>
|
||||
<NavigationExampleTabBar
|
||||
tabs={this.state.children}
|
||||
index={this.state.index}
|
||||
onNavigate={this.handleAction.bind(this)}
|
||||
tabs={navigationState.children}
|
||||
index={navigationState.index}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -266,35 +266,34 @@ class NavigationCompositionExample extends React.Component {
|
||||
}
|
||||
|
||||
class ExampleMainView extends React.Component {
|
||||
_renderScene: Function;
|
||||
_handleNavigation: Function;
|
||||
_renderScene: NavigationSceneRenderer;
|
||||
|
||||
componentWillMount() {
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._handleNavigation = this._handleNavigation.bind(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.tabsContent}>
|
||||
{this._renderScene()}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(): ReactElement {
|
||||
const {navigationState} = this.props;
|
||||
const childState = navigationState.children[navigationState.index];
|
||||
return (
|
||||
<ExampleTabScreen
|
||||
key={'tab_screen' + childState.key}
|
||||
navigationState={childState}
|
||||
onNavigate={this._handleNavigation}
|
||||
<NavigationView
|
||||
navigationState={this.props.navigationState}
|
||||
style={styles.tabsContent}
|
||||
renderScene={this._renderScene}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_handleNavigation(action: Object) {
|
||||
_renderScene(props: NavigationSceneRendererProps): ReactElement {
|
||||
const {scene} = props;
|
||||
return (
|
||||
<ExampleTabScreen
|
||||
key={'tab_screen' + scene.key}
|
||||
navigationState={scene.navigationState}
|
||||
onNavigate={this._handleNavigation.bind(this, scene.key)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_handleNavigation(tabKey, action) {
|
||||
if (ExampleExitAction.match(action)) {
|
||||
this.props.onExampleExit();
|
||||
return;
|
||||
@@ -303,6 +302,8 @@ class ExampleMainView extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
ExampleMainView = NavigationContainer.create(ExampleMainView);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
topView: {
|
||||
flex: 1,
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -20,20 +13,24 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const NavigationExperimental = require('NavigationExperimental');
|
||||
const React = require('react');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const Text = require('Text');
|
||||
const TouchableOpacity = require('TouchableOpacity');
|
||||
const View = require('View');
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
NavigationExperimental,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} = ReactNative;
|
||||
const {
|
||||
Container: NavigationContainer,
|
||||
Reducer: NavigationReducer,
|
||||
} = NavigationExperimental;
|
||||
const {
|
||||
JumpToAction,
|
||||
} = NavigationReducer.TabsReducer;
|
||||
|
||||
const NavigationExampleTabBar = React.createClass({
|
||||
var NavigationExampleTabBar = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.tabBar}>
|
||||
@@ -42,7 +39,7 @@ const NavigationExampleTabBar = React.createClass({
|
||||
);
|
||||
},
|
||||
_renderTab: function(tab, index) {
|
||||
const textStyle = [styles.tabButtonText];
|
||||
var textStyle = [styles.tabButtonText];
|
||||
if (this.props.index === index) {
|
||||
textStyle.push(styles.selectedTabButtonText);
|
||||
}
|
||||
@@ -61,6 +58,8 @@ const NavigationExampleTabBar = React.createClass({
|
||||
},
|
||||
});
|
||||
|
||||
NavigationExampleTabBar = NavigationContainer.create(NavigationExampleTabBar);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
height: 50,
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -20,19 +13,22 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AsyncStorage = require('AsyncStorage');
|
||||
const NavigationExampleRow = require('./NavigationExampleRow');
|
||||
const React = require('react');
|
||||
const ScrollView = require('ScrollView');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const View = require('View');
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
AsyncStorage,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
} = ReactNative;
|
||||
var NavigationExampleRow = require('./NavigationExampleRow');
|
||||
|
||||
/*
|
||||
* Heads up! This file is not the real navigation example- only a utility to switch between them.
|
||||
*
|
||||
* To learn how to use the Navigation API, take a look at the following example files:
|
||||
*/
|
||||
const EXAMPLES = {
|
||||
var EXAMPLES = {
|
||||
'Tabs': require('./NavigationTabsExample'),
|
||||
'Basic': require('./NavigationBasicExample'),
|
||||
'Animated Example': require('./NavigationAnimatedExample'),
|
||||
@@ -41,9 +37,9 @@ const EXAMPLES = {
|
||||
'Tic Tac Toe': require('./NavigationTicTacToeExample'),
|
||||
};
|
||||
|
||||
const EXAMPLE_STORAGE_KEY = 'NavigationExperimentalExample';
|
||||
var EXAMPLE_STORAGE_KEY = 'NavigationExperimentalExample';
|
||||
|
||||
const NavigationExperimentalExample = React.createClass({
|
||||
var NavigationExperimentalExample = React.createClass({
|
||||
statics: {
|
||||
title: 'Navigation (Experimental)',
|
||||
description: 'Upcoming navigation APIs and animated navigation views',
|
||||
@@ -78,7 +74,7 @@ const NavigationExperimentalExample = React.createClass({
|
||||
},
|
||||
|
||||
_renderMenu: function() {
|
||||
let exitRow = null;
|
||||
var exitRow = null;
|
||||
if (this.props.onExampleExit) {
|
||||
exitRow = (
|
||||
<NavigationExampleRow
|
||||
@@ -134,7 +130,7 @@ const NavigationExperimentalExample = React.createClass({
|
||||
return this._renderMenu();
|
||||
}
|
||||
if (EXAMPLES[this.state.example]) {
|
||||
const Component = EXAMPLES[this.state.example];
|
||||
var Component = EXAMPLES[this.state.example];
|
||||
return (
|
||||
<Component
|
||||
onExampleExit={this._exitInnerExample}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -29,6 +22,8 @@ const {
|
||||
View,
|
||||
} = ReactNative;
|
||||
const {
|
||||
Container: NavigationContainer,
|
||||
RootContainer: NavigationRootContainer,
|
||||
Reducer: NavigationReducer,
|
||||
} = NavigationExperimental;
|
||||
|
||||
@@ -60,6 +55,7 @@ class ExmpleTabPage extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
ExmpleTabPage = NavigationContainer.create(ExmpleTabPage);
|
||||
|
||||
const ExampleTabsReducer = NavigationReducer.TabsReducer({
|
||||
tabReducers: [
|
||||
@@ -70,40 +66,36 @@ const ExampleTabsReducer = NavigationReducer.TabsReducer({
|
||||
});
|
||||
|
||||
class NavigationTabsExample extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = ExampleTabsReducer(undefined, {});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.topView}>
|
||||
<ExmpleTabPage
|
||||
tabs={this.state.children}
|
||||
index={this.state.index}
|
||||
onExampleExit={this.props.onExampleExit}
|
||||
onNavigate={this.handleAction.bind(this)}
|
||||
/>
|
||||
<NavigationExampleTabBar
|
||||
tabs={this.state.children}
|
||||
index={this.state.index}
|
||||
onNavigate={this.handleAction.bind(this)}
|
||||
/>
|
||||
</View>
|
||||
<NavigationRootContainer
|
||||
reducer={ExampleTabsReducer}
|
||||
persistenceKey="NAV_EXAMPLE_STATE_TABS"
|
||||
ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
|
||||
renderNavigation={(navigationState) => {
|
||||
if (!navigationState) { return null; }
|
||||
return (
|
||||
<View style={styles.topView}>
|
||||
<ExmpleTabPage
|
||||
tabs={navigationState.children}
|
||||
index={navigationState.index}
|
||||
onExampleExit={this.props.onExampleExit}
|
||||
/>
|
||||
<NavigationExampleTabBar
|
||||
tabs={navigationState.children}
|
||||
index={navigationState.index}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
handleAction(action) {
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
const newState = ExampleTabsReducer(this.state, action);
|
||||
if (newState === this.state) {
|
||||
return false;
|
||||
}
|
||||
this.setState(newState);
|
||||
return true;
|
||||
}
|
||||
handleBackAction() {
|
||||
return this.handleAction({ type: 'BackAction' });
|
||||
return (
|
||||
this.navRootContainer &&
|
||||
this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -23,11 +16,19 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const Text = require('Text');
|
||||
const TouchableHighlight = require('TouchableHighlight');
|
||||
const View = require('View');
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
NavigationExperimental,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
} = ReactNative;
|
||||
const {
|
||||
Container: NavigationContainer,
|
||||
RootContainer: NavigationRootContainer,
|
||||
} = NavigationExperimental;
|
||||
|
||||
type GameGrid = Array<Array<?string>>;
|
||||
|
||||
@@ -40,7 +41,7 @@ function parseGame(game: string): GameGrid {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const row = Array(3);
|
||||
for (let j = 0; j < 3; j++) {
|
||||
const turnIndex = gameTurns.indexOf(rowLetterMap[i] + j);
|
||||
const turnIndex = gameTurns.indexOf(rowLetterMap[i]+j);
|
||||
if (turnIndex === -1) {
|
||||
row[j] = null;
|
||||
} else {
|
||||
@@ -59,13 +60,13 @@ function playTurn(game: string, row: number, col: number): string {
|
||||
|
||||
function getWinner(gameString: string): ?string {
|
||||
const game = parseGame(gameString);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (game[i][0] !== null && game[i][0] === game[i][1] &&
|
||||
game[i][0] === game[i][2]) {
|
||||
return game[i][0];
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (game[0][i] !== null && game[0][i] === game[1][i] &&
|
||||
game[0][i] === game[2][i]) {
|
||||
return game[0][i];
|
||||
@@ -87,8 +88,8 @@ function isGameOver(gameString: string): boolean {
|
||||
return true;
|
||||
}
|
||||
const game = parseGame(gameString);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let j = 0; j < 3; j++) {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
for (var j = 0; j < 3; j++) {
|
||||
if (game[i][j] === null) {
|
||||
return false;
|
||||
}
|
||||
@@ -156,9 +157,10 @@ function GameEndOverlay(props) {
|
||||
</View>
|
||||
);
|
||||
}
|
||||
GameEndOverlay = NavigationContainer.create(GameEndOverlay);
|
||||
|
||||
function TicTacToeGame(props) {
|
||||
const rows = parseGame(props.game).map((cells, row) =>
|
||||
var rows = parseGame(props.game).map((cells, row) =>
|
||||
<View key={'row' + row} style={styles.row}>
|
||||
{cells.map((player, col) =>
|
||||
<Cell
|
||||
@@ -182,11 +184,11 @@ function TicTacToeGame(props) {
|
||||
</View>
|
||||
<GameEndOverlay
|
||||
game={props.game}
|
||||
onNavigate={props.onNavigate}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
TicTacToeGame = NavigationContainer.create(TicTacToeGame);
|
||||
|
||||
const GameActions = {
|
||||
Turn: (row, col) => ({type: 'TicTacToeTurnAction', row, col }),
|
||||
@@ -206,34 +208,21 @@ function GameReducer(lastGame: ?string, action: Object): string {
|
||||
return lastGame;
|
||||
}
|
||||
|
||||
type AppState = {
|
||||
game: string,
|
||||
};
|
||||
|
||||
class NavigationTicTacToeExample extends React.Component {
|
||||
_handleAction: Function;
|
||||
state: AppState;
|
||||
constructor() {
|
||||
super();
|
||||
this._handleAction = this._handleAction.bind(this);
|
||||
this.state = {
|
||||
game: ''
|
||||
};
|
||||
}
|
||||
_handleAction(action: Object) {
|
||||
const newState = GameReducer(this.state.game, action);
|
||||
if (newState !== this.state.game) {
|
||||
this.setState({
|
||||
game: newState,
|
||||
});
|
||||
}
|
||||
}
|
||||
static GameView = TicTacToeGame;
|
||||
static GameReducer = GameReducer;
|
||||
static GameActions = GameActions;
|
||||
render() {
|
||||
return (
|
||||
<TicTacToeGame
|
||||
game={this.state && this.state.game}
|
||||
onExampleExit={this.props.onExampleExit}
|
||||
onNavigate={this._handleAction}
|
||||
<NavigationRootContainer
|
||||
reducer={GameReducer}
|
||||
persistenceKey="TicTacToeGameState"
|
||||
renderNavigation={(game) => (
|
||||
<TicTacToeGame
|
||||
game={game}
|
||||
onExampleExit={this.props.onExampleExit}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,17 +43,11 @@ var Button = React.createClass({
|
||||
|
||||
class NotificationExample extends React.Component {
|
||||
componentWillMount() {
|
||||
// Add listener for push notifications
|
||||
PushNotificationIOS.addEventListener('notification', this._onNotification);
|
||||
// Add listener for local notifications
|
||||
PushNotificationIOS.addEventListener('localNotification', this._onLocalNotification);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// Remove listener for push notifications
|
||||
PushNotificationIOS.removeEventListener('notification', this._onNotification);
|
||||
// Remove listener for local notifications
|
||||
PushNotificationIOS.removeEventListener('localNotification', this._onLocalNotification);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -63,11 +57,6 @@ class NotificationExample extends React.Component {
|
||||
onPress={this._sendNotification}
|
||||
label="Send fake notification"
|
||||
/>
|
||||
|
||||
<Button
|
||||
onPress={this._sendLocalNotification}
|
||||
label="Send fake local notification"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -83,31 +72,9 @@ class NotificationExample extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
_sendLocalNotification() {
|
||||
require('RCTDeviceEventEmitter').emit('localNotificationReceived', {
|
||||
aps: {
|
||||
alert: 'Sample local notification',
|
||||
badge: '+1',
|
||||
sound: 'default',
|
||||
category: 'REACT_NATIVE'
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_onNotification(notification) {
|
||||
AlertIOS.alert(
|
||||
'Push Notification Received',
|
||||
'Alert message: ' + notification.getMessage(),
|
||||
[{
|
||||
text: 'Dismiss',
|
||||
onPress: null,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
_onLocalNotification(notification){
|
||||
AlertIOS.alert(
|
||||
'Local Notification Received',
|
||||
'Notification Received',
|
||||
'Alert message: ' + notification.getMessage(),
|
||||
[{
|
||||
text: 'Dismiss',
|
||||
|
||||
@@ -54,7 +54,6 @@ var TabBarExample = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<TabBarIOS
|
||||
unselectedTintColor="yellow"
|
||||
tintColor="white"
|
||||
barTintColor="darkslateblue">
|
||||
<TabBarIOS.Item
|
||||
@@ -82,7 +81,6 @@ var TabBarExample = React.createClass({
|
||||
</TabBarIOS.Item>
|
||||
<TabBarIOS.Item
|
||||
icon={require('./flux.png')}
|
||||
renderAsOriginal
|
||||
title="More"
|
||||
selected={this.state.selectedTab === 'greenTab'}
|
||||
onPress={() => {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -162,19 +155,19 @@ exports.examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{fontSize: 20, fontWeight: '100'}}>
|
||||
<Text style={{fontWeight: '100'}}>
|
||||
Move fast and be ultralight
|
||||
</Text>
|
||||
<Text style={{fontSize: 20, fontWeight: '200'}}>
|
||||
<Text style={{fontWeight: '200'}}>
|
||||
Move fast and be light
|
||||
</Text>
|
||||
<Text style={{fontSize: 20, fontWeight: 'normal'}}>
|
||||
<Text style={{fontWeight: 'normal'}}>
|
||||
Move fast and be normal
|
||||
</Text>
|
||||
<Text style={{fontSize: 20, fontWeight: 'bold'}}>
|
||||
<Text style={{fontWeight: 'bold'}}>
|
||||
Move fast and be bold
|
||||
</Text>
|
||||
<Text style={{fontSize: 20, fontWeight: '900'}}>
|
||||
<Text style={{fontWeight: '900'}}>
|
||||
Move fast and be ultrabold
|
||||
</Text>
|
||||
</View>
|
||||
@@ -422,13 +415,12 @@ exports.examples = [
|
||||
);
|
||||
},
|
||||
}, {
|
||||
title: 'Inline views',
|
||||
title: 'Inline images',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
This text contains an inline blue view <View style={{width: 25, height: 25, backgroundColor: 'steelblue'}} /> and
|
||||
an inline image <Image source={require('./flux.png')} style={{width: 30, height: 11, resizeMode: 'cover'}}/>. Neat, huh?
|
||||
This text contains an inline image <Image source={require('./flux.png')} style={{width: 30, height: 11, resizeMode: 'cover'}}/>. Neat, huh?
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -407,31 +407,6 @@ exports.examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'fontFamily, fontWeight and fontStyle',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
style={[styles.singleLine, {fontFamily: 'sans-serif'}]}
|
||||
placeholder="Custom fonts like Sans-Serif are supported"
|
||||
/>
|
||||
<TextInput
|
||||
style={[styles.singleLine, {fontFamily: 'sans-serif', fontWeight: 'bold'}]}
|
||||
placeholder="Sans-Serif bold"
|
||||
/>
|
||||
<TextInput
|
||||
style={[styles.singleLine, {fontFamily: 'sans-serif', fontStyle: 'italic'}]}
|
||||
placeholder="Sans-Serif italic"
|
||||
/>
|
||||
<TextInput
|
||||
style={[styles.singleLine, {fontFamily: 'serif'}]}
|
||||
placeholder="Serif"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Passwords',
|
||||
render: function() {
|
||||
@@ -531,43 +506,4 @@ exports.examples = [
|
||||
return <TokenizedTextExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Return key',
|
||||
render: function() {
|
||||
var returnKeyTypes = [
|
||||
'none',
|
||||
'go',
|
||||
'search',
|
||||
'send',
|
||||
'done',
|
||||
'previous',
|
||||
'next',
|
||||
];
|
||||
var returnKeyLabels = [
|
||||
'Compile',
|
||||
'React Native',
|
||||
];
|
||||
var examples = returnKeyTypes.map((type) => {
|
||||
return (
|
||||
<TextInput
|
||||
key={type}
|
||||
returnKeyType={type}
|
||||
placeholder={'returnKeyType: ' + type}
|
||||
style={styles.singleLine}
|
||||
/>
|
||||
);
|
||||
});
|
||||
var types = returnKeyLabels.map((type) => {
|
||||
return (
|
||||
<TextInput
|
||||
key={type}
|
||||
returnKeyLabel={type}
|
||||
placeholder={'returnKeyLabel: ' + type}
|
||||
style={styles.singleLine}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return <View>{examples}{types}</View>;
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@@ -955,6 +955,10 @@
|
||||
004D28A61AAF61C70097A701 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -968,6 +972,12 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/UIExplorerUnitTests",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-framework",
|
||||
XCTest,
|
||||
"-ObjC",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@@ -976,6 +986,10 @@
|
||||
004D28A71AAF61C70097A701 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../../React/**",
|
||||
@@ -988,6 +1002,12 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/UIExplorerUnitTests",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-framework",
|
||||
XCTest,
|
||||
"-ObjC",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
@@ -1007,6 +1027,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/UIExplorer/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.react.uiapp;
|
||||
PRODUCT_NAME = UIExplorer;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
@@ -1032,6 +1053,7 @@
|
||||
INFOPLIST_FILE = "$(SRCROOT)/UIExplorer/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.react.uiapp;
|
||||
PRODUCT_NAME = UIExplorer;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
@@ -1049,6 +1071,10 @@
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
@@ -1057,6 +1083,12 @@
|
||||
INFOPLIST_FILE = UIExplorerIntegrationTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-framework",
|
||||
XCTest,
|
||||
"-ObjC",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.React.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
|
||||
@@ -1069,10 +1101,20 @@
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = UIExplorerIntegrationTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-framework",
|
||||
XCTest,
|
||||
"-ObjC",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.React.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
|
||||
@@ -1136,10 +1178,6 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
SDKROOT = iphoneos;
|
||||
WARNING_CFLAGS = (
|
||||
"-Wextra",
|
||||
@@ -1198,10 +1236,6 @@
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WARNING_CFLAGS = (
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -32,7 +25,9 @@ export type UIExplorerExampleAction = {
|
||||
openExample: string;
|
||||
};
|
||||
|
||||
export type UIExplorerAction = UIExplorerListWithFilterAction | UIExplorerExampleAction;
|
||||
import type {BackAction} from 'NavigationRootContainer';
|
||||
|
||||
export type UIExplorerAction = BackAction | UIExplorerListWithFilterAction | UIExplorerExampleAction;
|
||||
|
||||
function ExampleListWithFilter(filter: ?string): UIExplorerListWithFilterAction {
|
||||
return {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -23,24 +16,29 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AppRegistry = require('AppRegistry');
|
||||
const AsyncStorage = require('AsyncStorage');
|
||||
const BackAndroid = require('BackAndroid');
|
||||
const Dimensions = require('Dimensions');
|
||||
const DrawerLayoutAndroid = require('DrawerLayoutAndroid');
|
||||
const Linking = require('Linking');
|
||||
const React = require('react');
|
||||
const StatusBar = require('StatusBar');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const ToolbarAndroid = require('ToolbarAndroid');
|
||||
const ReactNative = require('react-native');
|
||||
const {
|
||||
AppRegistry,
|
||||
BackAndroid,
|
||||
Dimensions,
|
||||
DrawerLayoutAndroid,
|
||||
NavigationExperimental,
|
||||
StyleSheet,
|
||||
ToolbarAndroid,
|
||||
View,
|
||||
StatusBar,
|
||||
} = ReactNative;
|
||||
const {
|
||||
RootContainer: NavigationRootContainer,
|
||||
} = NavigationExperimental;
|
||||
const UIExplorerExampleList = require('./UIExplorerExampleList');
|
||||
const UIExplorerList = require('./UIExplorerList');
|
||||
const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
|
||||
const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
|
||||
const URIActionMap = require('./URIActionMap');
|
||||
const View = require('View');
|
||||
|
||||
const DRAWER_WIDTH_LEFT = 56;
|
||||
var DRAWER_WIDTH_LEFT = 56;
|
||||
|
||||
type Props = {
|
||||
exampleFromAppetizeParams: string,
|
||||
@@ -51,13 +49,14 @@ type State = {
|
||||
};
|
||||
|
||||
class UIExplorerApp extends React.Component {
|
||||
_handleAction: Function;
|
||||
_renderDrawerContent: Function;
|
||||
_handleOpenInitialExample: Function;
|
||||
state: State;
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this._handleAction = this._handleAction.bind(this);
|
||||
this._renderDrawerContent = this._renderDrawerContent.bind(this);
|
||||
this._handleOpenInitialExample = this._handleOpenInitialExample.bind(this);
|
||||
this.state = {
|
||||
initialExampleUri: props.exampleFromAppetizeParams,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
@@ -65,28 +64,38 @@ class UIExplorerApp extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Linking.getInitialURL().then((url) => {
|
||||
AsyncStorage.getItem('UIExplorerAppState', (err, storedString) => {
|
||||
const exampleAction = URIActionMap(this.props.exampleFromAppetizeParams);
|
||||
const urlAction = URIActionMap(url);
|
||||
const launchAction = exampleAction || urlAction;
|
||||
if (err || !storedString) {
|
||||
const initialAction = launchAction || {type: 'InitialAction'};
|
||||
this.setState(UIExplorerNavigationReducer(null, initialAction));
|
||||
return;
|
||||
}
|
||||
const storedState = JSON.parse(storedString);
|
||||
if (launchAction) {
|
||||
this.setState(UIExplorerNavigationReducer(storedState, launchAction));
|
||||
return;
|
||||
}
|
||||
this.setState(storedState);
|
||||
});
|
||||
});
|
||||
// There's a race condition if we try to navigate to the specified example
|
||||
// from the initial props at the same time the navigation logic is setting
|
||||
// up the initial navigation state. This hack adds a delay to avoid this
|
||||
// scenario. So after the initial example list is shown, we then transition
|
||||
// to the initial example.
|
||||
setTimeout(this._handleOpenInitialExample, 500);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state) {
|
||||
return (
|
||||
<NavigationRootContainer
|
||||
persistenceKey="UIExplorerStateNavState"
|
||||
ref={navRootRef => { this._navigationRootRef = navRootRef; }}
|
||||
reducer={UIExplorerNavigationReducer}
|
||||
renderNavigation={this._renderApp.bind(this)}
|
||||
linkingActionMap={URIActionMap}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_handleOpenInitialExample() {
|
||||
if (this.state.initialExampleUri) {
|
||||
const exampleAction = URIActionMap(this.state.initialExampleUri);
|
||||
if (exampleAction && this._navigationRootRef) {
|
||||
this._navigationRootRef.handleNavigation(exampleAction);
|
||||
}
|
||||
}
|
||||
this.setState({initialExampleUri: null});
|
||||
}
|
||||
|
||||
_renderApp(navigationState, onNavigate) {
|
||||
if (!navigationState) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
@@ -101,42 +110,42 @@ class UIExplorerApp extends React.Component {
|
||||
this._overrideBackPressForDrawerLayout = false;
|
||||
}}
|
||||
ref={(drawer) => { this.drawer = drawer; }}
|
||||
renderNavigationView={this._renderDrawerContent}
|
||||
renderNavigationView={this._renderDrawerContent.bind(this, onNavigate)}
|
||||
statusBarBackgroundColor="#589c90">
|
||||
{this._renderApp()}
|
||||
{this._renderNavigation(navigationState, onNavigate)}
|
||||
</DrawerLayoutAndroid>
|
||||
);
|
||||
}
|
||||
|
||||
_renderDrawerContent() {
|
||||
_renderDrawerContent(onNavigate) {
|
||||
return (
|
||||
<View style={styles.drawerContentWrapper}>
|
||||
<UIExplorerExampleList
|
||||
list={UIExplorerList}
|
||||
displayTitleRow={true}
|
||||
disableSearch={true}
|
||||
onNavigate={this._handleAction}
|
||||
onNavigate={(action) => {
|
||||
this.drawer && this.drawer.closeDrawer();
|
||||
onNavigate(action);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderApp() {
|
||||
const {
|
||||
externalExample,
|
||||
stack,
|
||||
} = this.state;
|
||||
if (externalExample) {
|
||||
const Component = UIExplorerList.Modules[externalExample];
|
||||
_renderNavigation(navigationState, onNavigate) {
|
||||
if (navigationState.externalExample) {
|
||||
var Component = UIExplorerList.Modules[navigationState.externalExample];
|
||||
return (
|
||||
<Component
|
||||
onExampleExit={() => {
|
||||
this._handleAction({ type: 'BackAction' });
|
||||
onNavigate(NavigationRootContainer.getBackAction());
|
||||
}}
|
||||
ref={(example) => { this._exampleRef = example; }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const {stack} = navigationState;
|
||||
const title = UIExplorerStateTitleMap(stack.children[stack.index]);
|
||||
const index = stack.children.length <= 1 ? 1 : stack.index;
|
||||
|
||||
@@ -169,7 +178,6 @@ class UIExplorerApp extends React.Component {
|
||||
title={title}
|
||||
/>
|
||||
<UIExplorerExampleList
|
||||
onNavigate={this._handleAction}
|
||||
list={UIExplorerList}
|
||||
{...stack.children[0]}
|
||||
/>
|
||||
@@ -177,17 +185,6 @@ class UIExplorerApp extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
_handleAction(action: Object): boolean {
|
||||
this.drawer && this.drawer.closeDrawer();
|
||||
const newState = UIExplorerNavigationReducer(this.state, action);
|
||||
if (this.state !== newState) {
|
||||
this.setState(newState);
|
||||
AsyncStorage.setItem('UIExplorerAppState', JSON.stringify(this.state));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_handleBackButtonPress() {
|
||||
if (this._overrideBackPressForDrawerLayout) {
|
||||
// This hack is necessary because drawer layout provides an imperative API
|
||||
@@ -203,7 +200,12 @@ class UIExplorerApp extends React.Component {
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return this._handleAction({ type: 'BackAction' });
|
||||
if (this._navigationRootRef) {
|
||||
return this._navigationRootRef.handleNavigation(
|
||||
NavigationRootContainer.getBackAction()
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const AsyncStorage = require('AsyncStorage');
|
||||
const Linking = require('Linking');
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const UIExplorerList = require('./UIExplorerList.ios');
|
||||
@@ -44,6 +42,7 @@ const {
|
||||
const {
|
||||
CardStack: NavigationCardStack,
|
||||
Header: NavigationHeader,
|
||||
RootContainer: NavigationRootContainer,
|
||||
} = NavigationExperimental;
|
||||
|
||||
import type { NavigationSceneRendererProps } from 'NavigationTypeDefinition';
|
||||
@@ -56,86 +55,81 @@ type Props = {
|
||||
exampleFromAppetizeParams: string,
|
||||
};
|
||||
|
||||
type State = UIExplorerNavigationState & {
|
||||
externalExample?: string,
|
||||
type State = {
|
||||
initialExampleUri: ?string,
|
||||
};
|
||||
|
||||
class UIExplorerApp extends React.Component {
|
||||
_navigationRootRef: ?NavigationRootContainer;
|
||||
_renderNavigation: Function;
|
||||
_renderOverlay: Function;
|
||||
_renderScene: Function;
|
||||
_renderCard: Function;
|
||||
_renderTitleComponent: Function;
|
||||
_handleAction: Function;
|
||||
_handleOpenInitialExample: Function;
|
||||
state: State;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this._handleOpenInitialExample = this._handleOpenInitialExample.bind(this);
|
||||
this.state = {
|
||||
initialExampleUri: props.exampleFromAppetizeParams,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._handleAction = this._handleAction.bind(this);
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderOverlay = this._renderOverlay.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._renderTitleComponent = this._renderTitleComponent.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Linking.getInitialURL().then((url) => {
|
||||
AsyncStorage.getItem('UIExplorerAppState', (err, storedString) => {
|
||||
const exampleAction = URIActionMap(this.props.exampleFromAppetizeParams);
|
||||
const urlAction = URIActionMap(url);
|
||||
const launchAction = exampleAction || urlAction;
|
||||
if (err || !storedString) {
|
||||
const initialAction = launchAction || {type: 'InitialAction'};
|
||||
this.setState(UIExplorerNavigationReducer(null, initialAction));
|
||||
return;
|
||||
}
|
||||
const storedState = JSON.parse(storedString);
|
||||
if (launchAction) {
|
||||
this.setState(UIExplorerNavigationReducer(storedState, launchAction));
|
||||
return;
|
||||
}
|
||||
this.setState(storedState);
|
||||
});
|
||||
});
|
||||
|
||||
Linking.addEventListener('url', (url) => {
|
||||
this._handleAction(URIActionMap(url));
|
||||
});
|
||||
// There's a race condition if we try to navigate to the specified example
|
||||
// from the initial props at the same time the navigation logic is setting
|
||||
// up the initial navigation state. This hack adds a delay to avoid this
|
||||
// scenario. So after the initial example list is shown, we then transition
|
||||
// to the initial example.
|
||||
setTimeout(this._handleOpenInitialExample, 500);
|
||||
}
|
||||
|
||||
_handleAction(action: Object) {
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
const newState = UIExplorerNavigationReducer(this.state, action);
|
||||
if (this.state !== newState) {
|
||||
this.setState(newState);
|
||||
AsyncStorage.setItem('UIExplorerAppState', JSON.stringify(this.state));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state) {
|
||||
return (
|
||||
<NavigationRootContainer
|
||||
persistenceKey="UIExplorerState"
|
||||
reducer={UIExplorerNavigationReducer}
|
||||
ref={navRootRef => { this._navigationRootRef = navRootRef; }}
|
||||
renderNavigation={this._renderNavigation}
|
||||
linkingActionMap={URIActionMap}
|
||||
/>
|
||||
);
|
||||
}
|
||||
_handleOpenInitialExample() {
|
||||
if (this.state.initialExampleUri) {
|
||||
const exampleAction = URIActionMap(this.state.initialExampleUri);
|
||||
if (exampleAction && this._navigationRootRef) {
|
||||
this._navigationRootRef.handleNavigation(exampleAction);
|
||||
}
|
||||
}
|
||||
this.setState({initialExampleUri: null});
|
||||
}
|
||||
_renderNavigation(navigationState: UIExplorerNavigationState, onNavigate: Function) {
|
||||
if (!navigationState) {
|
||||
return null;
|
||||
}
|
||||
if (this.state.externalExample) {
|
||||
const Component = UIExplorerList.Modules[this.state.externalExample];
|
||||
if (navigationState.externalExample) {
|
||||
var Component = UIExplorerList.Modules[navigationState.externalExample];
|
||||
return (
|
||||
<Component
|
||||
onExampleExit={() => {
|
||||
this._handleAction({ type: 'BackAction' });
|
||||
onNavigate(NavigationRootContainer.getBackAction());
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const {stack} = navigationState;
|
||||
return (
|
||||
<NavigationCardStack
|
||||
navigationState={this.state.stack}
|
||||
navigationState={stack}
|
||||
style={styles.container}
|
||||
renderOverlay={this._renderOverlay}
|
||||
renderScene={this._renderScene}
|
||||
onNavigate={this._handleAction}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -162,7 +156,6 @@ class UIExplorerApp extends React.Component {
|
||||
if (state.key === 'AppList') {
|
||||
return (
|
||||
<UIExplorerExampleList
|
||||
onNavigate={this._handleAction}
|
||||
list={UIExplorerList}
|
||||
style={styles.exampleContainer}
|
||||
{...state}
|
||||
@@ -201,9 +194,9 @@ AppRegistry.registerComponent('UIExplorerApp', () => UIExplorerApp);
|
||||
UIExplorerList.ComponentExamples.concat(UIExplorerList.APIExamples).forEach((Example: UIExplorerExample) => {
|
||||
const ExampleModule = Example.module;
|
||||
if (ExampleModule.displayName) {
|
||||
const Snapshotter = React.createClass({
|
||||
var Snapshotter = React.createClass({
|
||||
render: function() {
|
||||
const Renderable = UIExplorerExampleList.makeRenderable(ExampleModule);
|
||||
var Renderable = UIExplorerExampleList.makeRenderable(ExampleModule);
|
||||
return (
|
||||
<SnapshotViewIOS>
|
||||
<Renderable />
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -22,20 +15,26 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const ListView = require('ListView');
|
||||
const React = require('react');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const Text = require('Text');
|
||||
const TextInput = require('TextInput');
|
||||
const TouchableHighlight = require('TouchableHighlight');
|
||||
const View = require('View');
|
||||
const ReactNative = require('react-native');
|
||||
const UIExplorerActions = require('./UIExplorerActions');
|
||||
|
||||
const {
|
||||
ListView,
|
||||
NavigationExperimental,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
} = ReactNative;
|
||||
const createExamplePage = require('./createExamplePage');
|
||||
const {
|
||||
Container: NavigationContainer,
|
||||
} = NavigationExperimental;
|
||||
|
||||
import type {
|
||||
UIExplorerExample,
|
||||
} from './UIExplorerList.ios';
|
||||
} from './UIExplorerList.ios'
|
||||
|
||||
const ds = new ListView.DataSource({
|
||||
rowHasChanged: (r1, r2) => r1 !== r2,
|
||||
@@ -55,13 +54,6 @@ class UIExplorerExampleList extends React.Component {
|
||||
}) {
|
||||
|
||||
}
|
||||
|
||||
static makeRenderable(example: any): ReactClass<any> {
|
||||
return example.examples ?
|
||||
createExamplePage(null, example) :
|
||||
example;
|
||||
}
|
||||
|
||||
render(): ?ReactElement {
|
||||
const filterText = this.props.filter || '';
|
||||
const filterRegex = new RegExp(String(filterText), 'i');
|
||||
@@ -162,11 +154,20 @@ class UIExplorerExampleList extends React.Component {
|
||||
}
|
||||
|
||||
_handleRowPress(exampleKey: string): void {
|
||||
this.props.onNavigate(UIExplorerActions.ExampleAction(exampleKey));
|
||||
this.props.onNavigate(UIExplorerActions.ExampleAction(exampleKey))
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
function makeRenderable(example: any): ReactClass<any> {
|
||||
return example.examples ?
|
||||
createExamplePage(null, example) :
|
||||
example;
|
||||
}
|
||||
|
||||
UIExplorerExampleList = NavigationContainer.create(UIExplorerExampleList);
|
||||
UIExplorerExampleList.makeRenderable = makeRenderable;
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
listContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
|
||||
@@ -138,6 +138,12 @@ static ControlBlock propertiesUpdateBlock()
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
#if __LP64__
|
||||
RCTAssert(NO, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
|
||||
NSOperatingSystemVersion version = [NSProcessInfo processInfo].operatingSystemVersion;
|
||||
RCTAssert((version.majorVersion == 8 && version.minorVersion >= 3) || version.majorVersion >= 9, @"Tests should be run on iOS 8.3+, found %zd.%zd.%zd", version.majorVersion, version.minorVersion, version.patchVersion);
|
||||
_runner = RCTInitRunnerForApp(@"IntegrationTests/RCTRootViewIntegrationTestApp", nil);
|
||||
}
|
||||
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 360 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB |
@@ -31,6 +31,12 @@
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
#if __LP64__
|
||||
RCTAssert(NO, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
|
||||
NSOperatingSystemVersion version = [NSProcessInfo processInfo].operatingSystemVersion;
|
||||
RCTAssert((version.majorVersion == 8 && version.minorVersion >= 3) || version.majorVersion >= 9, @"Tests should be run on iOS 8.3+, found %zd.%zd.%zd", version.majorVersion, version.minorVersion, version.patchVersion);
|
||||
_runner = RCTInitRunnerForApp(@"IntegrationTests/IntegrationTestsApp", nil);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
#if __LP64__
|
||||
RCTAssert(NO, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
|
||||
#endif
|
||||
|
||||
NSOperatingSystemVersion version = [NSProcessInfo processInfo].operatingSystemVersion;
|
||||
RCTAssert((version.majorVersion == 8 && version.minorVersion >= 3) || version.majorVersion >= 9, @"Tests should be run on iOS 8.3+, found %zd.%zd.%zd", version.majorVersion, version.minorVersion, version.patchVersion);
|
||||
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerApp.ios", nil);
|
||||
_runner.recordMode = NO;
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ var ComponentExamples: Array<UIExplorerExample> = [
|
||||
module: require('./ModalExample'),
|
||||
},
|
||||
{
|
||||
key: 'PickerExample',
|
||||
module: require('./PickerExample'),
|
||||
key: 'PickerAndroidExample',
|
||||
module: require('./PickerAndroidExample'),
|
||||
},
|
||||
{
|
||||
key: 'ProgressBarAndroidExample',
|
||||
@@ -138,10 +138,6 @@ const APIExamples = [
|
||||
key: 'LinkingExample',
|
||||
module: require('./LinkingExample'),
|
||||
},
|
||||
{
|
||||
key: 'LayoutAnimationExample',
|
||||
module: require('./LayoutAnimationExample'),
|
||||
},
|
||||
{
|
||||
key: 'LayoutExample',
|
||||
module: require('./LayoutExample'),
|
||||
@@ -178,10 +174,6 @@ const APIExamples = [
|
||||
key: 'VibrationExample',
|
||||
module: require('./VibrationExample'),
|
||||
},
|
||||
{
|
||||
key: 'WebSocketExample',
|
||||
module: require('./WebSocketExample'),
|
||||
},
|
||||
{
|
||||
key: 'XHRExample',
|
||||
module: require('./XHRExample'),
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -27,7 +20,7 @@ export type UIExplorerExample = {
|
||||
module: Object;
|
||||
};
|
||||
|
||||
const ComponentExamples: Array<UIExplorerExample> = [
|
||||
var ComponentExamples: Array<UIExplorerExample> = [
|
||||
{
|
||||
key: 'ActivityIndicatorIOSExample',
|
||||
module: require('./ActivityIndicatorIOSExample'),
|
||||
@@ -76,10 +69,6 @@ const ComponentExamples: Array<UIExplorerExample> = [
|
||||
key: 'NavigatorIOSExample',
|
||||
module: require('./NavigatorIOSExample'),
|
||||
},
|
||||
{
|
||||
key: 'PickerExample',
|
||||
module: require('./PickerExample'),
|
||||
},
|
||||
{
|
||||
key: 'PickerIOSExample',
|
||||
module: require('./PickerIOSExample'),
|
||||
@@ -142,7 +131,7 @@ const ComponentExamples: Array<UIExplorerExample> = [
|
||||
},
|
||||
];
|
||||
|
||||
const APIExamples: Array<UIExplorerExample> = [
|
||||
var APIExamples: Array<UIExplorerExample> = [
|
||||
{
|
||||
key: 'AccessibilityIOSExample',
|
||||
module: require('./AccessibilityIOSExample'),
|
||||
@@ -155,10 +144,6 @@ const APIExamples: Array<UIExplorerExample> = [
|
||||
key: 'AdSupportIOSExample',
|
||||
module: require('./AdSupportIOSExample'),
|
||||
},
|
||||
{
|
||||
key: 'AlertExample',
|
||||
module: require('./AlertExample').AlertExample,
|
||||
},
|
||||
{
|
||||
key: 'AlertIOSExample',
|
||||
module: require('./AlertIOSExample'),
|
||||
@@ -207,10 +192,6 @@ const APIExamples: Array<UIExplorerExample> = [
|
||||
key: 'ImageEditingExample',
|
||||
module: require('./ImageEditingExample'),
|
||||
},
|
||||
{
|
||||
key: 'LayoutAnimationExample',
|
||||
module: require('./LayoutAnimationExample'),
|
||||
},
|
||||
{
|
||||
key: 'LayoutExample',
|
||||
module: require('./LayoutExample'),
|
||||
@@ -223,6 +204,10 @@ const APIExamples: Array<UIExplorerExample> = [
|
||||
key: 'NavigationExperimentalExample',
|
||||
module: require('./NavigationExperimental/NavigationExperimentalExample'),
|
||||
},
|
||||
{
|
||||
key: 'NavigationExperimentalLegacyNavigatorExample',
|
||||
module: require('./NavigationExperimental/LegacyNavigator/LegacyNavigatorExample'),
|
||||
},
|
||||
{
|
||||
key: 'NetInfoExample',
|
||||
module: require('./NetInfoExample'),
|
||||
@@ -263,10 +248,6 @@ const APIExamples: Array<UIExplorerExample> = [
|
||||
key: 'VibrationExample',
|
||||
module: require('./VibrationExample'),
|
||||
},
|
||||
{
|
||||
key: 'WebSocketExample',
|
||||
module: require('./WebSocketExample'),
|
||||
},
|
||||
{
|
||||
key: 'XHRExample',
|
||||
module: require('./XHRExample.ios'),
|
||||
|
||||
@@ -133,4 +133,52 @@ RCTAssertEqualSizes(a.size, b.size); \
|
||||
RCTAssertEqualRects(expected, result);
|
||||
}
|
||||
|
||||
- (void)testPlaceholderImage
|
||||
{
|
||||
CGSize size = {45, 22};
|
||||
CGFloat expectedScale = 1.0;
|
||||
UIImage *image = RCTGetPlaceholderImage(size, nil);
|
||||
RCTAssertEqualSizes(size, image.size);
|
||||
XCTAssertEqual(expectedScale, image.scale);
|
||||
}
|
||||
|
||||
- (void)testPlaceholderNonintegralSize
|
||||
{
|
||||
CGSize size = {3.0/2, 7.0/3};
|
||||
CGFloat expectedScale = 6;
|
||||
CGSize pixelSize = {
|
||||
round(size.width * expectedScale),
|
||||
round(size.height * expectedScale)
|
||||
};
|
||||
UIImage *image = RCTGetPlaceholderImage(size, nil);
|
||||
RCTAssertEqualSizes(size, image.size);
|
||||
XCTAssertEqual(pixelSize.width, CGImageGetWidth(image.CGImage));
|
||||
XCTAssertEqual(pixelSize.height, CGImageGetHeight(image.CGImage));
|
||||
XCTAssertEqual(expectedScale, image.scale);
|
||||
}
|
||||
|
||||
- (void)testPlaceholderSquareImage
|
||||
{
|
||||
CGSize size = {333, 333};
|
||||
CGFloat expectedScale = 1.0/333;
|
||||
CGSize pixelSize = {1, 1};
|
||||
UIImage *image = RCTGetPlaceholderImage(size, nil);
|
||||
RCTAssertEqualSizes(size, image.size);
|
||||
XCTAssertEqual(pixelSize.width, CGImageGetWidth(image.CGImage));
|
||||
XCTAssertEqual(pixelSize.height, CGImageGetHeight(image.CGImage));
|
||||
XCTAssertEqual(expectedScale, image.scale);
|
||||
}
|
||||
|
||||
- (void)testPlaceholderNonsquareImage
|
||||
{
|
||||
CGSize size = {640, 480};
|
||||
CGFloat expectedScale = 1.0/160;
|
||||
CGSize pixelSize = {4, 3};
|
||||
UIImage *image = RCTGetPlaceholderImage(size, nil);
|
||||
RCTAssertEqualSizes(size, image.size);
|
||||
XCTAssertEqual(pixelSize.width, CGImageGetWidth(image.CGImage));
|
||||
XCTAssertEqual(pixelSize.height, CGImageGetHeight(image.CGImage));
|
||||
XCTAssertEqual(expectedScale, image.scale);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#import "RCTJSCExecutor.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
#define RUN_PERF_TESTS 0
|
||||
|
||||
@interface RCTJSCExecutorTests : XCTestCase
|
||||
|
||||
@end
|
||||
@@ -47,4 +49,164 @@
|
||||
[_executor invalidate];
|
||||
}
|
||||
|
||||
#if RUN_PERF_TESTS
|
||||
|
||||
static uint64_t _get_time_nanoseconds(void)
|
||||
{
|
||||
static struct mach_timebase_info tb_info = {0, 0};
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
int ret = mach_timebase_info(&tb_info);
|
||||
assert(0 == ret);
|
||||
});
|
||||
|
||||
return (mach_absolute_time() * tb_info.numer) / tb_info.denom;
|
||||
}
|
||||
|
||||
- (void)testDeserializationPerf
|
||||
{
|
||||
// This test case checks the assumption that deserializing objects from JavaScript
|
||||
// values one-by-one via ObjC JSC API is slower than using JSON string
|
||||
// You might want to switch your tests schema to "Release" build configuration
|
||||
|
||||
JSContextGroupRef group = JSContextGroupCreate();
|
||||
JSGlobalContextRef context = JSGlobalContextCreateInGroup(group, NULL);
|
||||
id message = @[@[@1, @2, @3, @4], @[@{@"a": @1}, @{@"b": @2}], (id)kCFNull];
|
||||
NSString *code = RCTJSONStringify(message, NULL);
|
||||
JSStringRef script = JSStringCreateWithCFString((__bridge CFStringRef)code);
|
||||
JSValueRef error = NULL;
|
||||
JSValueRef value = JSEvaluateScript(context, script, NULL, NULL, 0, &error);
|
||||
XCTAssertTrue(error == NULL);
|
||||
|
||||
id obj;
|
||||
uint64_t start = _get_time_nanoseconds();
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
JSStringRef jsonJSString = JSValueCreateJSONString(context, value, 0, nil);
|
||||
NSString *jsonString = (__bridge NSString *)JSStringCopyCFString(kCFAllocatorDefault, jsonJSString);
|
||||
JSStringRelease(jsonJSString);
|
||||
|
||||
obj = RCTJSONParse(jsonString, NULL);
|
||||
}
|
||||
NSLog(@"JSON Parse time: %.2fms", (_get_time_nanoseconds() - start) / 1000000.0);
|
||||
|
||||
JSStringRelease(script);
|
||||
JSGlobalContextRelease(context);
|
||||
JSContextGroupRelease(group);
|
||||
}
|
||||
|
||||
- (void)testJavaScriptCallSpeed
|
||||
{
|
||||
/**
|
||||
* Since we almost don't change the RCTJSCExecutor logic, and this test is
|
||||
* very likely to become flaky (specially across different devices) leave it
|
||||
* to be run manually
|
||||
*
|
||||
* Previous Values: If you change the executor code, you should update this values
|
||||
*/
|
||||
|
||||
int const runs = 4e5;
|
||||
int const frequency = 10;
|
||||
double const threshold = 0.1;
|
||||
static double const expectedTimes[] = {
|
||||
0x1.6199943826cf1p+13,
|
||||
0x1.a3bc0a81551c3p+13,
|
||||
0x1.d49fbb8602fe3p+13,
|
||||
0x1.d1f64085ecb7bp+13,
|
||||
};
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
NSString *script = @" \
|
||||
var modules = { \
|
||||
module: { \
|
||||
method: function () { \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
var Bridge = { \
|
||||
callFunctionReturnFlushedQueue: function(module, method, args) { \
|
||||
modules[module].apply(modules[module], args); \
|
||||
} \
|
||||
}; \
|
||||
function require(module) { \
|
||||
return Bridge; \
|
||||
} \
|
||||
";
|
||||
|
||||
[_executor executeApplicationScript:[script dataUsingEncoding:NSUTF8StringEncoding] sourceURL:[NSURL URLWithString:@"http://localhost:8081/"] onComplete:^(__unused NSError *error) {
|
||||
NSMutableArray *params = [NSMutableArray new];
|
||||
id data = @1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
double samples[runs / frequency];
|
||||
int size = runs / frequency;
|
||||
double total = 0;
|
||||
for (int j = 0; j < runs; j++) {
|
||||
@autoreleasepool {
|
||||
double start = _get_time_nanoseconds();
|
||||
[_executor callFunctionOnModule:@"module"
|
||||
method:@"method"
|
||||
arguments:params
|
||||
callback:^(__unused id json, __unused NSError *unused) {
|
||||
}];
|
||||
double run = _get_time_nanoseconds() - start;
|
||||
if ((j % frequency) == frequency - 1) { // Warmup
|
||||
total += run;
|
||||
samples[j/frequency] = run;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double mean = total / size;
|
||||
double variance = 0;
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
variance += pow(samples[j] - mean, 2);
|
||||
}
|
||||
variance /= size;
|
||||
|
||||
double standardDeviation = sqrt(variance);
|
||||
double marginOfError = standardDeviation * 1.645;
|
||||
|
||||
double lower = mean - marginOfError;
|
||||
double upper = mean + marginOfError;
|
||||
|
||||
int s = 0;
|
||||
total = 0;
|
||||
for (int j = 0; j < size; j++) {
|
||||
double v = samples[j];
|
||||
if (v >= lower && v <= upper) {
|
||||
samples[s++] = v;
|
||||
total += v;
|
||||
}
|
||||
}
|
||||
mean = total / s;
|
||||
|
||||
lower = mean * (1.0 - threshold);
|
||||
upper = mean * (1.0 + threshold);
|
||||
|
||||
double expected = expectedTimes[i];
|
||||
|
||||
NSLog(@"Previous: %lf, New: %f -> %a", expected, mean, mean);
|
||||
if (upper < expected) {
|
||||
NSLog(@"You made JS calls with %d argument(s) %.2lf%% faster :) - Remember to update the tests with the new value: %a",
|
||||
i, (1 - (double)mean / expected) * 100, mean);
|
||||
}
|
||||
|
||||
|
||||
XCTAssertTrue(lower < expected, @"You made JS calls with %d argument(s) %.2lf%% slower :( - If that's *really* necessary, update the tests with the new value: %a",
|
||||
i, ((double)mean / expected - 1) * 100, mean);
|
||||
|
||||
[params addObject:data];
|
||||
}
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
}];
|
||||
|
||||
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) {
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@@ -221,16 +221,10 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
- (void)testCustomSetBridgeModuleInitializedAtBridgeStartup
|
||||
{
|
||||
XCTAssertFalse(_customSetBridgeModuleNotificationSent);
|
||||
|
||||
__block RCTTestCustomSetBridgeModule *module;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
module = [_bridge moduleForClass:[RCTTestCustomSetBridgeModule class]];
|
||||
});
|
||||
|
||||
RUN_RUNLOOP_WHILE(!module);
|
||||
RUN_RUNLOOP_WHILE(!_customSetBridgeModuleNotificationSent);
|
||||
XCTAssertTrue(_customSetBridgeModuleNotificationSent);
|
||||
XCTAssertFalse(module.setBridgeOnMainThread);
|
||||
RCTTestCustomSetBridgeModule *module = [_bridge moduleForClass:[RCTTestCustomSetBridgeModule class]];
|
||||
XCTAssertTrue(module.setBridgeOnMainThread);
|
||||
XCTAssertEqual(module.bridge, _bridge.batchedBridge);
|
||||
XCTAssertNotNil(module.methodQueue);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ var ViewBorderStyleExample = React.createClass({
|
||||
<View>
|
||||
<View style={{
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
borderStyle: this.state.showBorder ? 'dashed' : null,
|
||||
padding: 5
|
||||
}}>
|
||||
|
||||
@@ -109,7 +109,6 @@ var ViewPagerAndroidExample = React.createClass({
|
||||
return {
|
||||
page: 0,
|
||||
animationsAreEnabled: true,
|
||||
scrollEnabled: true,
|
||||
progress: {
|
||||
position: 0,
|
||||
offset: 0,
|
||||
@@ -168,7 +167,6 @@ var ViewPagerAndroidExample = React.createClass({
|
||||
<ViewPagerAndroid
|
||||
style={styles.viewPager}
|
||||
initialPage={0}
|
||||
scrollEnabled={this.state.scrollEnabled}
|
||||
onPageScroll={this.onPageScroll}
|
||||
onPageSelected={this.onPageSelected}
|
||||
onPageScrollStateChanged={this.onPageScrollStateChanged}
|
||||
@@ -176,13 +174,6 @@ var ViewPagerAndroidExample = React.createClass({
|
||||
ref={viewPager => { this.viewPager = viewPager; }}>
|
||||
{pages}
|
||||
</ViewPagerAndroid>
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
enabled={true}
|
||||
text={this.state.scrollEnabled ? 'Scroll Enabled' : 'Scroll Disabled'}
|
||||
onPress={() => this.setState({scrollEnabled: !this.state.scrollEnabled})}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.buttons}>
|
||||
{ animationsAreEnabled ?
|
||||
<Button
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/* eslint-env browser */
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {
|
||||
PixelRatio,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} = ReactNative;
|
||||
|
||||
const DEFAULT_WS_URL = 'ws://localhost:5555/';
|
||||
const WS_EVENTS = [
|
||||
'close',
|
||||
'error',
|
||||
'message',
|
||||
'open',
|
||||
];
|
||||
const WS_STATES = [
|
||||
/* 0 */ 'CONNECTING',
|
||||
/* 1 */ 'OPEN',
|
||||
/* 2 */ 'CLOSING',
|
||||
/* 3 */ 'CLOSED',
|
||||
];
|
||||
|
||||
class Button extends React.Component {
|
||||
render(): ReactElement {
|
||||
const label = <Text style={styles.buttonLabel}>{this.props.label}</Text>;
|
||||
if (this.props.disabled) {
|
||||
return (
|
||||
<View style={[styles.button, styles.disabledButton]}>
|
||||
{label}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={this.props.onPress}
|
||||
style={styles.button}>
|
||||
{label}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Row extends React.Component {
|
||||
render(): ReactElement {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
<Text>{this.props.label}</Text>
|
||||
<Text>{this.props.value}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function showValue(value) {
|
||||
if (value === undefined || value === null) {
|
||||
return '(no value)';
|
||||
}
|
||||
console.log('typeof Uint8Array', typeof Uint8Array);
|
||||
if (typeof ArrayBuffer !== 'undefined' &&
|
||||
typeof Uint8Array !== 'undefined' &&
|
||||
value instanceof ArrayBuffer) {
|
||||
return `ArrayBuffer {${Array.from(new Uint8Array(value))}}`;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
type State = {
|
||||
url: string;
|
||||
socket: ?WebSocket;
|
||||
socketState: ?number;
|
||||
lastSocketEvent: ?string;
|
||||
lastMessage: ?string | ?ArrayBuffer;
|
||||
outgoingMessage: string;
|
||||
};
|
||||
|
||||
class WebSocketExample extends React.Component<any, any, State> {
|
||||
|
||||
static title = 'WebSocket';
|
||||
static description = 'WebSocket API';
|
||||
|
||||
state: State = {
|
||||
url: DEFAULT_WS_URL,
|
||||
socket: null,
|
||||
socketState: null,
|
||||
lastSocketEvent: null,
|
||||
lastMessage: null,
|
||||
outgoingMessage: '',
|
||||
};
|
||||
|
||||
_connect = () => {
|
||||
const socket = new WebSocket(this.state.url);
|
||||
WS_EVENTS.forEach(ev => socket.addEventListener(ev, this._onSocketEvent));
|
||||
this.setState({
|
||||
socket,
|
||||
socketState: socket.readyState,
|
||||
});
|
||||
};
|
||||
|
||||
_disconnect = () => {
|
||||
if (!this.state.socket) {
|
||||
return;
|
||||
}
|
||||
this.state.socket.close();
|
||||
};
|
||||
|
||||
// Ideally this would be a MessageEvent, but Flow's definition
|
||||
// doesn't inherit from Event, so it's 'any' for now.
|
||||
// See https://github.com/facebook/flow/issues/1654.
|
||||
_onSocketEvent = (event: any) => {
|
||||
const state: any = {
|
||||
socketState: event.target.readyState,
|
||||
lastSocketEvent: event.type,
|
||||
};
|
||||
if (event.type === 'message') {
|
||||
state.lastMessage = event.data;
|
||||
}
|
||||
this.setState(state);
|
||||
};
|
||||
|
||||
_sendText = () => {
|
||||
if (!this.state.socket) {
|
||||
return;
|
||||
}
|
||||
this.state.socket.send(this.state.outgoingMessage);
|
||||
this.setState({outgoingMessage: ''});
|
||||
};
|
||||
|
||||
_sendBinary = () => {
|
||||
if (!this.state.socket ||
|
||||
typeof ArrayBuffer === 'undefined' ||
|
||||
typeof Uint8Array === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const {outgoingMessage} = this.state;
|
||||
const buffer = new Uint8Array(outgoingMessage.length);
|
||||
for (let i = 0; i < outgoingMessage.length; i++) {
|
||||
buffer[i] = outgoingMessage.charCodeAt(i);
|
||||
}
|
||||
this.state.socket.send(buffer);
|
||||
this.setState({outgoingMessage: ''});
|
||||
};
|
||||
|
||||
render(): ReactElement {
|
||||
const socketState = WS_STATES[this.state.socketState || -1];
|
||||
const canConnect =
|
||||
!this.state.socket ||
|
||||
this.state.socket.readyState >= WebSocket.CLOSING;
|
||||
const canSend = !!this.state.socket;
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.note}>
|
||||
<Text>Pro tip:</Text>
|
||||
<Text style={styles.monospace}>
|
||||
node Examples/UIExplorer/websocket_test_server.js
|
||||
</Text>
|
||||
<Text>
|
||||
{' in the '}
|
||||
<Text style={styles.monospace}>react-native</Text>
|
||||
{' directory starts a test server.'}
|
||||
</Text>
|
||||
</View>
|
||||
<Row
|
||||
label="Current WebSocket state"
|
||||
value={showValue(socketState)}
|
||||
/>
|
||||
<Row
|
||||
label="Last WebSocket event"
|
||||
value={showValue(this.state.lastSocketEvent)}
|
||||
/>
|
||||
<Row
|
||||
label="Last message received"
|
||||
value={showValue(this.state.lastMessage)}
|
||||
/>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
autoCorrect={false}
|
||||
placeholder="Server URL..."
|
||||
onChangeText={(url) => this.setState({url})}
|
||||
value={this.state.url}
|
||||
/>
|
||||
<Button
|
||||
onPress={this._connect}
|
||||
label="Connect"
|
||||
disabled={!canConnect}
|
||||
/>
|
||||
<Button
|
||||
onPress={this._disconnect}
|
||||
label="Disconnect"
|
||||
disabled={canConnect}
|
||||
/>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
autoCorrect={false}
|
||||
placeholder="Type message here..."
|
||||
onChangeText={(outgoingMessage) => this.setState({outgoingMessage})}
|
||||
value={this.state.outgoingMessage}
|
||||
/>
|
||||
<View style={styles.buttonRow}>
|
||||
<Button
|
||||
onPress={this._sendText}
|
||||
label="Send as text"
|
||||
disabled={!canSend}
|
||||
/>
|
||||
<Button
|
||||
onPress={this._sendBinary}
|
||||
label="Send as binary"
|
||||
disabled={!canSend}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
note: {
|
||||
padding: 8,
|
||||
margin: 4,
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
monospace: {
|
||||
fontFamily: 'courier',
|
||||
fontSize: 11,
|
||||
},
|
||||
row: {
|
||||
height: 40,
|
||||
padding: 4,
|
||||
backgroundColor: 'white',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1 / PixelRatio.get(),
|
||||
borderColor: 'grey',
|
||||
},
|
||||
button: {
|
||||
margin: 8,
|
||||
padding: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: 'blue',
|
||||
alignSelf: 'center',
|
||||
},
|
||||
disabledButton: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
buttonLabel: {
|
||||
color: 'white',
|
||||
},
|
||||
buttonRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
textInput: {
|
||||
height: 40,
|
||||
backgroundColor: 'white',
|
||||
margin: 8,
|
||||
padding: 8,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = WebSocketExample;
|
||||
@@ -22,7 +22,6 @@ var {
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
WebView,
|
||||
} = ReactNative;
|
||||
|
||||
var RCTNetworking = require('RCTNetworking');
|
||||
@@ -46,7 +45,6 @@ class XHRExampleCookies extends React.Component {
|
||||
var url = `https://${domain}/cookies/set?a=${a}&b=${b}`;
|
||||
fetch(url).then((response) => {
|
||||
this.setStatus(`Cookies a=${a}, b=${b} set`);
|
||||
this.refreshWebview();
|
||||
});
|
||||
|
||||
this.setState({
|
||||
@@ -61,7 +59,6 @@ class XHRExampleCookies extends React.Component {
|
||||
return response.json();
|
||||
}).then((data) => {
|
||||
this.setStatus(`Got cookies ${JSON.stringify(data.cookies)} from server`);
|
||||
this.refreshWebview();
|
||||
});
|
||||
|
||||
this.setStatus('Getting cookies...');
|
||||
@@ -70,14 +67,9 @@ class XHRExampleCookies extends React.Component {
|
||||
clearCookies() {
|
||||
RCTNetworking.clearCookies((cleared) => {
|
||||
this.setStatus('Cookies cleared, had cookies=' + cleared);
|
||||
this.refreshWebview();
|
||||
});
|
||||
}
|
||||
|
||||
refreshWebview() {
|
||||
this.refs.webview.reload();
|
||||
}
|
||||
|
||||
setStatus(status: string) {
|
||||
this.setState({status});
|
||||
}
|
||||
@@ -121,18 +113,6 @@ class XHRExampleCookies extends React.Component {
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<Text>{this.state.status}</Text>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this.refreshWebview.bind(this)}>
|
||||
<View style={styles.button}>
|
||||
<Text>Refresh Webview</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<WebView
|
||||
ref="webview"
|
||||
source={{uri: 'http://httpbin.org/cookies'}}
|
||||
style={{height: 100}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/* eslint-env node */
|
||||
|
||||
const WebSocket = require('ws');
|
||||
|
||||
console.log(`\
|
||||
Test server for WebSocketExample
|
||||
|
||||
This will send each incoming message right back to the other side.a
|
||||
Restart with the '--binary' command line flag to have it respond with an
|
||||
ArrayBuffer instead of a string.
|
||||
`);
|
||||
|
||||
const respondWithBinary = process.argv.indexOf('--binary') !== -1;
|
||||
const server = new WebSocket.Server({port: 5555});
|
||||
server.on('connection', (ws) => {
|
||||
ws.on('message', (message) => {
|
||||
console.log('Received message:', message);
|
||||
if (respondWithBinary) {
|
||||
message = new Buffer(message);
|
||||
}
|
||||
ws.send(message);
|
||||
});
|
||||
|
||||
console.log('Incoming connection!');
|
||||
ws.send('Why hello there!');
|
||||
});
|
||||
@@ -23,7 +23,7 @@ var merge = require('merge');
|
||||
// Diff Helpers
|
||||
|
||||
function arrayDiffer(a, b) {
|
||||
if (a == null || b == null) {
|
||||
if (a == null) {
|
||||
return true;
|
||||
}
|
||||
if (a.length !== b.length) {
|
||||
|
||||
@@ -69,7 +69,6 @@ class Animated {
|
||||
__getNativeConfig(): Object {
|
||||
throw new Error('This JS animated node type cannot be used as native animated node');
|
||||
}
|
||||
toJSON(): any { return this.__getValue(); }
|
||||
}
|
||||
|
||||
type AnimationConfig = {
|
||||
@@ -83,7 +82,7 @@ type AnimationConfig = {
|
||||
class Animation {
|
||||
__active: bool;
|
||||
__isInteraction: bool;
|
||||
__nativeId: number;
|
||||
__nativeTag: number;
|
||||
__onEnd: ?EndCallback;
|
||||
start(
|
||||
fromValue: number,
|
||||
@@ -92,11 +91,7 @@ class Animation {
|
||||
previousAnimation: ?Animation,
|
||||
animatedValue: AnimatedValue
|
||||
): void {}
|
||||
stop(): void {
|
||||
if (this.__nativeId) {
|
||||
NativeAnimatedAPI.stopAnimation(this.__nativeId);
|
||||
}
|
||||
}
|
||||
stop(): void {}
|
||||
_getNativeAnimationConfig(): any {
|
||||
// Subclasses that have corresponding animation implementation done in native
|
||||
// should override this method
|
||||
@@ -110,9 +105,9 @@ class Animation {
|
||||
}
|
||||
__startNativeAnimation(animatedValue: AnimatedValue): void {
|
||||
animatedValue.__makeNative();
|
||||
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
|
||||
this.__nativeTag = NativeAnimatedHelper.generateNewAnimationTag();
|
||||
NativeAnimatedAPI.startAnimatingNode(
|
||||
this.__nativeId,
|
||||
this.__nativeTag,
|
||||
animatedValue.__getNativeTag(),
|
||||
this._getNativeAnimationConfig(),
|
||||
this.__debouncedOnEnd.bind(this)
|
||||
@@ -316,7 +311,6 @@ class TimingAnimation extends Animation {
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
clearTimeout(this._timeout);
|
||||
window.cancelAnimationFrame(this._animationFrame);
|
||||
@@ -387,7 +381,6 @@ class DecayAnimation extends Animation {
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
window.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
@@ -602,7 +595,6 @@ class SpringAnimation extends Animation {
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
super.stop();
|
||||
this.__active = false;
|
||||
window.cancelAnimationFrame(this._animationFrame);
|
||||
this.__debouncedOnEnd({finished: false});
|
||||
@@ -653,7 +645,7 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
this._animation.stop();
|
||||
this._animation = null;
|
||||
}
|
||||
this._updateValue(value, !this.__isNative /* don't perform a flush for natively driven values */);
|
||||
this._updateValue(value);
|
||||
if (this.__isNative) {
|
||||
NativeAnimatedAPI.setAnimatedNodeValue(this.__getNativeTag(), value);
|
||||
}
|
||||
@@ -713,7 +705,7 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
* 0-10.
|
||||
*/
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
return new AnimatedInterpolation(this, Interpolation.create(config));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -731,9 +723,7 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
animation.start(
|
||||
this._value,
|
||||
(value) => {
|
||||
// Natively driven animations will never call into that callback, therefore we can always pass `flush = true`
|
||||
// to allow the updated value to propagate to native with `setNativeProps`
|
||||
this._updateValue(value, true /* flush */);
|
||||
this._updateValue(value);
|
||||
},
|
||||
(result) => {
|
||||
this._animation = null;
|
||||
@@ -763,11 +753,9 @@ class AnimatedValue extends AnimatedWithChildren {
|
||||
this._tracking = tracking;
|
||||
}
|
||||
|
||||
_updateValue(value: number, flush: bool): void {
|
||||
_updateValue(value: number): void {
|
||||
this._value = value;
|
||||
if (flush) {
|
||||
_flush(this);
|
||||
}
|
||||
_flush(this);
|
||||
for (var key in this._listeners) {
|
||||
this._listeners[key]({value: this.__getValue()});
|
||||
}
|
||||
@@ -924,14 +912,12 @@ class AnimatedValueXY extends AnimatedWithChildren {
|
||||
|
||||
class AnimatedInterpolation extends AnimatedWithChildren {
|
||||
_parent: Animated;
|
||||
_config: InterpolationConfigType;
|
||||
_interpolation: (input: number) => number | string;
|
||||
|
||||
constructor(parent: Animated, config: InterpolationConfigType) {
|
||||
constructor(parent: Animated, interpolation: (input: number) => number | string) {
|
||||
super();
|
||||
this._parent = parent;
|
||||
this._config = config;
|
||||
this._interpolation = Interpolation.create(config);
|
||||
this._interpolation = interpolation;
|
||||
}
|
||||
|
||||
__getValue(): number | string {
|
||||
@@ -944,7 +930,7 @@ class AnimatedInterpolation extends AnimatedWithChildren {
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
return new AnimatedInterpolation(this, Interpolation.create(config));
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
@@ -953,15 +939,6 @@ class AnimatedInterpolation extends AnimatedWithChildren {
|
||||
|
||||
__detach(): void {
|
||||
this._parent.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
NativeAnimatedHelper.validateInterpolation(this._config);
|
||||
return {
|
||||
...this._config,
|
||||
type: 'interpolation',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,18 +952,12 @@ class AnimatedAddition extends AnimatedWithChildren {
|
||||
this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
this._a.__makeNative();
|
||||
this._b.__makeNative();
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
return this._a.__getValue() + this._b.__getValue();
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
return new AnimatedInterpolation(this, Interpolation.create(config));
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
@@ -997,14 +968,6 @@ class AnimatedAddition extends AnimatedWithChildren {
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
this._b.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'addition',
|
||||
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1018,18 +981,12 @@ class AnimatedMultiplication extends AnimatedWithChildren {
|
||||
this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
super.__makeNative();
|
||||
this._a.__makeNative();
|
||||
this._b.__makeNative();
|
||||
}
|
||||
|
||||
__getValue(): number {
|
||||
return this._a.__getValue() * this._b.__getValue();
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
return new AnimatedInterpolation(this, Interpolation.create(config));
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
@@ -1040,14 +997,6 @@ class AnimatedMultiplication extends AnimatedWithChildren {
|
||||
__detach(): void {
|
||||
this._a.__removeChild(this);
|
||||
this._b.__removeChild(this);
|
||||
super.__detach();
|
||||
}
|
||||
|
||||
__getNativeConfig(): any {
|
||||
return {
|
||||
type: 'multiplication',
|
||||
input: [this._a.__getNativeTag(), this._b.__getNativeTag()],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,7 +1015,7 @@ class AnimatedModulo extends AnimatedWithChildren {
|
||||
}
|
||||
|
||||
interpolate(config: InterpolationConfigType): AnimatedInterpolation {
|
||||
return new AnimatedInterpolation(this, config);
|
||||
return new AnimatedInterpolation(this, Interpolation.create(config));
|
||||
}
|
||||
|
||||
__attach(): void {
|
||||
@@ -1445,7 +1394,7 @@ function createAnimatedComponent(Component: any): any {
|
||||
|
||||
for (var key in ViewStylePropTypes) {
|
||||
if (!Component.propTypes[key] && props[key] !== undefined) {
|
||||
console.warn(
|
||||
console.error(
|
||||
'You are setting the style `{ ' + key + ': ... }` as a prop. You ' +
|
||||
'should nest it in a style object. ' +
|
||||
'E.g. `{ style: { ' + key + ': ... } }`'
|
||||
|
||||
@@ -233,7 +233,7 @@ function createInterpolationFromStringOutputRange(
|
||||
// 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...'
|
||||
return outputRange[0].replace(stringShapeRegex, () => {
|
||||
const val = +interpolations[i++](input);
|
||||
const rounded = shouldRound && i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000;
|
||||
const rounded = shouldRound && i < 4 ? Math.round(val) : val;
|
||||
return String(rounded);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ var NativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
|
||||
var __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */
|
||||
var __nativeAnimationIdCount = 1; /* used for started animations */
|
||||
var __nativeAnimationTagCount = 1; /* used for started animations */
|
||||
|
||||
type EndResult = {finished: bool};
|
||||
type EndCallback = (result: EndResult) => void;
|
||||
@@ -38,13 +38,9 @@ var API = {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag);
|
||||
},
|
||||
startAnimatingNode: function(animationId: number, nodeTag: number, config: Object, endCallback: EndCallback): void {
|
||||
startAnimatingNode: function(animationTag: number, nodeTag: number, config: Object, endCallback: EndCallback): void {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.startAnimatingNode(animationId, nodeTag, config, endCallback);
|
||||
},
|
||||
stopAnimation: function(animationId: number) {
|
||||
assertNativeAnimatedModule();
|
||||
NativeAnimatedModule.stopAnimation(animationId);
|
||||
NativeAnimatedModule.startAnimatingNode(nodeTag, config, endCallback);
|
||||
},
|
||||
setAnimatedNodeValue: function(nodeTag: number, value: number): void {
|
||||
assertNativeAnimatedModule();
|
||||
@@ -101,24 +97,12 @@ function validateStyles(styles: Object): void {
|
||||
}
|
||||
}
|
||||
|
||||
function validateInterpolation(config: Object): void {
|
||||
var SUPPORTED_INTERPOLATION_PARAMS = {
|
||||
inputRange: true,
|
||||
outputRange: true,
|
||||
};
|
||||
for (var key in config) {
|
||||
if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) {
|
||||
throw new Error(`Interpolation property '${key}' is not supported by native animated module`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateNewNodeTag(): number {
|
||||
return __nativeAnimatedNodeTagCount++;
|
||||
}
|
||||
|
||||
function generateNewAnimationId(): number {
|
||||
return __nativeAnimationIdCount++;
|
||||
function generateNewAnimationTag(): number {
|
||||
return __nativeAnimationTagCount++;
|
||||
}
|
||||
|
||||
function assertNativeAnimatedModule(): void {
|
||||
@@ -129,8 +113,7 @@ module.exports = {
|
||||
API,
|
||||
validateProps,
|
||||
validateStyles,
|
||||
validateInterpolation,
|
||||
generateNewNodeTag,
|
||||
generateNewAnimationId,
|
||||
generateNewAnimationTag,
|
||||
assertNativeAnimatedModule,
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
'use strict';
|
||||
|
||||
jest
|
||||
.disableAutomock()
|
||||
.autoMockOff()
|
||||
.setMock('Text', {})
|
||||
.setMock('View', {})
|
||||
.setMock('Image', {})
|
||||
@@ -22,7 +22,7 @@ describe('Animated', () => {
|
||||
it('works end to end', () => {
|
||||
var anim = new Animated.Value(0);
|
||||
|
||||
var callback = jest.fn();
|
||||
var callback = jest.genMockFunction();
|
||||
|
||||
var node = new Animated.__PropsOnlyForTests({
|
||||
style: {
|
||||
@@ -75,7 +75,7 @@ describe('Animated', () => {
|
||||
|
||||
it('does not detach on updates', () => {
|
||||
var anim = new Animated.Value(0);
|
||||
anim.__detach = jest.fn();
|
||||
anim.__detach = jest.genMockFunction();
|
||||
|
||||
var c = new Animated.View();
|
||||
c.props = {
|
||||
@@ -101,11 +101,11 @@ describe('Animated', () => {
|
||||
it('stops animation when detached', () => {
|
||||
// jest environment doesn't have cancelAnimationFrame :(
|
||||
if (!window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame = jest.fn();
|
||||
window.cancelAnimationFrame = jest.genMockFunction();
|
||||
}
|
||||
|
||||
var anim = new Animated.Value(0);
|
||||
var callback = jest.fn();
|
||||
var callback = jest.genMockFunction();
|
||||
|
||||
var c = new Animated.View();
|
||||
c.props = {
|
||||
@@ -125,14 +125,14 @@ describe('Animated', () => {
|
||||
|
||||
it('triggers callback when spring is at rest', () => {
|
||||
var anim = new Animated.Value(0);
|
||||
var callback = jest.fn();
|
||||
var callback = jest.genMockFunction();
|
||||
Animated.spring(anim, {toValue: 0, velocity: 0}).start(callback);
|
||||
expect(callback).toBeCalled();
|
||||
});
|
||||
|
||||
it('send toValue when a spring stops', () => {
|
||||
var anim = new Animated.Value(0);
|
||||
var listener = jest.fn();
|
||||
var listener = jest.genMockFunction();
|
||||
anim.addListener(listener);
|
||||
Animated.spring(anim, {toValue: 15}).start();
|
||||
jest.runAllTimers();
|
||||
@@ -142,24 +142,21 @@ describe('Animated', () => {
|
||||
expect(anim.__getValue()).toBe(15);
|
||||
});
|
||||
|
||||
it('convert to JSON', () => {
|
||||
expect(JSON.stringify(new Animated.Value(10))).toBe('10');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Animated Sequence', () => {
|
||||
|
||||
it('works with an empty sequence', () => {
|
||||
var cb = jest.fn();
|
||||
var cb = jest.genMockFunction();
|
||||
Animated.sequence([]).start(cb);
|
||||
expect(cb).toBeCalledWith({finished: true});
|
||||
});
|
||||
|
||||
it('sequences well', () => {
|
||||
var anim1 = {start: jest.fn()};
|
||||
var anim2 = {start: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim1 = {start: jest.genMockFunction()};
|
||||
var anim2 = {start: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
|
||||
var seq = Animated.sequence([anim1, anim2]);
|
||||
|
||||
@@ -182,9 +179,9 @@ describe('Animated Sequence', () => {
|
||||
});
|
||||
|
||||
it('supports interrupting sequence', () => {
|
||||
var anim1 = {start: jest.fn()};
|
||||
var anim2 = {start: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim1 = {start: jest.genMockFunction()};
|
||||
var anim2 = {start: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
|
||||
Animated.sequence([anim1, anim2]).start(cb);
|
||||
|
||||
@@ -196,9 +193,9 @@ describe('Animated Sequence', () => {
|
||||
});
|
||||
|
||||
it('supports stopping sequence', () => {
|
||||
var anim1 = {start: jest.fn(), stop: jest.fn()};
|
||||
var anim2 = {start: jest.fn(), stop: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim1 = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var anim2 = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
|
||||
var seq = Animated.sequence([anim1, anim2]);
|
||||
seq.start(cb);
|
||||
@@ -218,14 +215,14 @@ describe('Animated Sequence', () => {
|
||||
describe('Animated Parallel', () => {
|
||||
|
||||
it('works with an empty parallel', () => {
|
||||
var cb = jest.fn();
|
||||
var cb = jest.genMockFunction();
|
||||
Animated.parallel([]).start(cb);
|
||||
expect(cb).toBeCalledWith({finished: true});
|
||||
});
|
||||
|
||||
it('works with an empty element in array', () => {
|
||||
var anim1 = {start: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim1 = {start: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
Animated.parallel([null, anim1]).start(cb);
|
||||
|
||||
expect(anim1.start).toBeCalled();
|
||||
@@ -235,9 +232,9 @@ describe('Animated Parallel', () => {
|
||||
});
|
||||
|
||||
it('parellelizes well', () => {
|
||||
var anim1 = {start: jest.fn()};
|
||||
var anim2 = {start: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim1 = {start: jest.genMockFunction()};
|
||||
var anim2 = {start: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
|
||||
var par = Animated.parallel([anim1, anim2]);
|
||||
|
||||
@@ -258,9 +255,9 @@ describe('Animated Parallel', () => {
|
||||
});
|
||||
|
||||
it('supports stopping parallel', () => {
|
||||
var anim1 = {start: jest.fn(), stop: jest.fn()};
|
||||
var anim2 = {start: jest.fn(), stop: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim1 = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var anim2 = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
|
||||
var seq = Animated.parallel([anim1, anim2]);
|
||||
seq.start(cb);
|
||||
@@ -279,10 +276,10 @@ describe('Animated Parallel', () => {
|
||||
|
||||
|
||||
it('does not call stop more than once when stopping', () => {
|
||||
var anim1 = {start: jest.fn(), stop: jest.fn()};
|
||||
var anim2 = {start: jest.fn(), stop: jest.fn()};
|
||||
var anim3 = {start: jest.fn(), stop: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim1 = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var anim2 = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var anim3 = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
|
||||
var seq = Animated.parallel([anim1, anim2, anim3]);
|
||||
seq.start(cb);
|
||||
@@ -309,8 +306,8 @@ describe('Animated Parallel', () => {
|
||||
|
||||
describe('Animated delays', () => {
|
||||
it('should call anim after delay in sequence', () => {
|
||||
var anim = {start: jest.fn(), stop: jest.fn()};
|
||||
var cb = jest.fn();
|
||||
var anim = {start: jest.genMockFunction(), stop: jest.genMockFunction()};
|
||||
var cb = jest.genMockFunction();
|
||||
Animated.sequence([
|
||||
Animated.delay(1000),
|
||||
anim,
|
||||
@@ -322,7 +319,7 @@ describe('Animated delays', () => {
|
||||
expect(cb).toBeCalledWith({finished: true});
|
||||
});
|
||||
it('should run stagger to end', () => {
|
||||
var cb = jest.fn();
|
||||
var cb = jest.genMockFunction();
|
||||
Animated.stagger(1000, [
|
||||
Animated.delay(1000),
|
||||
Animated.delay(1000),
|
||||
@@ -344,7 +341,7 @@ describe('Animated Events', () => {
|
||||
});
|
||||
it('should call listeners', () => {
|
||||
var value = new Animated.Value(0);
|
||||
var listener = jest.fn();
|
||||
var listener = jest.genMockFunction();
|
||||
var handler = Animated.event(
|
||||
[{foo: value}],
|
||||
{listener},
|
||||
@@ -369,14 +366,14 @@ describe('Animated Interactions', () => {
|
||||
});
|
||||
|
||||
afterEach(()=> {
|
||||
jest.unmock('InteractionManager');
|
||||
jest.dontMock('InteractionManager');
|
||||
});
|
||||
|
||||
it('registers an interaction by default', () => {
|
||||
InteractionManager.createInteractionHandle.mockReturnValue(777);
|
||||
|
||||
var value = new Animated.Value(0);
|
||||
var callback = jest.fn();
|
||||
var callback = jest.genMockFunction();
|
||||
Animated.timing(value, {
|
||||
toValue: 100,
|
||||
duration: 100,
|
||||
@@ -390,7 +387,7 @@ describe('Animated Interactions', () => {
|
||||
|
||||
it('does not register an interaction when specified', () => {
|
||||
var value = new Animated.Value(0);
|
||||
var callback = jest.fn();
|
||||
var callback = jest.genMockFunction();
|
||||
Animated.timing(value, {
|
||||
toValue: 100,
|
||||
duration: 100,
|
||||
@@ -454,7 +451,7 @@ describe('Animated Vectors', () => {
|
||||
it('should animate vectors', () => {
|
||||
var vec = new Animated.ValueXY();
|
||||
|
||||
var callback = jest.fn();
|
||||
var callback = jest.genMockFunction();
|
||||
|
||||
var node = new Animated.__PropsOnlyForTests({
|
||||
style: {
|
||||
@@ -539,7 +536,7 @@ describe('Animated Vectors', () => {
|
||||
describe('Animated Listeners', () => {
|
||||
it('should get updates', () => {
|
||||
var value1 = new Animated.Value(0);
|
||||
var listener = jest.fn();
|
||||
var listener = jest.genMockFunction();
|
||||
var id = value1.addListener(listener);
|
||||
value1.setValue(42);
|
||||
expect(listener.mock.calls.length).toBe(1);
|
||||
@@ -557,7 +554,7 @@ describe('Animated Listeners', () => {
|
||||
|
||||
it('should removeAll', () => {
|
||||
var value1 = new Animated.Value(0);
|
||||
var listener = jest.fn();
|
||||
var listener = jest.genMockFunction();
|
||||
[1,2,3,4].forEach(() => value1.addListener(listener));
|
||||
value1.setValue(42);
|
||||
expect(listener.mock.calls.length).toBe(4);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
'use strict';
|
||||
|
||||
jest
|
||||
.disableAutomock()
|
||||
.autoMockOff()
|
||||
.setMock('Text', {})
|
||||
.setMock('View', {})
|
||||
.setMock('Image', {})
|
||||
@@ -24,19 +24,18 @@ describe('Animated', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
nativeAnimatedModule.createAnimatedNode = jest.fn();
|
||||
nativeAnimatedModule.connectAnimatedNodes = jest.fn();
|
||||
nativeAnimatedModule.disconnectAnimatedNodes = jest.fn();
|
||||
nativeAnimatedModule.startAnimatingNode = jest.fn();
|
||||
nativeAnimatedModule.stopAnimation = jest.fn();
|
||||
nativeAnimatedModule.setAnimatedNodeValue = jest.fn();
|
||||
nativeAnimatedModule.connectAnimatedNodeToView = jest.fn();
|
||||
nativeAnimatedModule.disconnectAnimatedNodeFromView = jest.fn();
|
||||
nativeAnimatedModule.dropAnimatedNode = jest.fn();
|
||||
nativeAnimatedModule.createAnimatedNode = jest.genMockFunction();
|
||||
nativeAnimatedModule.connectAnimatedNodes = jest.genMockFunction();
|
||||
nativeAnimatedModule.disconnectAnimatedNodes = jest.genMockFunction();
|
||||
nativeAnimatedModule.startAnimatingNode = jest.genMockFunction();
|
||||
nativeAnimatedModule.setAnimatedNodeValue = jest.genMockFunction();
|
||||
nativeAnimatedModule.connectAnimatedNodeToView = jest.genMockFunction();
|
||||
nativeAnimatedModule.disconnectAnimatedNodeFromView = jest.genMockFunction();
|
||||
nativeAnimatedModule.dropAnimatedNode = jest.genMockFunction();
|
||||
|
||||
// jest environment doesn't have cancelAnimationFrame :(
|
||||
if (!window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame = jest.fn();
|
||||
window.cancelAnimationFrame = jest.genMockFunction();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -60,7 +59,6 @@ describe('Animated', () => {
|
||||
expect(nativeAnimatedModule.connectAnimatedNodes.mock.calls.length).toBe(2);
|
||||
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
jasmine.any(Number),
|
||||
jasmine.any(Number),
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number)},
|
||||
jasmine.any(Function)
|
||||
@@ -92,114 +90,12 @@ describe('Animated', () => {
|
||||
.toBeCalledWith(jasmine.any(Number), { type: 'props', props: { style: jasmine.any(Number) }});
|
||||
});
|
||||
|
||||
it('sends a valid graph description for Animated.add nodes', () => {
|
||||
var first = new Animated.Value(1);
|
||||
var second = new Animated.Value(2);
|
||||
|
||||
var c = new Animated.View();
|
||||
c.props = {
|
||||
style: {
|
||||
opacity: Animated.add(first, second),
|
||||
},
|
||||
};
|
||||
c.componentWillMount();
|
||||
|
||||
Animated.timing(first, {toValue: 2, duration: 1000, useNativeDriver: true}).start();
|
||||
Animated.timing(second, {toValue: 3, duration: 1000, useNativeDriver: true}).start();
|
||||
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(jasmine.any(Number), { type: 'addition', input: jasmine.any(Array) });
|
||||
var additionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
(call) => call[1].type === 'addition'
|
||||
);
|
||||
expect(additionCalls.length).toBe(1);
|
||||
var additionCall = additionCalls[0];
|
||||
var additionNodeTag = additionCall[0];
|
||||
var additionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
(call) => call[1] === additionNodeTag
|
||||
);
|
||||
expect(additionConnectionCalls.length).toBe(2);
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(additionCall[1].input[0], { type: 'value', value: 1 });
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(additionCall[1].input[1], { type: 'value', value: 2 });
|
||||
});
|
||||
|
||||
it('sends a valid graph description for Animated.multiply nodes', () => {
|
||||
var first = new Animated.Value(2);
|
||||
var second = new Animated.Value(1);
|
||||
|
||||
var c = new Animated.View();
|
||||
c.props = {
|
||||
style: {
|
||||
opacity: Animated.multiply(first, second),
|
||||
},
|
||||
};
|
||||
c.componentWillMount();
|
||||
|
||||
Animated.timing(first, {toValue: 5, duration: 1000, useNativeDriver: true}).start();
|
||||
Animated.timing(second, {toValue: -1, duration: 1000, useNativeDriver: true}).start();
|
||||
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(jasmine.any(Number), { type: 'multiplication', input: jasmine.any(Array) });
|
||||
var multiplicationCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
(call) => call[1].type === 'multiplication'
|
||||
);
|
||||
expect(multiplicationCalls.length).toBe(1);
|
||||
var multiplicationCall = multiplicationCalls[0];
|
||||
var multiplicationNodeTag = multiplicationCall[0];
|
||||
var multiplicationConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
(call) => call[1] === multiplicationNodeTag
|
||||
);
|
||||
expect(multiplicationConnectionCalls.length).toBe(2);
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(multiplicationCall[1].input[0], { type: 'value', value: 2 });
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(multiplicationCall[1].input[1], { type: 'value', value: 1 });
|
||||
});
|
||||
|
||||
it('sends a valid graph description for interpolate() nodes', () => {
|
||||
var node = new Animated.Value(10);
|
||||
|
||||
var c = new Animated.View();
|
||||
c.props = {
|
||||
style: {
|
||||
opacity: node.interpolate({
|
||||
inputRange: [10, 20],
|
||||
outputRange: [0, 1],
|
||||
}),
|
||||
},
|
||||
};
|
||||
c.componentWillMount();
|
||||
|
||||
Animated.timing(node, {toValue: 20, duration: 1000, useNativeDriver: true}).start();
|
||||
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(jasmine.any(Number), { type: 'value', value: 10 });
|
||||
expect(nativeAnimatedModule.createAnimatedNode)
|
||||
.toBeCalledWith(jasmine.any(Number), {
|
||||
type: 'interpolation',
|
||||
inputRange: [10, 20],
|
||||
outputRange: [0, 1],
|
||||
});
|
||||
var interpolationNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find(
|
||||
(call) => call[1].type === 'interpolation'
|
||||
)[0];
|
||||
var valueNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find(
|
||||
(call) => call[1].type === 'value'
|
||||
)[0];
|
||||
expect(nativeAnimatedModule.connectAnimatedNodes).toBeCalledWith(valueNodeTag, interpolationNodeTag);
|
||||
});
|
||||
|
||||
it('sends a valid timing animation description', () => {
|
||||
var anim = new Animated.Value(0);
|
||||
Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start();
|
||||
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
jasmine.any(Number),
|
||||
jasmine.any(Number),
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number)},
|
||||
jasmine.any(Function)
|
||||
@@ -210,27 +106,10 @@ describe('Animated', () => {
|
||||
var anim = new Animated.Value(0);
|
||||
Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start();
|
||||
|
||||
var c = new Animated.View();
|
||||
c.props = {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
};
|
||||
c.componentWillMount();
|
||||
|
||||
// We expect `setValue` not to propagate down to `setNativeProps`, otherwise it may try to access `setNativeProps`
|
||||
// via component refs table that we override here.
|
||||
c.refs = {
|
||||
node: {
|
||||
setNativeProps: jest.genMockFunction(),
|
||||
},
|
||||
};
|
||||
|
||||
anim.setValue(0.5);
|
||||
anim.setValue(5);
|
||||
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(jasmine.any(Number), 0.5);
|
||||
expect(c.refs.node.setNativeProps.mock.calls.length).toBe(0);
|
||||
expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(jasmine.any(Number), 5);
|
||||
});
|
||||
|
||||
it('doesn\'t call into native API if useNativeDriver is set to false', () => {
|
||||
@@ -300,25 +179,6 @@ describe('Animated', () => {
|
||||
expect(animation.start).toThrowError(/left/);
|
||||
});
|
||||
|
||||
it('fails for unsupported interpolation parameters', () => {
|
||||
var anim = new Animated.Value(0);
|
||||
|
||||
var c = new Animated.View();
|
||||
c.props = {
|
||||
style: {
|
||||
opacity: anim.interpolate({
|
||||
inputRange: [0, 100],
|
||||
outputRange: [0, 1],
|
||||
extrapolate: 'clamp',
|
||||
}),
|
||||
},
|
||||
};
|
||||
c.componentWillMount();
|
||||
|
||||
var animation = Animated.timing(anim, {toValue: 100, duration: 50, useNativeDriver: true});
|
||||
expect(animation.start).toThrowError(/extrapolate/);
|
||||
});
|
||||
|
||||
it('works for any `static` props and styles', () => {
|
||||
// Passing "unsupported" props should work just fine as long as they are not animated
|
||||
var anim = new Animated.Value(0);
|
||||
@@ -341,22 +201,4 @@ describe('Animated', () => {
|
||||
.toBeCalledWith(jasmine.any(Number), { type: 'props', props: { style: jasmine.any(Number) }});
|
||||
});
|
||||
|
||||
it('send stopAnimation command to native', () => {
|
||||
var value = new Animated.Value(0);
|
||||
var animation = Animated.timing(value, {toValue: 10, duration: 50, useNativeDriver: true});
|
||||
var nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
|
||||
animation.start();
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
jasmine.any(Number),
|
||||
jasmine.any(Number),
|
||||
{type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number)},
|
||||
jasmine.any(Function)
|
||||
);
|
||||
var animationId = nativeAnimatedModule.startAnimatingNode.mock.calls[0][0];
|
||||
|
||||
animation.stop();
|
||||
expect(nativeAnimatedModule.stopAnimation).toBeCalledWith(animationId);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
jest.unmock('Easing');
|
||||
jest.dontMock('Easing');
|
||||
|
||||
var Easing = require('Easing');
|
||||
describe('Easing', () => {
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
'use strict';
|
||||
|
||||
jest
|
||||
.unmock('Interpolation')
|
||||
.unmock('Easing')
|
||||
.unmock('normalizeColor');
|
||||
.dontMock('Interpolation')
|
||||
.dontMock('Easing')
|
||||
.dontMock('normalizeColor');
|
||||
|
||||
var Interpolation = require('Interpolation');
|
||||
var Easing = require('Easing');
|
||||
@@ -294,14 +294,4 @@ describe('Interpolation', () => {
|
||||
outputRange: ['20deg', '30rad'],
|
||||
})).toThrow();
|
||||
});
|
||||
|
||||
it('should round the alpha channel of a color to the nearest thousandth', () => {
|
||||
var interpolation = Interpolation.create({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, 1)'],
|
||||
});
|
||||
|
||||
expect(interpolation(1e-12)).toBe('rgba(0, 0, 0, 0)');
|
||||
expect(interpolation(2 / 3)).toBe('rgba(0, 0, 0, 0.667)');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable */
|
||||
|
||||
jest.unmock('bezier');
|
||||
jest.dontMock('bezier');
|
||||
var bezier = require('bezier');
|
||||
|
||||
var identity = function (x) { return x; };
|
||||
|
||||
@@ -12,12 +12,10 @@
|
||||
'use strict';
|
||||
|
||||
var BatchedBridge = require('BatchedBridge');
|
||||
var BugReporting = require('BugReporting');
|
||||
var ReactNative = require('ReactNative');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var renderApplication = require('renderApplication');
|
||||
const infoLog = require('infoLog');
|
||||
|
||||
if (__DEV__) {
|
||||
// In order to use Cmd+P to record/dump perf data, we need to make sure
|
||||
@@ -26,7 +24,6 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
var runnables = {};
|
||||
var runCount = 1;
|
||||
|
||||
type ComponentProvider = () => ReactClass<any>;
|
||||
|
||||
@@ -82,14 +79,13 @@ var AppRegistry = {
|
||||
},
|
||||
|
||||
runApplication: function(appKey: string, appParameters: any): void {
|
||||
const msg =
|
||||
console.log(
|
||||
'Running application "' + appKey + '" with appParams: ' +
|
||||
JSON.stringify(appParameters) + '. ' +
|
||||
'__DEV__ === ' + String(__DEV__) +
|
||||
', development-level warning are ' + (__DEV__ ? 'ON' : 'OFF') +
|
||||
', performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON');
|
||||
infoLog(msg);
|
||||
BugReporting.addSource('AppRegistry.runApplication' + runCount++, () => msg);
|
||||
', performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON')
|
||||
);
|
||||
invariant(
|
||||
runnables[appKey] && runnables[appKey].run,
|
||||
'Application ' + appKey + ' has not been registered. This ' +
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
const MessageQueue = require('MessageQueue');
|
||||
|
||||
const BatchedBridge = new MessageQueue(
|
||||
() => global.__fbBatchedBridgeConfig
|
||||
__fbBatchedBridgeConfig.remoteModuleConfig,
|
||||
__fbBatchedBridgeConfig.localModulesConfig,
|
||||
);
|
||||
|
||||
// TODO: Move these around to solve the cycle in a cleaner way.
|
||||
@@ -23,7 +24,6 @@ const JSTimersExecution = require('JSTimersExecution');
|
||||
|
||||
BatchedBridge.registerCallableModule('Systrace', Systrace);
|
||||
BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);
|
||||
BatchedBridge.registerCallableModule('HeapCapture', require('HeapCapture'));
|
||||
|
||||
if (__DEV__) {
|
||||
BatchedBridge.registerCallableModule('HMRClient', require('HMRClient'));
|
||||
|
||||
@@ -51,14 +51,65 @@ Object.keys(RemoteModules).forEach((moduleName) => {
|
||||
module = config && BatchedBridge.processModuleConfig(config, module.moduleID);
|
||||
RemoteModules[moduleName] = module;
|
||||
}
|
||||
Object.defineProperty(NativeModules, moduleName, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value: module,
|
||||
});
|
||||
return module;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Copies the ViewManager constants and commands into UIManager. This is
|
||||
* only needed for iOS, which puts the constants in the ViewManager
|
||||
* namespace instead of UIManager, unlike Android.
|
||||
*
|
||||
* We'll eventually move this logic to UIManager.js, once all
|
||||
* the call sites accessing NativeModules.UIManager directly have
|
||||
* been removed #9344445
|
||||
*/
|
||||
const UIManager = NativeModules.UIManager;
|
||||
UIManager && Object.keys(UIManager).forEach(viewName => {
|
||||
const viewConfig = UIManager[viewName];
|
||||
if (viewConfig.Manager) {
|
||||
let constants;
|
||||
/* $FlowFixMe - nice try. Flow doesn't like getters */
|
||||
Object.defineProperty(viewConfig, 'Constants', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: () => {
|
||||
if (constants) {
|
||||
return constants;
|
||||
}
|
||||
constants = {};
|
||||
const viewManager = NativeModules[normalizePrefix(viewConfig.Manager)];
|
||||
viewManager && Object.keys(viewManager).forEach(key => {
|
||||
const value = viewManager[key];
|
||||
if (typeof value !== 'function') {
|
||||
constants[key] = value;
|
||||
}
|
||||
});
|
||||
return constants;
|
||||
},
|
||||
});
|
||||
let commands;
|
||||
/* $FlowFixMe - nice try. Flow doesn't like getters */
|
||||
Object.defineProperty(viewConfig, 'Commands', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: () => {
|
||||
if (commands) {
|
||||
return commands;
|
||||
}
|
||||
commands = {};
|
||||
const viewManager = NativeModules[normalizePrefix(viewConfig.Manager)];
|
||||
viewManager && Object.keys(viewManager).forEach((key, index) => {
|
||||
const value = viewManager[key];
|
||||
if (typeof value === 'function') {
|
||||
commands[key] = index;
|
||||
}
|
||||
});
|
||||
return commands;
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = NativeModules;
|
||||
|
||||
@@ -11,15 +11,13 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const BatchedBridge = require('BatchedBridge');
|
||||
var BatchedBridge = require('BatchedBridge');
|
||||
var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
|
||||
|
||||
const RCTEventEmitter = {
|
||||
register(eventEmitter: any) {
|
||||
BatchedBridge.registerCallableModule(
|
||||
'RCTEventEmitter',
|
||||
eventEmitter
|
||||
);
|
||||
}
|
||||
};
|
||||
BatchedBridge.registerCallableModule(
|
||||
'RCTEventEmitter',
|
||||
ReactNativeEventEmitter
|
||||
);
|
||||
|
||||
module.exports = RCTEventEmitter;
|
||||
// Completely locally implemented - no native hooks.
|
||||
module.exports = ReactNativeEventEmitter;
|
||||
|
||||
@@ -10,19 +10,21 @@ var NativeModules = {
|
||||
}),
|
||||
},
|
||||
Timing: {
|
||||
createTimer: jest.fn(),
|
||||
deleteTimer: jest.fn(),
|
||||
createTimer: jest.genMockFunction(),
|
||||
deleteTimer: jest.genMockFunction(),
|
||||
},
|
||||
GraphPhotoUpload: {
|
||||
upload: jest.fn(),
|
||||
upload: jest.genMockFunction(),
|
||||
},
|
||||
FacebookSDK: {
|
||||
login: jest.fn(),
|
||||
logout: jest.fn(),
|
||||
queryGraphPath: jest.fn((path, method, params, callback) => callback()),
|
||||
login: jest.genMockFunction(),
|
||||
logout: jest.genMockFunction(),
|
||||
queryGraphPath: jest.genMockFunction().mockImpl(
|
||||
(path, method, params, callback) => callback()
|
||||
),
|
||||
},
|
||||
DataManager: {
|
||||
queryData: jest.fn(),
|
||||
queryData: jest.genMockFunction(),
|
||||
},
|
||||
UIManager: {
|
||||
customBubblingEventTypes: {},
|
||||
@@ -36,10 +38,10 @@ var NativeModules = {
|
||||
},
|
||||
},
|
||||
AsyncLocalStorage: {
|
||||
getItem: jest.fn(),
|
||||
setItem: jest.fn(),
|
||||
removeItem: jest.fn(),
|
||||
clear: jest.fn(),
|
||||
getItem: jest.genMockFunction(),
|
||||
setItem: jest.genMockFunction(),
|
||||
removeItem: jest.genMockFunction(),
|
||||
clear: jest.genMockFunction(),
|
||||
},
|
||||
SourceCode: {
|
||||
scriptURL: null,
|
||||
@@ -50,10 +52,10 @@ var NativeModules = {
|
||||
},
|
||||
ModalFullscreenViewManager: {},
|
||||
AlertManager: {
|
||||
alertWithArgs: jest.fn(),
|
||||
alertWithArgs: jest.genMockFunction(),
|
||||
},
|
||||
Clipboard: {
|
||||
setString: jest.fn(),
|
||||
setString: jest.genMockFunction(),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule BugReporting
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
const Map = require('Map');
|
||||
const infoLog = require('infoLog');
|
||||
|
||||
import type EmitterSubscription from 'EmitterSubscription';
|
||||
|
||||
type ExtraData = { [key: string]: string };
|
||||
type SourceCallback = () => string;
|
||||
type DebugData = { extras: ExtraData, files: ExtraData };
|
||||
|
||||
function defaultExtras() {
|
||||
BugReporting.addFileSource('react_hierarchy.txt', () => require('dumpReactTree')());
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class for collecting bug report data. Components can add sources that will be queried when a bug report
|
||||
* is created via `collectExtraData`. For example, a list component might add a source that provides the list of rows
|
||||
* that are currently visible on screen. Components should also remember to call `remove()` on the object that is
|
||||
* returned by `addSource` when they are unmounted.
|
||||
*/
|
||||
class BugReporting {
|
||||
static _extraSources: Map<string, SourceCallback> = new Map();
|
||||
static _fileSources: Map<string, SourceCallback> = new Map();
|
||||
static _subscription: ?EmitterSubscription = null;
|
||||
|
||||
static _maybeInit() {
|
||||
if (!BugReporting._subscription) {
|
||||
BugReporting._subscription = RCTDeviceEventEmitter
|
||||
.addListener('collectBugExtraData', BugReporting.collectExtraData, null);
|
||||
defaultExtras();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a string key to a simple callback that should return a string payload to be attached
|
||||
* to a bug report. Source callbacks are called when `collectExtraData` is called.
|
||||
*
|
||||
* Returns an object to remove the source when the component unmounts.
|
||||
*
|
||||
* Conflicts trample with a warning.
|
||||
*/
|
||||
static addSource(key: string, callback: SourceCallback): {remove: () => void} {
|
||||
return this._addSource(key, callback, BugReporting._extraSources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a string key to a simple callback that should return a string payload to be attached
|
||||
* to a bug report. Source callbacks are called when `collectExtraData` is called.
|
||||
*
|
||||
* Returns an object to remove the source when the component unmounts.
|
||||
*
|
||||
* Conflicts trample with a warning.
|
||||
*/
|
||||
static addFileSource(key: string, callback: SourceCallback): {remove: () => void} {
|
||||
return this._addSource(key, callback, BugReporting._fileSources);
|
||||
}
|
||||
|
||||
static _addSource(key: string, callback: SourceCallback, source: Map<string, SourceCallback>): {remove: () => void} {
|
||||
BugReporting._maybeInit();
|
||||
if (source.has(key)) {
|
||||
console.warn(`BugReporting.add* called multiple times for same key '${key}'`);
|
||||
}
|
||||
source.set(key, callback);
|
||||
return {remove: () => { source.delete(key); }};
|
||||
}
|
||||
|
||||
/**
|
||||
* This can be called from a native bug reporting flow, or from JS code.
|
||||
*
|
||||
* If available, this will call `NativeModules.BugReporting.setExtraData(extraData)`
|
||||
* after collecting `extraData`.
|
||||
*/
|
||||
static collectExtraData(): DebugData {
|
||||
const extraData: ExtraData = {};
|
||||
for (const [key, callback] of BugReporting._extraSources) {
|
||||
extraData[key] = callback();
|
||||
}
|
||||
const fileData: ExtraData = {};
|
||||
for (const [key, callback] of BugReporting._fileSources) {
|
||||
fileData[key] = callback();
|
||||
}
|
||||
infoLog('BugReporting extraData:', extraData);
|
||||
const BugReportingNativeModule = require('NativeModules').BugReporting;
|
||||
BugReportingNativeModule &&
|
||||
BugReportingNativeModule.setExtraData &&
|
||||
BugReportingNativeModule.setExtraData(extraData, fileData);
|
||||
|
||||
return { extras: extraData, files: fileData };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BugReporting;
|
||||
@@ -1,142 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule dumpReactTree
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const ReactNativeMount = require('ReactNativeMount');
|
||||
const getReactData = require('getReactData');
|
||||
|
||||
const INDENTATION_SIZE = 2;
|
||||
const MAX_DEPTH = 2;
|
||||
const MAX_STRING_LENGTH = 50;
|
||||
|
||||
/**
|
||||
* Dump all React Native root views and their content. This function tries
|
||||
* it best to get the content but ultimately relies on implementation details
|
||||
* of React and will fail in future versions.
|
||||
*/
|
||||
function dumpReactTree() {
|
||||
try {
|
||||
return getReactTree();
|
||||
} catch (e) {
|
||||
return 'Failed to dump react tree: ' + e;
|
||||
}
|
||||
}
|
||||
|
||||
function getReactTree() {
|
||||
let output = '';
|
||||
const rootIds = Object.getOwnPropertyNames(ReactNativeMount._instancesByContainerID);
|
||||
for (const rootId of rootIds) {
|
||||
const instance = ReactNativeMount._instancesByContainerID[rootId];
|
||||
output += `============ Root ID: ${rootId} ============\n`;
|
||||
output += dumpNode(instance, 0);
|
||||
output += `============ End root ID: ${rootId} ============\n`;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function dumpNode(node: Object, identation: number) {
|
||||
const data = getReactData(node);
|
||||
if (data.nodeType === 'Text') {
|
||||
return indent(identation) + data.text + '\n';
|
||||
} else if (data.nodeType === 'Empty') {
|
||||
return '';
|
||||
}
|
||||
let output = indent(identation) + `<${data.name}`;
|
||||
if (data.nodeType === 'Composite') {
|
||||
for (const propName of Object.getOwnPropertyNames(data.props || {})) {
|
||||
if (isNormalProp(propName)) {
|
||||
try {
|
||||
const value = convertValue(data.props[propName]);
|
||||
if (value) {
|
||||
output += ` ${propName}=${value}`;
|
||||
}
|
||||
} catch (e) {
|
||||
const message = `[Failed to get property: ${e}]`;
|
||||
output += ` ${propName}=${message}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let childOutput = '';
|
||||
for (const child of data.children || []) {
|
||||
childOutput += dumpNode(child, identation + 1);
|
||||
}
|
||||
|
||||
if (childOutput) {
|
||||
output += '>\n' + childOutput + indent(identation) + `</${data.name}>\n`;
|
||||
} else {
|
||||
output += ' />\n';
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function isNormalProp(name: string): boolean {
|
||||
switch (name) {
|
||||
case 'children':
|
||||
case 'key':
|
||||
case 'ref':
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function convertObject(object: Object, depth: number) {
|
||||
if (depth >= MAX_DEPTH) {
|
||||
return '[...omitted]';
|
||||
}
|
||||
let output = '{';
|
||||
let first = true;
|
||||
for (const key of Object.getOwnPropertyNames(object)) {
|
||||
if (!first) {
|
||||
output += ', ';
|
||||
}
|
||||
output += `${key}: ${convertValue(object[key], depth + 1)}`;
|
||||
first = false;
|
||||
}
|
||||
return output + '}';
|
||||
}
|
||||
|
||||
function convertValue(value, depth = 0): ?string {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return JSON.stringify(possiblyEllipsis(value).replace('\n', '\\n'));
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
return JSON.stringify(value);
|
||||
case 'function':
|
||||
return '[function]';
|
||||
case 'object':
|
||||
return convertObject(value, depth);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function possiblyEllipsis(value: string) {
|
||||
if (value.length > MAX_STRING_LENGTH) {
|
||||
return value.slice(0, MAX_STRING_LENGTH) + '...';
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
function indent(size: number) {
|
||||
return ' '.repeat(size * INDENTATION_SIZE);
|
||||
}
|
||||
|
||||
module.exports = dumpReactTree;
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule getReactData
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Convert a react internal instance to a sanitized data object.
|
||||
*
|
||||
* This is shamelessly stolen from react-devtools:
|
||||
* https://github.com/facebook/react-devtools/blob/master/backend/getData.js
|
||||
*/
|
||||
function getData(element: Object): Object {
|
||||
var children = null;
|
||||
var props = null;
|
||||
var state = null;
|
||||
var context = null;
|
||||
var updater = null;
|
||||
var name = null;
|
||||
var type = null;
|
||||
var text = null;
|
||||
var publicInstance = null;
|
||||
var nodeType = 'Native';
|
||||
// If the parent is a native node without rendered children, but with
|
||||
// multiple string children, then the `element` that gets passed in here is
|
||||
// a plain value -- a string or number.
|
||||
if (typeof element !== 'object') {
|
||||
nodeType = 'Text';
|
||||
text = element + '';
|
||||
} else if (element._currentElement === null || element._currentElement === false) {
|
||||
nodeType = 'Empty';
|
||||
} else if (element._renderedComponent) {
|
||||
nodeType = 'NativeWrapper';
|
||||
children = [element._renderedComponent];
|
||||
props = element._instance.props;
|
||||
state = element._instance.state;
|
||||
context = element._instance.context;
|
||||
if (context && Object.keys(context).length === 0) {
|
||||
context = null;
|
||||
}
|
||||
} else if (element._renderedChildren) {
|
||||
children = childrenList(element._renderedChildren);
|
||||
} else if (element._currentElement && element._currentElement.props) {
|
||||
// This is a native node without rendered children -- meaning the children
|
||||
// prop is just a string or (in the case of the <option>) a list of
|
||||
// strings & numbers.
|
||||
children = element._currentElement.props.children;
|
||||
}
|
||||
|
||||
if (!props && element._currentElement && element._currentElement.props) {
|
||||
props = element._currentElement.props;
|
||||
}
|
||||
|
||||
// != used deliberately here to catch undefined and null
|
||||
if (element._currentElement != null) {
|
||||
type = element._currentElement.type;
|
||||
if (typeof type === 'string') {
|
||||
name = type;
|
||||
} else if (element.getName) {
|
||||
nodeType = 'Composite';
|
||||
name = element.getName();
|
||||
// 0.14 top-level wrapper
|
||||
// TODO(jared): The backend should just act as if these don't exist.
|
||||
if (element._renderedComponent && element._currentElement.props === element._renderedComponent._currentElement) {
|
||||
nodeType = 'Wrapper';
|
||||
}
|
||||
if (name === null) {
|
||||
name = 'No display name';
|
||||
}
|
||||
} else if (element._stringText) {
|
||||
nodeType = 'Text';
|
||||
text = element._stringText;
|
||||
} else {
|
||||
name = type.displayName || type.name || 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
if (element._instance) {
|
||||
var inst = element._instance;
|
||||
updater = {
|
||||
setState: inst.setState && inst.setState.bind(inst),
|
||||
forceUpdate: inst.forceUpdate && inst.forceUpdate.bind(inst),
|
||||
setInProps: inst.forceUpdate && setInProps.bind(null, element),
|
||||
setInState: inst.forceUpdate && setInState.bind(null, inst),
|
||||
setInContext: inst.forceUpdate && setInContext.bind(null, inst),
|
||||
};
|
||||
publicInstance = inst;
|
||||
|
||||
// TODO: React ART currently falls in this bucket, but this doesn't
|
||||
// actually make sense and we should clean this up after stabilizing our
|
||||
// API for backends
|
||||
if (inst._renderedChildren) {
|
||||
children = childrenList(inst._renderedChildren);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
nodeType,
|
||||
type,
|
||||
name,
|
||||
props,
|
||||
state,
|
||||
context,
|
||||
children,
|
||||
text,
|
||||
updater,
|
||||
publicInstance,
|
||||
};
|
||||
}
|
||||
|
||||
function setInProps(internalInst, path: Array<string | number>, value: any) {
|
||||
var element = internalInst._currentElement;
|
||||
internalInst._currentElement = {
|
||||
...element,
|
||||
props: copyWithSet(element.props, path, value),
|
||||
};
|
||||
internalInst._instance.forceUpdate();
|
||||
}
|
||||
|
||||
function setInState(inst, path: Array<string | number>, value: any) {
|
||||
setIn(inst.state, path, value);
|
||||
inst.forceUpdate();
|
||||
}
|
||||
|
||||
function setInContext(inst, path: Array<string | number>, value: any) {
|
||||
setIn(inst.context, path, value);
|
||||
inst.forceUpdate();
|
||||
}
|
||||
|
||||
function setIn(obj: Object, path: Array<string | number>, value: any) {
|
||||
var last = path.pop();
|
||||
var parent = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, obj);
|
||||
if (parent) {
|
||||
parent[last] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function childrenList(children) {
|
||||
var res = [];
|
||||
for (var name in children) {
|
||||
res.push(children[name]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function copyWithSetImpl(obj, path, idx, value) {
|
||||
if (idx >= path.length) {
|
||||
return value;
|
||||
}
|
||||
var key = path[idx];
|
||||
var updated = Array.isArray(obj) ? obj.slice() : {...obj};
|
||||
// $FlowFixMe number or string is fine here
|
||||
updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value);
|
||||
return updated;
|
||||
}
|
||||
|
||||
function copyWithSet(obj: Object | Array<any>, path: Array<string | number>, value: any): Object | Array<any> {
|
||||
return copyWithSetImpl(obj, path, 0, value);
|
||||
}
|
||||
|
||||
module.exports = getData;
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import <libkern/OSAtomic.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTUtils.h"
|
||||
@@ -54,13 +53,10 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
ALAssetRepresentation *representation = [asset defaultRepresentation];
|
||||
NSInteger length = (NSInteger)representation.size;
|
||||
|
||||
|
||||
CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(representation.UTI), kUTTagClassMIMEType);
|
||||
|
||||
NSURLResponse *response =
|
||||
[[NSURLResponse alloc] initWithURL:request.URL
|
||||
MIMEType:(__bridge NSString *)(MIMEType)
|
||||
MIMEType:representation.UTI
|
||||
expectedContentLength:length
|
||||
textEncodingName:nil];
|
||||
|
||||
|
||||
@@ -108,15 +108,8 @@ didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
|
||||
BOOL isMovie = [mediaType isEqualToString:(NSString *)kUTTypeMovie];
|
||||
NSString *key = isMovie ? UIImagePickerControllerMediaURL : UIImagePickerControllerReferenceURL;
|
||||
NSURL *imageURL = info[key];
|
||||
UIImage *image = info[UIImagePickerControllerOriginalImage];
|
||||
NSNumber *width = 0;
|
||||
NSNumber *height = 0;
|
||||
if (image) {
|
||||
height = @(image.size.height);
|
||||
width = @(image.size.width);
|
||||
}
|
||||
if (imageURL) {
|
||||
[self _dismissPicker:picker args:@[imageURL.absoluteString, RCTNullIfNil(height), RCTNullIfNil(width)]];
|
||||
[self _dismissPicker:picker args:@[imageURL.absoluteString]];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -127,7 +120,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
|
||||
// WARNING: Using ImageStoreManager may cause a memory leak because the
|
||||
// image isn't automatically removed from store once we're done using it.
|
||||
[_bridge.imageStoreManager storeImage:originalImage withBlock:^(NSString *tempImageTag) {
|
||||
[self _dismissPicker:picker args:tempImageTag ? @[tempImageTag, height, width] : nil];
|
||||
[self _dismissPicker:picker args:tempImageTag ? @[tempImageTag] : nil];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var RCTDatePickerIOSConsts = require('UIManager').RCTDatePicker.Constants;
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var View = require('View');
|
||||
|
||||
@@ -141,8 +142,8 @@ var DatePickerIOS = React.createClass({
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
datePickerIOS: {
|
||||
height: 216,
|
||||
width: 320,
|
||||
height: RCTDatePickerIOSConsts.ComponentHeight,
|
||||
width: RCTDatePickerIOSConsts.ComponentWidth,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ var DrawerLayoutAndroid = React.createClass({
|
||||
* - idle, meaning there is no interaction with the navigation view happening at the time
|
||||
* - dragging, meaning there is currently an interaction with the navigation view
|
||||
* - settling, meaning that there was an interaction with the navigation view, and the
|
||||
* navigation view is now finishing its closing or opening animation
|
||||
* navigation view is now finishing it's closing or opening animation
|
||||
*/
|
||||
onDrawerStateChanged: ReactPropTypes.func,
|
||||
/**
|
||||
|
||||
@@ -351,7 +351,6 @@ const MapView = React.createClass({
|
||||
}
|
||||
var viewIndex = children.length;
|
||||
children.push(React.cloneElement(view, {
|
||||
// $FlowFixMe - An array of styles should be fine
|
||||
style: [styles.annotationView, view.props.style || {}]
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -308,15 +308,6 @@ var NavigatorIOS = React.createClass({
|
||||
*/
|
||||
translucent: PropTypes.bool,
|
||||
|
||||
/**
|
||||
* A Boolean value that indicates whether the interactive pop gesture is enabled. Useful
|
||||
* for enabling/disabling the back swipe navigation gesture. If this prop is not provided,
|
||||
* the default behavior is for the back swipe gesture to be enabled when the navigation bar
|
||||
* is shown and disabled when the navigation bar is hidden. Once you've provided
|
||||
* the interactivePopGestureEnabled prop, you can never restore the default behavior.
|
||||
*/
|
||||
interactivePopGestureEnabled: PropTypes.bool,
|
||||
|
||||
},
|
||||
|
||||
navigator: (undefined: ?Object),
|
||||
@@ -695,8 +686,7 @@ var NavigatorIOS = React.createClass({
|
||||
style={styles.transitioner}
|
||||
vertical={this.props.vertical}
|
||||
requestedTopOfStack={this.state.requestedTopOfStack}
|
||||
onNavigationComplete={this._handleNavigationComplete}
|
||||
interactivePopGestureEnabled={this.props.interactivePopGestureEnabled}>
|
||||
onNavigationComplete={this._handleNavigationComplete}>
|
||||
{items}
|
||||
</NavigatorTransitionerIOS>
|
||||
</StaticContainer>
|
||||
|
||||
@@ -52,11 +52,7 @@ var PickerAndroid = React.createClass({
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
var state = this._stateFromProps(this.props);
|
||||
return {
|
||||
...state,
|
||||
initialSelectedIndex: state.selectedIndex,
|
||||
};
|
||||
return this._stateFromProps(this.props);
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
@@ -91,7 +87,7 @@ var PickerAndroid = React.createClass({
|
||||
mode: this.props.mode,
|
||||
onSelect: this._onChange,
|
||||
prompt: this.props.prompt,
|
||||
selected: this.state.initialSelectedIndex,
|
||||
selected: this.state.selectedIndex,
|
||||
testID: this.props.testID,
|
||||
style: [styles.pickerAndroid, this.props.style],
|
||||
};
|
||||
@@ -109,24 +105,15 @@ var PickerAndroid = React.createClass({
|
||||
this.props.onValueChange(null, position);
|
||||
}
|
||||
}
|
||||
this._lastNativePosition = event.nativeEvent.position;
|
||||
this.forceUpdate();
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this._lastNativePosition = this.state.initialSelectedIndex;
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// The picker is a controlled component. This means we expect the
|
||||
// on*Change handlers to be in charge of updating our
|
||||
// `selectedValue` prop. That way they can also
|
||||
// disallow/undo/mutate the selection of certain values. In other
|
||||
// words, the embedder of this component should be the source of
|
||||
// truth, not the native component.
|
||||
if (this.refs[REF_PICKER] && this.state.selectedIndex !== this._lastNativePosition) {
|
||||
if (this.refs[REF_PICKER] && this.state.selectedIndex !== event.nativeEvent.position) {
|
||||
this.refs[REF_PICKER].setNativeProps({selected: this.state.selectedIndex});
|
||||
this._lastNativePosition = this.state.selectedIndex;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
var Image = require('Image');
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var NativeModules = require('NativeModules');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
@@ -71,7 +72,7 @@ var ProgressViewIOS = React.createClass({
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
progressView: {
|
||||
height: 2,
|
||||
height: NativeModules.ProgressViewManager.ComponentHeight
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const View = require('View');
|
||||
const requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
var RefreshLayoutConsts = require('UIManager').AndroidSwipeRefreshLayout.Constants;
|
||||
var RefreshLayoutConsts = require('NativeModules').UIManager.AndroidSwipeRefreshLayout.Constants;
|
||||
} else {
|
||||
var RefreshLayoutConsts = {SIZE: {}};
|
||||
}
|
||||
@@ -86,7 +86,7 @@ const RefreshControl = React.createClass({
|
||||
/**
|
||||
* Whether the view should be indicating an active refresh.
|
||||
*/
|
||||
refreshing: React.PropTypes.bool.isRequired,
|
||||
refreshing: React.PropTypes.bool,
|
||||
/**
|
||||
* The color of the refresh indicator.
|
||||
* @platform ios
|
||||
@@ -121,32 +121,10 @@ const RefreshControl = React.createClass({
|
||||
* Size of the refresh indicator, see RefreshControl.SIZE.
|
||||
* @platform android
|
||||
*/
|
||||
size: React.PropTypes.oneOf([RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE]),
|
||||
/**
|
||||
* Progress view top offset
|
||||
* @platform android
|
||||
*/
|
||||
progressViewOffset: React.PropTypes.number,
|
||||
size: React.PropTypes.oneOf(RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE),
|
||||
},
|
||||
|
||||
_nativeRef: (null: any),
|
||||
_lastNativeRefreshing: false,
|
||||
|
||||
componentDidMount() {
|
||||
this._lastNativeRefreshing = this.props.refreshing;
|
||||
},
|
||||
|
||||
componentDidUpdate(prevProps: {refreshing: boolean}) {
|
||||
// RefreshControl is a controlled component so if the native refreshing
|
||||
// value doesn't match the current js refreshing prop update it to
|
||||
// the js value.
|
||||
if (this.props.refreshing !== prevProps.refreshing) {
|
||||
this._lastNativeRefreshing = this.props.refreshing;
|
||||
} else if (this.props.refreshing !== this._lastNativeRefreshing) {
|
||||
this._nativeRef.setNativeProps({refreshing: this.props.refreshing});
|
||||
this._lastNativeRefreshing = this.props.refreshing;
|
||||
}
|
||||
},
|
||||
_nativeRef: {},
|
||||
|
||||
render() {
|
||||
return (
|
||||
@@ -159,13 +137,11 @@ const RefreshControl = React.createClass({
|
||||
},
|
||||
|
||||
_onRefresh() {
|
||||
this._lastNativeRefreshing = true;
|
||||
|
||||
this.props.onRefresh && this.props.onRefresh();
|
||||
|
||||
// The native component will start refreshing so force an update to
|
||||
// make sure it stays in sync with the js component.
|
||||
this.forceUpdate();
|
||||
if (this._nativeRef) {
|
||||
this._nativeRef.setNativeProps({refreshing: this.props.refreshing});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
|
||||
var Dimensions = require('Dimensions');
|
||||
var Platform = require('Platform');
|
||||
var Keyboard = require('Keyboard');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var React = require('React');
|
||||
var ReactNative = require('ReactNative');
|
||||
var Subscribable = require('Subscribable');
|
||||
var TextInputState = require('TextInputState');
|
||||
@@ -22,6 +23,9 @@ var UIManager = require('UIManager');
|
||||
var { ScrollViewManager } = require('NativeModules');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
import type ReactComponent from 'ReactComponent';
|
||||
|
||||
/**
|
||||
* Mixin that can be integrated in order to handle scrolling that plays well
|
||||
@@ -476,10 +480,10 @@ var ScrollResponderMixin = {
|
||||
componentWillMount: function() {
|
||||
this.keyboardWillOpenTo = null;
|
||||
this.additionalScrollOffset = 0;
|
||||
this.addListenerOn(Keyboard, 'keyboardWillShow', this.scrollResponderKeyboardWillShow);
|
||||
this.addListenerOn(Keyboard, 'keyboardWillHide', this.scrollResponderKeyboardWillHide);
|
||||
this.addListenerOn(Keyboard, 'keyboardDidShow', this.scrollResponderKeyboardDidShow);
|
||||
this.addListenerOn(Keyboard, 'keyboardDidHide', this.scrollResponderKeyboardDidHide);
|
||||
this.addListenerOn(RCTDeviceEventEmitter, 'keyboardWillShow', this.scrollResponderKeyboardWillShow);
|
||||
this.addListenerOn(RCTDeviceEventEmitter, 'keyboardWillHide', this.scrollResponderKeyboardWillHide);
|
||||
this.addListenerOn(RCTDeviceEventEmitter, 'keyboardDidShow', this.scrollResponderKeyboardDidShow);
|
||||
this.addListenerOn(RCTDeviceEventEmitter, 'keyboardDidHide', this.scrollResponderKeyboardDidHide);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var React = require('React');
|
||||
var ScrollResponder = require('ScrollResponder');
|
||||
var ScrollView = require('ScrollView');
|
||||
|
||||
@@ -11,26 +11,30 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const ColorPropType = require('ColorPropType');
|
||||
const EdgeInsetsPropType = require('EdgeInsetsPropType');
|
||||
const Platform = require('Platform');
|
||||
const PointPropType = require('PointPropType');
|
||||
const RCTScrollViewManager = require('NativeModules').ScrollViewManager;
|
||||
const React = require('React');
|
||||
const ReactNative = require('ReactNative');
|
||||
const ScrollResponder = require('ScrollResponder');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const StyleSheetPropType = require('StyleSheetPropType');
|
||||
const View = require('View');
|
||||
const ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
var ColorPropType = require('ColorPropType');
|
||||
var EdgeInsetsPropType = require('EdgeInsetsPropType');
|
||||
var Platform = require('Platform');
|
||||
var PointPropType = require('PointPropType');
|
||||
var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
|
||||
var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
|
||||
var React = require('React');
|
||||
var ReactNative = require('ReactNative');
|
||||
var ScrollResponder = require('ScrollResponder');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var View = require('View');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
const deprecatedPropType = require('deprecatedPropType');
|
||||
const dismissKeyboard = require('dismissKeyboard');
|
||||
const flattenStyle = require('flattenStyle');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const processDecelerationRate = require('processDecelerationRate');
|
||||
const PropTypes = React.PropTypes;
|
||||
const requireNativeComponent = require('requireNativeComponent');
|
||||
var deprecatedPropType = require('deprecatedPropType');
|
||||
var dismissKeyboard = require('dismissKeyboard');
|
||||
var flattenStyle = require('flattenStyle');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
var processDecelerationRate = require('processDecelerationRate');
|
||||
var PropTypes = React.PropTypes;
|
||||
|
||||
var SCROLLVIEW = 'ScrollView';
|
||||
var INNERVIEW = 'InnerScrollView';
|
||||
|
||||
/**
|
||||
* Component that wraps platform ScrollView while providing
|
||||
@@ -47,7 +51,7 @@ const requireNativeComponent = require('requireNativeComponent');
|
||||
* Doesn't yet support other contained responders from blocking this scroll
|
||||
* view from becoming the responder.
|
||||
*/
|
||||
const ScrollView = React.createClass({
|
||||
var ScrollView = React.createClass({
|
||||
propTypes: {
|
||||
...View.propTypes,
|
||||
/**
|
||||
@@ -59,7 +63,7 @@ const ScrollView = React.createClass({
|
||||
automaticallyAdjustContentInsets: PropTypes.bool,
|
||||
/**
|
||||
* The amount by which the scroll view content is inset from the edges
|
||||
* of the scroll view. Defaults to `{top: 0, left: 0, bottom: 0, right: 0}`.
|
||||
* of the scroll view. Defaults to `{0, 0, 0, 0}`.
|
||||
* @platform ios
|
||||
*/
|
||||
contentInset: EdgeInsetsPropType,
|
||||
@@ -115,7 +119,7 @@ const ScrollView = React.createClass({
|
||||
* </ScrollView>
|
||||
* );
|
||||
* ...
|
||||
* const styles = StyleSheet.create({
|
||||
* var styles = StyleSheet.create({
|
||||
* contentContainer: {
|
||||
* paddingVertical: 20
|
||||
* }
|
||||
@@ -206,11 +210,8 @@ const ScrollView = React.createClass({
|
||||
*/
|
||||
onScrollAnimationEnd: PropTypes.func,
|
||||
/**
|
||||
* Called when scrollable content view of the ScrollView changes.
|
||||
*
|
||||
* Handler function is passed the content width and content height as parameters: `(contentWidth, contentHeight)`
|
||||
*
|
||||
* It's implemented using onLayout handler attached to the content container
|
||||
* Called when scrollable content view of the ScrollView changes. It's
|
||||
* implemented using onLayout handler attached to the content container
|
||||
* which this ScrollView renders.
|
||||
*/
|
||||
onContentSizeChange: PropTypes.func,
|
||||
@@ -218,6 +219,7 @@ const ScrollView = React.createClass({
|
||||
* When true, the scroll view stops on multiples of the scroll view's size
|
||||
* when scrolling. This can be used for horizontal pagination. The default
|
||||
* value is false.
|
||||
* @platform ios
|
||||
*/
|
||||
pagingEnabled: PropTypes.bool,
|
||||
/**
|
||||
@@ -327,15 +329,6 @@ const ScrollView = React.createClass({
|
||||
* @platform android
|
||||
*/
|
||||
endFillColor: ColorPropType,
|
||||
|
||||
/**
|
||||
* Tag used to log scroll performance on this scroll view. Will force
|
||||
* momentum events to be turned on (see sendMomentumEvents). This doesn't do
|
||||
* anything out of the box and you need to implement a custom native
|
||||
* FpsListener for it to be useful.
|
||||
* @platform android
|
||||
*/
|
||||
scrollPerfTag: PropTypes.string,
|
||||
},
|
||||
|
||||
mixins: [ScrollResponder.Mixin],
|
||||
@@ -345,7 +338,7 @@ const ScrollView = React.createClass({
|
||||
},
|
||||
|
||||
setNativeProps: function(props: Object) {
|
||||
this._scrollViewRef && this._scrollViewRef.setNativeProps(props);
|
||||
this.refs[SCROLLVIEW].setNativeProps(props);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -363,16 +356,16 @@ const ScrollView = React.createClass({
|
||||
* implement this method so that they can be composed while providing access
|
||||
* to the underlying scroll responder's methods.
|
||||
*/
|
||||
getScrollResponder: function(): ScrollView {
|
||||
getScrollResponder: function(): ReactComponent {
|
||||
return this;
|
||||
},
|
||||
|
||||
getScrollableNode: function(): any {
|
||||
return ReactNative.findNodeHandle(this._scrollViewRef);
|
||||
return ReactNative.findNodeHandle(this.refs[SCROLLVIEW]);
|
||||
},
|
||||
|
||||
getInnerViewNode: function(): any {
|
||||
return ReactNative.findNodeHandle(this._innerViewRef);
|
||||
return ReactNative.findNodeHandle(this.refs[INNERVIEW]);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -396,6 +389,7 @@ const ScrollView = React.createClass({
|
||||
} else {
|
||||
({x, y, animated} = y || {});
|
||||
}
|
||||
// $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
|
||||
this.getScrollResponder().scrollResponderScrollTo({x: x || 0, y: y || 0, animated: animated !== false});
|
||||
},
|
||||
|
||||
@@ -410,7 +404,7 @@ const ScrollView = React.createClass({
|
||||
_handleScroll: function(e: Object) {
|
||||
if (__DEV__) {
|
||||
if (this.props.onScroll && !this.props.scrollEventThrottle && Platform.OS === 'ios') {
|
||||
console.log( // eslint-disable-line no-console-disallow
|
||||
console.log(
|
||||
'You specified `onScroll` on a <ScrollView> but not ' +
|
||||
'`scrollEventThrottle`. You will only receive one event. ' +
|
||||
'Using `16` you get all the events but be aware that it may ' +
|
||||
@@ -428,29 +422,18 @@ const ScrollView = React.createClass({
|
||||
},
|
||||
|
||||
_handleContentOnLayout: function(e: Object) {
|
||||
const {width, height} = e.nativeEvent.layout;
|
||||
var {width, height} = e.nativeEvent.layout;
|
||||
this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
|
||||
},
|
||||
|
||||
_scrollViewRef: (null: ?ScrollView),
|
||||
_setScrollViewRef: function(ref: ?ScrollView) {
|
||||
this._scrollViewRef = ref;
|
||||
},
|
||||
|
||||
_innerViewRef: (null: ?View),
|
||||
_setInnerViewRef: function(ref: ?View) {
|
||||
this._innerViewRef = ref;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const contentContainerStyle = [
|
||||
var contentContainerStyle = [
|
||||
this.props.horizontal && styles.contentContainerHorizontal,
|
||||
this.props.contentContainerStyle,
|
||||
];
|
||||
let style, childLayoutProps;
|
||||
if (__DEV__ && this.props.style) {
|
||||
style = flattenStyle(this.props.style);
|
||||
childLayoutProps = ['alignItems', 'justifyContent']
|
||||
var style = flattenStyle(this.props.style);
|
||||
var childLayoutProps = ['alignItems', 'justifyContent']
|
||||
.filter((prop) => style && style[prop] !== undefined);
|
||||
invariant(
|
||||
childLayoutProps.length === 0,
|
||||
@@ -459,34 +442,34 @@ const ScrollView = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
let contentSizeChangeProps = {};
|
||||
var contentSizeChangeProps = {};
|
||||
if (this.props.onContentSizeChange) {
|
||||
contentSizeChangeProps = {
|
||||
onLayout: this._handleContentOnLayout,
|
||||
};
|
||||
}
|
||||
|
||||
const contentContainer =
|
||||
var contentContainer =
|
||||
<View
|
||||
{...contentSizeChangeProps}
|
||||
ref={this._setInnerViewRef}
|
||||
ref={INNERVIEW}
|
||||
style={contentContainerStyle}
|
||||
removeClippedSubviews={this.props.removeClippedSubviews}
|
||||
collapsable={false}>
|
||||
{this.props.children}
|
||||
</View>;
|
||||
|
||||
const alwaysBounceHorizontal =
|
||||
var alwaysBounceHorizontal =
|
||||
this.props.alwaysBounceHorizontal !== undefined ?
|
||||
this.props.alwaysBounceHorizontal :
|
||||
this.props.horizontal;
|
||||
|
||||
const alwaysBounceVertical =
|
||||
var alwaysBounceVertical =
|
||||
this.props.alwaysBounceVertical !== undefined ?
|
||||
this.props.alwaysBounceVertical :
|
||||
!this.props.horizontal;
|
||||
|
||||
const props = {
|
||||
var props = {
|
||||
...this.props,
|
||||
alwaysBounceHorizontal,
|
||||
alwaysBounceVertical,
|
||||
@@ -510,7 +493,7 @@ const ScrollView = React.createClass({
|
||||
sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ? true : false,
|
||||
};
|
||||
|
||||
const onRefreshStart = this.props.onRefreshStart;
|
||||
var onRefreshStart = this.props.onRefreshStart;
|
||||
if (onRefreshStart) {
|
||||
// this is necessary because if we set it on props, even when empty,
|
||||
// it'll trigger the default pull-to-refresh behavior on native.
|
||||
@@ -518,12 +501,12 @@ const ScrollView = React.createClass({
|
||||
function() { onRefreshStart && onRefreshStart(this.endRefreshing); }.bind(this);
|
||||
}
|
||||
|
||||
const { decelerationRate } = this.props;
|
||||
var { decelerationRate } = this.props;
|
||||
if (decelerationRate) {
|
||||
props.decelerationRate = processDecelerationRate(decelerationRate);
|
||||
}
|
||||
|
||||
let ScrollViewClass;
|
||||
var ScrollViewClass;
|
||||
if (Platform.OS === 'ios') {
|
||||
ScrollViewClass = RCTScrollView;
|
||||
} else if (Platform.OS === 'android') {
|
||||
@@ -538,12 +521,12 @@ const ScrollView = React.createClass({
|
||||
'ScrollViewClass must not be undefined'
|
||||
);
|
||||
|
||||
const refreshControl = this.props.refreshControl;
|
||||
var refreshControl = this.props.refreshControl;
|
||||
if (refreshControl) {
|
||||
if (Platform.OS === 'ios') {
|
||||
// On iOS the RefreshControl is a child of the ScrollView.
|
||||
return (
|
||||
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
|
||||
<ScrollViewClass {...props} ref={SCROLLVIEW}>
|
||||
{refreshControl}
|
||||
{contentContainer}
|
||||
</ScrollViewClass>
|
||||
@@ -555,21 +538,21 @@ const ScrollView = React.createClass({
|
||||
return React.cloneElement(
|
||||
refreshControl,
|
||||
{style: props.style},
|
||||
<ScrollViewClass {...props} style={styles.base} ref={this._setScrollViewRef}>
|
||||
<ScrollViewClass {...props} style={styles.base} ref={SCROLLVIEW}>
|
||||
{contentContainer}
|
||||
</ScrollViewClass>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
|
||||
<ScrollViewClass {...props} ref={SCROLLVIEW}>
|
||||
{contentContainer}
|
||||
</ScrollViewClass>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
var styles = StyleSheet.create({
|
||||
base: {
|
||||
flex: 1,
|
||||
},
|
||||
@@ -579,29 +562,16 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
let nativeOnlyProps, AndroidScrollView, AndroidHorizontalScrollView, RCTScrollView;
|
||||
if (Platform.OS === 'android') {
|
||||
nativeOnlyProps = {
|
||||
nativeOnly: {
|
||||
sendMomentumEvents: true,
|
||||
}
|
||||
};
|
||||
AndroidScrollView = requireNativeComponent('RCTScrollView', ScrollView, nativeOnlyProps);
|
||||
AndroidHorizontalScrollView = requireNativeComponent(
|
||||
var nativeOnlyProps = { nativeOnly : { 'sendMomentumEvents' : true } };
|
||||
var AndroidScrollView = requireNativeComponent('RCTScrollView', ScrollView, nativeOnlyProps);
|
||||
var AndroidHorizontalScrollView = requireNativeComponent(
|
||||
'AndroidHorizontalScrollView',
|
||||
ScrollView,
|
||||
nativeOnlyProps
|
||||
);
|
||||
} else if (Platform.OS === 'ios') {
|
||||
nativeOnlyProps = {
|
||||
nativeOnly: {
|
||||
onMomentumScrollBegin: true,
|
||||
onMomentumScrollEnd : true,
|
||||
onScrollBeginDrag: true,
|
||||
onScrollEndDrag: true,
|
||||
}
|
||||
};
|
||||
RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView, nativeOnlyProps);
|
||||
var RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
|
||||
}
|
||||
|
||||
module.exports = ScrollView;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var NativeModules = require('NativeModules');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
@@ -119,7 +120,7 @@ var SegmentedControlIOS = React.createClass({
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
segmentedControl: {
|
||||
height: 28,
|
||||
height: NativeModules.SegmentedControlManager.ComponentHeight
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -11,6 +11,4 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeEventEmitter = require('NativeEventEmitter');
|
||||
|
||||
module.exports = new NativeEventEmitter('StatusBarManager');
|
||||
module.exports = null;
|
||||
|
||||
@@ -11,26 +11,24 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeEventEmitter = require('NativeEventEmitter');
|
||||
const StatusBar = require('StatusBar');
|
||||
const StatusBarManager = require('NativeModules').StatusBarManager;
|
||||
|
||||
import type {StatusBarStyle, StatusBarAnimation} from 'StatusBar';
|
||||
|
||||
/**
|
||||
* Deprecated. Use `StatusBar` instead.
|
||||
*/
|
||||
class StatusBarIOS extends NativeEventEmitter {
|
||||
const StatusBarIOS = {
|
||||
|
||||
setStyle(style: StatusBarStyle, animated?: boolean) {
|
||||
console.warn('`StatusBarIOS.setStyle` is deprecated. Use `StatusBar.setBarStyle` instead.');
|
||||
StatusBar.setBarStyle(style, animated);
|
||||
}
|
||||
},
|
||||
|
||||
setHidden(hidden: boolean, animation?: StatusBarAnimation) {
|
||||
console.warn('`StatusBarIOS.setHidden` is deprecated. Use `StatusBar.setHidden` instead.');
|
||||
StatusBar.setHidden(hidden, animation);
|
||||
}
|
||||
},
|
||||
|
||||
setNetworkActivityIndicatorVisible(visible: boolean) {
|
||||
console.warn(
|
||||
@@ -38,7 +36,7 @@ class StatusBarIOS extends NativeEventEmitter {
|
||||
'Use `StatusBar.setNetworkActivityIndicatorVisible` instead.'
|
||||
);
|
||||
StatusBar.setNetworkActivityIndicatorVisible(visible);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = new StatusBarIOS(StatusBarManager);
|
||||
module.exports = StatusBarIOS;
|
||||
|
||||
@@ -27,10 +27,6 @@ var TabBarIOS = React.createClass({
|
||||
propTypes: {
|
||||
...View.propTypes,
|
||||
style: View.propTypes.style,
|
||||
/**
|
||||
* Color of text on unselected tabs
|
||||
*/
|
||||
unselectedTintColor: ColorPropType,
|
||||
/**
|
||||
* Color of the currently selected tab icon
|
||||
*/
|
||||
@@ -49,7 +45,6 @@ var TabBarIOS = React.createClass({
|
||||
return (
|
||||
<RCTTabBar
|
||||
style={[styles.tabGroup, this.props.style]}
|
||||
unselectedTintColor={this.props.unselectedTintColor}
|
||||
tintColor={this.props.tintColor}
|
||||
barTintColor={this.props.barTintColor}
|
||||
translucent={this.props.translucent !== false}>
|
||||
|
||||
@@ -62,11 +62,6 @@ var TabBarItemIOS = React.createClass({
|
||||
* component to set selected={true}.
|
||||
*/
|
||||
onPress: React.PropTypes.func,
|
||||
/**
|
||||
* If set to true it renders the image as original,
|
||||
* it defaults to being displayed as a template
|
||||
*/
|
||||
renderAsOriginal: React.PropTypes.bool,
|
||||
/**
|
||||
* It specifies whether the children are visible or not. If you see a
|
||||
* blank content, you probably forgot to add a selected one.
|
||||
|
||||
@@ -120,7 +120,6 @@ var TextInput = React.createClass({
|
||||
* Determines which keyboard to open, e.g.`numeric`.
|
||||
*
|
||||
* The following values work across platforms:
|
||||
*
|
||||
* - default
|
||||
* - numeric
|
||||
* - email-address
|
||||
@@ -151,54 +150,22 @@ var TextInput = React.createClass({
|
||||
'dark',
|
||||
]),
|
||||
/**
|
||||
* Determines how the return key should look. On Android you can also use
|
||||
* `returnKeyLabel`.
|
||||
*
|
||||
* The following values work across platforms:
|
||||
*
|
||||
* - done
|
||||
* - go
|
||||
* - next
|
||||
* - search
|
||||
* - send
|
||||
*
|
||||
* The following values work on Android only:
|
||||
*
|
||||
* - none
|
||||
* - previous
|
||||
*
|
||||
* The following values work on iOS only:
|
||||
*
|
||||
* - default
|
||||
* - emergency-call
|
||||
* - google
|
||||
* - join
|
||||
* - route
|
||||
* - yahoo
|
||||
* Determines how the return key should look.
|
||||
* @platform ios
|
||||
*/
|
||||
returnKeyType: PropTypes.oneOf([
|
||||
// Cross-platform
|
||||
'done',
|
||||
'go',
|
||||
'next',
|
||||
'search',
|
||||
'send',
|
||||
// Android-only
|
||||
'none',
|
||||
'previous',
|
||||
// iOS-only
|
||||
'default',
|
||||
'emergency-call',
|
||||
'go',
|
||||
'google',
|
||||
'join',
|
||||
'next',
|
||||
'route',
|
||||
'search',
|
||||
'send',
|
||||
'yahoo',
|
||||
'done',
|
||||
'emergency-call',
|
||||
]),
|
||||
/**
|
||||
* Sets the return key to the label. Use it instead of `returnKeyType`.
|
||||
* @platform android
|
||||
*/
|
||||
returnKeyLabel: PropTypes.string,
|
||||
/**
|
||||
* Limits the maximum number of characters that can be entered. Use this
|
||||
* instead of implementing the logic in JS to avoid flicker.
|
||||
@@ -476,8 +443,8 @@ var TextInput = React.createClass({
|
||||
!(props.value && childCount),
|
||||
'Cannot specify both value and children.'
|
||||
);
|
||||
if (childCount >= 1) {
|
||||
children = <Text style={props.style}>{children}</Text>;
|
||||
if (childCount > 1) {
|
||||
children = <Text>{children}</Text>;
|
||||
}
|
||||
if (props.inputView) {
|
||||
children = [children, props.inputView];
|
||||
@@ -564,8 +531,6 @@ var TextInput = React.createClass({
|
||||
children={children}
|
||||
editable={this.props.editable}
|
||||
selectTextOnFocus={this.props.selectTextOnFocus}
|
||||
returnKeyType={this.props.returnKeyType}
|
||||
returnKeyLabel={this.props.returnKeyLabel}
|
||||
/>;
|
||||
|
||||
return (
|
||||
|
||||
@@ -360,10 +360,10 @@ var TouchableMixin = {
|
||||
/**
|
||||
* Place as callback for a DOM element's `onResponderGrant` event.
|
||||
* @param {SyntheticEvent} e Synthetic event from event system.
|
||||
* @param {string} dispatchID ID of node that e was dispatched to.
|
||||
*
|
||||
*/
|
||||
touchableHandleResponderGrant: function(e) {
|
||||
var dispatchID = e.currentTarget;
|
||||
touchableHandleResponderGrant: function(e, dispatchID) {
|
||||
// Since e is used in a callback invoked on another event loop
|
||||
// (as in setTimeout etc), we need to call e.persist() on the
|
||||
// event to make sure it doesn't get reused in the event object pool.
|
||||
@@ -756,5 +756,8 @@ var Touchable = {
|
||||
);
|
||||
}
|
||||
};
|
||||
if (Touchable.TOUCH_TARGET_DEBUG) {
|
||||
console.warn('Touchable.TOUCH_TARGET_DEBUG is enabled');
|
||||
}
|
||||
|
||||
module.exports = Touchable;
|
||||
|
||||
@@ -55,7 +55,7 @@ var TouchableOpacity = React.createClass({
|
||||
...TouchableWithoutFeedback.propTypes,
|
||||
/**
|
||||
* Determines what the opacity of the wrapped view should be when touch is
|
||||
* active. Defaults to 0.2.
|
||||
* active.
|
||||
*/
|
||||
activeOpacity: React.PropTypes.number,
|
||||
},
|
||||
|
||||
@@ -123,12 +123,6 @@ var ViewPagerAndroid = React.createClass({
|
||||
'none', // default
|
||||
'on-drag',
|
||||
]),
|
||||
|
||||
/**
|
||||
* When false, the content does not scroll.
|
||||
* The default value is true.
|
||||
*/
|
||||
scrollEnabled: ReactPropTypes.bool,
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
@@ -207,7 +201,7 @@ var ViewPagerAndroid = React.createClass({
|
||||
|
||||
/**
|
||||
* A helper function to scroll to a specific page in the ViewPager.
|
||||
* The transition between pages will *not* be animated.
|
||||
* The transition between pages will be *not* be animated.
|
||||
*/
|
||||
setPageWithoutAnimation: function(selectedPage: number) {
|
||||
UIManager.dispatchViewManagerCommand(
|
||||
|
||||
@@ -264,14 +264,6 @@ var WebView = React.createClass({
|
||||
);
|
||||
},
|
||||
|
||||
stopLoading: function() {
|
||||
UIManager.dispatchViewManagerCommand(
|
||||
this.getWebViewHandle(),
|
||||
UIManager.RCTWebView.Commands.stopLoading,
|
||||
null
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* We return an event with a bunch of fields including:
|
||||
* url, title, loading, canGoBack, canGoForward
|
||||
|
||||
@@ -362,14 +362,6 @@ var WebView = React.createClass({
|
||||
);
|
||||
},
|
||||
|
||||
stopLoading: function() {
|
||||
UIManager.dispatchViewManagerCommand(
|
||||
this.getWebViewHandle(),
|
||||
UIManager.RCTWebView.Commands.stopLoading,
|
||||
null
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* We return an event with a bunch of fields including:
|
||||
* url, title, loading, canGoBack, canGoForward
|
||||
|
||||
@@ -56,10 +56,10 @@ var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
||||
/**
|
||||
* ListView - A core component designed for efficient display of vertically
|
||||
* scrolling lists of changing data. The minimal API is to create a
|
||||
* [`ListView.DataSource`](docs/listviewdatasource.html), populate it with a simple
|
||||
* array of data blobs, and instantiate a `ListView` component with that data
|
||||
* source and a `renderRow` callback which takes a blob from the data array and
|
||||
* returns a renderable component.
|
||||
* `ListView.DataSource`, populate it with a simple array of data blobs, and
|
||||
* instantiate a `ListView` component with that data source and a `renderRow`
|
||||
* callback which takes a blob from the data array and returns a renderable
|
||||
* component.
|
||||
*
|
||||
* Minimal example:
|
||||
*
|
||||
@@ -117,9 +117,7 @@ var ListView = React.createClass({
|
||||
*/
|
||||
propTypes: {
|
||||
...ScrollView.propTypes,
|
||||
/**
|
||||
* An instance of [ListView.DataSource](docs/listviewdatasource.html) to use
|
||||
*/
|
||||
|
||||
dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
|
||||
/**
|
||||
* (sectionID, rowID, adjacentRowHighlighted) => renderable
|
||||
@@ -137,10 +135,9 @@ var ListView = React.createClass({
|
||||
* a renderable component to be rendered as the row. By default the data
|
||||
* is exactly what was put into the data source, but it's also possible to
|
||||
* provide custom extractors. ListView can be notified when a row is
|
||||
* being highlighted by calling `highlightRow(sectionID, rowID)`. This
|
||||
* sets a boolean value of adjacentRowHighlighted in renderSeparator, allowing you
|
||||
* to control the separators above and below the highlighted row. The highlighted
|
||||
* state of a row can be reset by calling highlightRow(null).
|
||||
* being highlighted by calling highlightRow function. The separators above and
|
||||
* below will be hidden when a row is highlighted. The highlighted state of
|
||||
* a row can be reset by calling highlightRow(null).
|
||||
*/
|
||||
renderRow: PropTypes.func.isRequired,
|
||||
/**
|
||||
@@ -596,19 +593,12 @@ var ListView = React.createClass({
|
||||
var rowID = rowIDs[rowIdx];
|
||||
var frame = this._childFrames[totalIndex];
|
||||
totalIndex++;
|
||||
if(this.props.renderSeparator &&
|
||||
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)){
|
||||
totalIndex++;
|
||||
}
|
||||
if (!frame) {
|
||||
break;
|
||||
}
|
||||
var rowVisible = visibleSection[rowID];
|
||||
var min = isVertical ? frame.y : frame.x;
|
||||
var max = min + (isVertical ? frame.height : frame.width);
|
||||
if ((!min && !max) || (min === max)) {
|
||||
break;
|
||||
}
|
||||
if (min > visibleMax || max < visibleMin) {
|
||||
if (rowVisible) {
|
||||
visibilityChanged = true;
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
const Animated = require('Animated');
|
||||
const NavigationCardStackPanResponder = require('NavigationCardStackPanResponder');
|
||||
const NavigationCardStackStyleInterpolator = require('NavigationCardStackStyleInterpolator');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationPagerPanResponder = require('NavigationPagerPanResponder');
|
||||
const NavigationPagerStyleInterpolator = require('NavigationPagerStyleInterpolator');
|
||||
const NavigationPointerEventsContainer = require('NavigationPointerEventsContainer');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const React = require('React');
|
||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
@@ -50,40 +50,20 @@ import type {
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type SceneViewProps = {
|
||||
sceneRenderer: NavigationSceneRenderer,
|
||||
sceneRendererProps: NavigationSceneRendererProps,
|
||||
};
|
||||
|
||||
type Props = NavigationSceneRendererProps & {
|
||||
onComponentRef: (ref: any) => void,
|
||||
panHandlers: ?NavigationPanPanHandlers,
|
||||
pointerEvents: string,
|
||||
renderScene: NavigationSceneRenderer,
|
||||
style: any,
|
||||
panHandlers: ?NavigationPanPanHandlers,
|
||||
renderScene: NavigationSceneRenderer,
|
||||
};
|
||||
|
||||
const {PropTypes} = React;
|
||||
|
||||
class SceneView extends React.Component<any, SceneViewProps, any> {
|
||||
|
||||
static propTypes = {
|
||||
sceneRenderer: PropTypes.func.isRequired,
|
||||
sceneRendererProps:
|
||||
PropTypes.shape(NavigationPropTypes.SceneRenderer).isRequired,
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: SceneViewProps, nextState: any): boolean {
|
||||
return (
|
||||
nextProps.sceneRendererProps.scene.navigationState !==
|
||||
this.props.sceneRendererProps.scene.navigationState
|
||||
);
|
||||
}
|
||||
|
||||
render(): ?ReactElement {
|
||||
return this.props.sceneRenderer(this.props.sceneRendererProps);
|
||||
}
|
||||
}
|
||||
const propTypes = {
|
||||
...NavigationPropTypes.SceneRenderer,
|
||||
style: PropTypes.any,
|
||||
panHandlers: NavigationPropTypes.panHandlers,
|
||||
renderScene: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
* Component that renders the scene as card for the <NavigationCardStack />.
|
||||
@@ -91,15 +71,6 @@ class SceneView extends React.Component<any, SceneViewProps, any> {
|
||||
class NavigationCard extends React.Component<any, Props, any> {
|
||||
props: Props;
|
||||
|
||||
static propTypes = {
|
||||
...NavigationPropTypes.SceneRendererProps,
|
||||
onComponentRef: PropTypes.func.isRequired,
|
||||
panHandlers: NavigationPropTypes.panHandlers,
|
||||
pointerEvents: PropTypes.string.isRequired,
|
||||
renderScene: PropTypes.func.isRequired,
|
||||
style: PropTypes.any,
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: Props, nextState: any): boolean {
|
||||
return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
|
||||
this,
|
||||
@@ -111,40 +82,50 @@ class NavigationCard extends React.Component<any, Props, any> {
|
||||
render(): ReactElement {
|
||||
const {
|
||||
panHandlers,
|
||||
pointerEvents,
|
||||
renderScene,
|
||||
style,
|
||||
...props, /* NavigationSceneRendererProps */
|
||||
} = this.props;
|
||||
|
||||
const viewStyle = style === undefined ?
|
||||
NavigationCardStackStyleInterpolator.forHorizontal(props) :
|
||||
style;
|
||||
let viewStyle = null;
|
||||
if (style === undefined) {
|
||||
// fall back to default style.
|
||||
viewStyle = NavigationCardStackStyleInterpolator.forHorizontal(props);
|
||||
} else {
|
||||
viewStyle = style;
|
||||
}
|
||||
|
||||
const viewPanHandlers = panHandlers === undefined ?
|
||||
NavigationCardStackPanResponder.forHorizontal(props) :
|
||||
panHandlers;
|
||||
const {
|
||||
navigationState,
|
||||
scene,
|
||||
} = props;
|
||||
|
||||
const interactive = navigationState.index === scene.index && !scene.isStale;
|
||||
const pointerEvents = interactive ? 'auto' : 'none';
|
||||
|
||||
let viewPanHandlers = null;
|
||||
if (interactive) {
|
||||
if (panHandlers === undefined) {
|
||||
// fall back to default pan handlers.
|
||||
viewPanHandlers = NavigationCardStackPanResponder.forHorizontal(props);
|
||||
} else {
|
||||
viewPanHandlers = panHandlers;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
{...viewPanHandlers}
|
||||
pointerEvents={pointerEvents}
|
||||
ref={this.props.onComponentRef}
|
||||
style={[styles.main, viewStyle]}>
|
||||
<SceneView
|
||||
sceneRenderer={renderScene}
|
||||
sceneRendererProps={props}
|
||||
/>
|
||||
{renderScene(props)}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
static CardStackPanResponder = NavigationCardStackPanResponder;
|
||||
static CardStackStyleInterpolator = NavigationCardStackStyleInterpolator;
|
||||
static PagerPanResponder = NavigationPagerPanResponder;
|
||||
static PagerStyleInterpolator = NavigationPagerStyleInterpolator;
|
||||
}
|
||||
|
||||
NavigationCard.propTypes = propTypes;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
main: {
|
||||
backgroundColor: '#E9E9EF',
|
||||
@@ -160,6 +141,13 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
NavigationCard = NavigationPointerEventsContainer.create(NavigationCard);
|
||||
|
||||
module.exports = NavigationCard;
|
||||
const NavigationCardContainer = NavigationContainer.create(NavigationCard);
|
||||
|
||||
// Export these buil-in interaction modules.
|
||||
NavigationCardContainer.CardStackPanResponder = NavigationCardStackPanResponder;
|
||||
NavigationCardContainer.CardStackStyleInterpolator = NavigationCardStackStyleInterpolator;
|
||||
NavigationCardContainer.PagerPanResponder = NavigationPagerPanResponder;
|
||||
NavigationCardContainer.PagerStyleInterpolator = NavigationPagerStyleInterpolator;
|
||||
|
||||
module.exports = NavigationCardContainer;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
const NavigationAnimatedView = require('NavigationAnimatedView');
|
||||
const NavigationCard = require('NavigationCard');
|
||||
const NavigationCardStackStyleInterpolator = require('NavigationCardStackStyleInterpolator');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationCardStackPanResponder = require('NavigationCardStackPanResponder');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const React = require('React');
|
||||
@@ -47,7 +48,6 @@ const {PropTypes} = React;
|
||||
const {Directions} = NavigationCardStackPanResponder;
|
||||
|
||||
import type {
|
||||
NavigationActionCaller,
|
||||
NavigationParentState,
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
@@ -60,16 +60,10 @@ import type {
|
||||
type Props = {
|
||||
direction: NavigationGestureDirection,
|
||||
navigationState: NavigationParentState,
|
||||
onNavigate: NavigationActionCaller,
|
||||
renderOverlay: ?NavigationSceneRenderer,
|
||||
renderScene: NavigationSceneRenderer,
|
||||
};
|
||||
|
||||
type DefaultProps = {
|
||||
direction: NavigationGestureDirection,
|
||||
renderOverlay: ?NavigationSceneRenderer,
|
||||
};
|
||||
|
||||
/**
|
||||
* A controlled navigation view that renders a stack of cards.
|
||||
*
|
||||
@@ -84,18 +78,17 @@ type DefaultProps = {
|
||||
* +-+ |
|
||||
* +------------+
|
||||
*/
|
||||
class NavigationCardStack extends React.Component<DefaultProps, Props, void> {
|
||||
class NavigationCardStack extends React.Component {
|
||||
_renderScene : NavigationSceneRenderer;
|
||||
|
||||
static propTypes = {
|
||||
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
|
||||
navigationState: NavigationPropTypes.navigationParentState.isRequired,
|
||||
onNavigate: NavigationPropTypes.SceneRendererProps.onNavigate,
|
||||
renderOverlay: PropTypes.func,
|
||||
renderScene: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps: DefaultProps = {
|
||||
static defaultProps = {
|
||||
direction: Directions.HORIZONTAL,
|
||||
renderOverlay: emptyFunction.thatReturnsNull,
|
||||
};
|
||||
@@ -108,7 +101,7 @@ class NavigationCardStack extends React.Component<DefaultProps, Props, void> {
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: Object, nextState: void): boolean {
|
||||
shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
|
||||
return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
|
||||
this,
|
||||
nextProps,
|
||||
@@ -122,8 +115,6 @@ class NavigationCardStack extends React.Component<DefaultProps, Props, void> {
|
||||
navigationState={this.props.navigationState}
|
||||
renderOverlay={this.props.renderOverlay}
|
||||
renderScene={this._renderScene}
|
||||
onNavigate={this.props.onNavigate}
|
||||
// $FlowFixMe - style should be declared
|
||||
style={[styles.animatedView, this.props.style]}
|
||||
/>
|
||||
);
|
||||
@@ -158,4 +149,4 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = NavigationCardStack;
|
||||
module.exports = NavigationContainer.create(NavigationCardStack);
|
||||
|
||||
-30
@@ -51,28 +51,6 @@ import type {
|
||||
* +------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
* Render the initial style when the initial layout isn't measured yet.
|
||||
*/
|
||||
function forInitial(props: NavigationSceneRendererProps): Object {
|
||||
const {
|
||||
navigationState,
|
||||
scene,
|
||||
} = props;
|
||||
|
||||
const focused = navigationState.index === scene.index;
|
||||
const opacity = focused ? 1 : 0;
|
||||
// If not focused, move the scene to the far away.
|
||||
const translate = focused ? 0 : 1000000;
|
||||
return {
|
||||
opacity,
|
||||
transform: [
|
||||
{ translateX: translate },
|
||||
{ translateY: translate },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function forHorizontal(props: NavigationSceneRendererProps): Object {
|
||||
const {
|
||||
layout,
|
||||
@@ -80,10 +58,6 @@ function forHorizontal(props: NavigationSceneRendererProps): Object {
|
||||
scene,
|
||||
} = props;
|
||||
|
||||
if (!layout.isMeasured) {
|
||||
return forInitial(props);
|
||||
}
|
||||
|
||||
const index = scene.index;
|
||||
const inputRange = [index - 1, index, index + 1];
|
||||
const width = layout.initWidth;
|
||||
@@ -121,10 +95,6 @@ function forVertical(props: NavigationSceneRendererProps): Object {
|
||||
scene,
|
||||
} = props;
|
||||
|
||||
if (!layout.isMeasured) {
|
||||
return forInitial(props);
|
||||
}
|
||||
|
||||
const index = scene.index;
|
||||
const inputRange = [index - 1, index, index + 1];
|
||||
const height = layout.initHeight;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
const React = require('React');
|
||||
const ReactNative = require('react-native');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationHeaderTitle = require('NavigationHeaderTitle');
|
||||
const NavigationHeaderBackButton = require('NavigationHeaderBackButton');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
@@ -48,7 +49,6 @@ const {
|
||||
} = ReactNative;
|
||||
|
||||
import type {
|
||||
NavigationActionCaller,
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
NavigationStyleInterpolator,
|
||||
@@ -64,9 +64,8 @@ type Props = NavigationSceneRendererProps & {
|
||||
renderLeftComponent: NavigationSceneRenderer,
|
||||
renderRightComponent: NavigationSceneRenderer,
|
||||
renderTitleComponent: NavigationSceneRenderer,
|
||||
onNavigate: NavigationActionCaller,
|
||||
style?: any,
|
||||
viewProps?: any,
|
||||
style?: any;
|
||||
viewProps?: any;
|
||||
};
|
||||
|
||||
type SubViewName = 'left' | 'title' | 'right';
|
||||
@@ -87,14 +86,7 @@ class NavigationHeader extends React.Component<DefaultProps, Props, any> {
|
||||
},
|
||||
|
||||
renderLeftComponent: (props: NavigationSceneRendererProps) => {
|
||||
if (props.scene.index === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<NavigationHeaderBackButton
|
||||
onNavigate={props.onNavigate}
|
||||
/>
|
||||
);
|
||||
return props.scene.index > 0 ? <NavigationHeaderBackButton /> : null;
|
||||
},
|
||||
|
||||
renderRightComponent: (props: NavigationSceneRendererProps) => {
|
||||
@@ -103,7 +95,7 @@ class NavigationHeader extends React.Component<DefaultProps, Props, any> {
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
...NavigationPropTypes.SceneRendererProps,
|
||||
...NavigationPropTypes.SceneRenderer,
|
||||
renderLeftComponent: PropTypes.func,
|
||||
renderRightComponent: PropTypes.func,
|
||||
renderTitleComponent: PropTypes.func,
|
||||
@@ -207,11 +199,6 @@ class NavigationHeader extends React.Component<DefaultProps, Props, any> {
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
static HEIGHT = APPBAR_HEIGHT + STATUSBAR_HEIGHT;
|
||||
static Title = NavigationHeaderTitle;
|
||||
static BackButton = NavigationHeaderBackButton;
|
||||
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -257,4 +244,10 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
NavigationHeader = NavigationContainer.create(NavigationHeader);
|
||||
|
||||
NavigationHeader.HEIGHT = APPBAR_HEIGHT + STATUSBAR_HEIGHT;
|
||||
NavigationHeader.Title = NavigationHeaderTitle;
|
||||
NavigationHeader.BackButton = NavigationHeaderBackButton;
|
||||
|
||||
module.exports = NavigationHeader;
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
@@ -25,6 +18,8 @@
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationRootContainer = require('NavigationRootContainer');
|
||||
|
||||
const {
|
||||
Image,
|
||||
@@ -38,7 +33,7 @@ type Props = {
|
||||
}
|
||||
|
||||
const NavigationHeaderBackButton = (props: Props) => (
|
||||
<TouchableOpacity style={styles.buttonContainer} onPress={() => props.onNavigate({type: 'BackAction'})}>
|
||||
<TouchableOpacity style={styles.buttonContainer} onPress={() => props.onNavigate(NavigationRootContainer.getBackAction())}>
|
||||
<Image style={styles.button} source={require('./assets/back-icon.png')} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
@@ -62,4 +57,4 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = NavigationHeaderBackButton;
|
||||
module.exports = NavigationContainer.create(NavigationHeaderBackButton);
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* Facebook, Inc. ("Facebook") owns all right, title and interest, including
|
||||
* all intellectual property and other proprietary rights, in and to the React
|
||||
* Native CustomComponents software (the "Software"). Subject to your
|
||||
* compliance with these terms, you are hereby granted a non-exclusive,
|
||||
* worldwide, royalty-free copyright license to (1) use and copy the Software;
|
||||
* and (2) reproduce and distribute the Software as part of your own software
|
||||
* ("Your Software"). Facebook reserves all rights not expressly granted to
|
||||
* you in this license agreement.
|
||||
*
|
||||
* THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
|
||||
* EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @providesModule NavigationLegacyNavigator
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const Animated = require('Animated');
|
||||
const NavigationAnimatedValueSubscription = require('NavigationAnimatedValueSubscription');
|
||||
const NavigationAnimatedView = require('NavigationAnimatedView');
|
||||
const NavigationCard = require('NavigationCard');
|
||||
const NavigationCardStackStyleInterpolator = require('NavigationCardStackStyleInterpolator');
|
||||
const NavigationContext = require('NavigationContext');
|
||||
const NavigationLegacyNavigatorRouteStack = require('NavigationLegacyNavigatorRouteStack');
|
||||
const NavigationCardStackPanResponder = require('NavigationCardStackPanResponder');
|
||||
const NavigationPagerPanResponder = require('NavigationPagerPanResponder');
|
||||
const NavigationPagerStyleInterpolator = require('NavigationPagerStyleInterpolator');
|
||||
const NavigatorBreadcrumbNavigationBar = require('NavigatorBreadcrumbNavigationBar');
|
||||
const NavigatorNavigationBar = require('NavigatorNavigationBar');
|
||||
const NavigatorSceneConfigs = require('NavigatorSceneConfigs');
|
||||
const React = require('React');
|
||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
|
||||
import type {
|
||||
NavigationActionCaller,
|
||||
NavigationAnimatedValue,
|
||||
NavigationAnimationSetter,
|
||||
NavigationParentState,
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type Props = {
|
||||
configureScene: any,
|
||||
initialRoute: any,
|
||||
initialRouteStack: any,
|
||||
navigationBar: any,
|
||||
navigationBarNavigator: any,
|
||||
navigator: any,
|
||||
onDidFocus: any,
|
||||
onWillFocus: any,
|
||||
renderScene: any,
|
||||
renderScene: any,
|
||||
style: any,
|
||||
};
|
||||
|
||||
type State = {
|
||||
presentedIndex: number,
|
||||
routeStack: Array<any>,
|
||||
};
|
||||
|
||||
const RouteStack = NavigationLegacyNavigatorRouteStack;
|
||||
|
||||
/**
|
||||
* NavigationLegacyNavigator is meant to replace Navigator seemlessly with
|
||||
* minimum API changes.
|
||||
*
|
||||
* While the APIs remain compatible with Navigator, it is built with good
|
||||
* intention by using the new Navigation API such as
|
||||
* `NavigationAnimatedView`...etc.
|
||||
*/
|
||||
class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
||||
static BreadcrumbNavigationBar: any;
|
||||
static NavigationBar: any;
|
||||
static SceneConfigs: any;
|
||||
|
||||
_applyAnimation: NavigationAnimationSetter;
|
||||
_navigationBarRef: any;
|
||||
_onNavigationBarRef: (ref: any) => void;
|
||||
_onPositionChange: (data: {value: number}) => void;
|
||||
_positionListener: ?NavigationAnimatedValueSubscription;
|
||||
_previousStack: NavigationLegacyNavigatorRouteStack;
|
||||
_renderCard: NavigationSceneRenderer;
|
||||
_renderHeader: NavigationSceneRenderer;
|
||||
_renderScene: NavigationSceneRenderer;
|
||||
_routeFocused: any;
|
||||
_routeToFocus: any;
|
||||
_onNavigate: NavigationActionCaller;
|
||||
_stack: NavigationLegacyNavigatorRouteStack;
|
||||
_useAnimation: boolean;
|
||||
|
||||
navigationContext: NavigationContext;
|
||||
parentNavigator: any;
|
||||
props: Props;
|
||||
state: State;
|
||||
|
||||
constructor(props: Props, context: any) {
|
||||
super(props, context);
|
||||
|
||||
const stack = this._getInitialRouteStack();
|
||||
|
||||
// Unfortunately, due to historical reasons, the `state` has been exposed
|
||||
// as public members of the navigator, therefore we'd keep private state
|
||||
// as private members.
|
||||
this._previousStack = stack;
|
||||
this._stack = stack;
|
||||
this._useAnimation = false;
|
||||
|
||||
// Legacy members portred from `Navigator`.
|
||||
this.parentNavigator = props.navigator;
|
||||
this.navigationContext = new NavigationContext();
|
||||
|
||||
this.state = {
|
||||
routeStack: stack.toArray(),
|
||||
presentedIndex: stack.index,
|
||||
};
|
||||
}
|
||||
|
||||
jumpTo(route: any): void {
|
||||
this._applyStack(this._stack.jumpTo(route));
|
||||
}
|
||||
|
||||
jumpForward(): void {
|
||||
this._applyStack(this._stack.jumpForward());
|
||||
}
|
||||
|
||||
jumpBack(): void {
|
||||
this._applyStack(this._stack.jumpBack());
|
||||
}
|
||||
|
||||
push(route: any): void {
|
||||
this._applyStack(this._stack.push(route));
|
||||
}
|
||||
|
||||
pop(): void {
|
||||
this._applyStack(this._stack.pop());
|
||||
}
|
||||
|
||||
replaceAtIndex(route: any, index: number): void {
|
||||
this._applyStack(this._stack.replaceAtIndex(index, route));
|
||||
}
|
||||
|
||||
replace(route: any): void {
|
||||
this.replaceAtIndex(route, this._stack.index);
|
||||
}
|
||||
|
||||
replacePrevious(route: any): void {
|
||||
this.replaceAtIndex(route, this._stack.index - 1);
|
||||
}
|
||||
|
||||
popToTop(): void {
|
||||
this._applyStack(this._stack.slice(0, 1));
|
||||
}
|
||||
|
||||
popToRoute(route: any): void {
|
||||
this._applyStack(this._stack.popToRoute(route));
|
||||
}
|
||||
|
||||
replacePreviousAndPop(route: any): void {
|
||||
this._applyStack(this._stack.replacePreviousAndPop(route));
|
||||
}
|
||||
|
||||
resetTo(route: any): void {
|
||||
this._applyStack(this._stack.resetTo(route));
|
||||
}
|
||||
|
||||
immediatelyResetRouteStack(routes: Array<any>): void {
|
||||
this._applyStack(this._stack.resetRoutes(routes), true);
|
||||
}
|
||||
|
||||
getCurrentRoutes(): Array<any> {
|
||||
return this._stack.toArray();
|
||||
}
|
||||
|
||||
// Life cycle and private methods below.
|
||||
|
||||
shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
|
||||
return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
|
||||
this,
|
||||
nextProps,
|
||||
nextState
|
||||
);
|
||||
}
|
||||
|
||||
componentWillMount(): void {
|
||||
this._applyAnimation = this._applyAnimation.bind(this);
|
||||
this._onNavigate = this._onNavigate.bind(this);
|
||||
this._onNavigationBarRef = this._onNavigationBarRef.bind(this);
|
||||
this._onPositionChange = this._onPositionChange.bind(this);
|
||||
this._renderCard = this._renderCard.bind(this);
|
||||
this._renderHeader = this._renderHeader.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
|
||||
this._willFocus();
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this._didFocus();
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
this._positionListener && this._positionListener.remove();
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps: Props, nextState: State): void {
|
||||
this._willFocus();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props, prevState: State): void {
|
||||
if (this._useAnimation) {
|
||||
// will play animation.
|
||||
return;
|
||||
}
|
||||
this._didFocus();
|
||||
}
|
||||
|
||||
render(): ReactElement {
|
||||
return (
|
||||
<NavigationAnimatedView
|
||||
applyAnimation={this._applyAnimation}
|
||||
navigationState={this._stack.toNavigationState()}
|
||||
onNavigate={this._onNavigate}
|
||||
renderOverlay={this._renderHeader}
|
||||
renderScene={this._renderCard}
|
||||
style={this.props.style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_getInitialRouteStack(): RouteStack {
|
||||
const {initialRouteStack, initialRoute} = this.props;
|
||||
const routes = initialRouteStack || [initialRoute];
|
||||
const index = initialRoute ?
|
||||
routes.indexOf(initialRoute) :
|
||||
routes.length - 1;
|
||||
return new RouteStack(index, routes);
|
||||
}
|
||||
|
||||
_renderHeader(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
// `_renderHeader` is always called before `_renderCard`. We should
|
||||
// subscribe to the position here.
|
||||
this._positionListener && this._positionListener.remove();
|
||||
this._positionListener = new NavigationAnimatedValueSubscription(
|
||||
props.position,
|
||||
this._onPositionChange,
|
||||
);
|
||||
|
||||
const {navigationBar, navigationBarNavigator} = this.props;
|
||||
if (!navigationBar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return React.cloneElement(
|
||||
navigationBar,
|
||||
{
|
||||
key: 'header_' + props.scene.key,
|
||||
ref: this._onNavigationBarRef,
|
||||
navigator: navigationBarNavigator || this,
|
||||
navState: {...this.state},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_renderCard(props: NavigationSceneRendererProps): ReactElement {
|
||||
const {scene} = props;
|
||||
const {configureScene} = this.props;
|
||||
|
||||
// Default getters for style and pan responders.
|
||||
let styleGetter = NavigationCardStackStyleInterpolator.forHorizontal;
|
||||
let panResponderGetter = NavigationCardStackPanResponder.forHorizontal;
|
||||
|
||||
if (configureScene) {
|
||||
const route = RouteStack.getRouteByNavigationState(scene.navigationState);
|
||||
const config = configureScene(route, this.state.routeStack);
|
||||
|
||||
if (config) {
|
||||
const gestures = config.gestures || {};
|
||||
if (gestures.pop && gestures.pop.direction === 'left-to-right') {
|
||||
// pass, will use default getters.
|
||||
} else if (gestures.pop && gestures.pop.direction === 'top-to-bottom') {
|
||||
styleGetter = NavigationCardStackStyleInterpolator.forVertical;
|
||||
panResponderGetter = NavigationCardStackPanResponder.forVertical;
|
||||
} else if (
|
||||
gestures.jumpBack &&
|
||||
gestures.jumpForward &&
|
||||
gestures.jumpBack.direction === 'left-to-right' &&
|
||||
gestures.jumpForward.direction === 'right-to-left'
|
||||
) {
|
||||
styleGetter = NavigationPagerStyleInterpolator.forHorizontal;
|
||||
panResponderGetter = NavigationPagerPanResponder.forHorizontal;
|
||||
} else if (__DEV__) {
|
||||
console.warn('unsupported scene configuration', config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const style = styleGetter(props);
|
||||
const panHandlers = panResponderGetter(props);
|
||||
|
||||
return (
|
||||
<NavigationCard
|
||||
{...props}
|
||||
key={'card_' + props.scene.key}
|
||||
panHandlers={panHandlers}
|
||||
renderScene={this._renderScene}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(props: NavigationSceneRendererProps): ReactElement {
|
||||
const {navigationState} = props.scene;
|
||||
const route = RouteStack.getRouteByNavigationState(navigationState);
|
||||
return this.props.renderScene(route, this);
|
||||
}
|
||||
|
||||
_applyStack(
|
||||
stack: NavigationLegacyNavigatorRouteStack,
|
||||
noAnimation: ?boolean,
|
||||
): void {
|
||||
if (stack !== this._stack) {
|
||||
this._previousStack = this._stack;
|
||||
this._stack = stack;
|
||||
|
||||
this._useAnimation = noAnimation ||
|
||||
this._previousStack.index !== stack.index;
|
||||
|
||||
this.setState({
|
||||
presentedIndex: stack.index,
|
||||
routeStack: stack.toArray(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_onNavigationBarRef(navigationBarRef: any): void {
|
||||
this._navigationBarRef = navigationBarRef;
|
||||
const {navigationBar} = this.props;
|
||||
if (navigationBar && typeof navigationBar.ref === 'function') {
|
||||
navigationBar.ref(navigationBarRef);
|
||||
}
|
||||
}
|
||||
|
||||
_onPositionChange(data: {value: number}): void {
|
||||
const fromIndex = this._previousStack.index;
|
||||
const toIndex = this._stack.index;
|
||||
|
||||
if (
|
||||
fromIndex !== toIndex &&
|
||||
this._navigationBarRef &&
|
||||
typeof this._navigationBarRef.updateProgress === 'function'
|
||||
) {
|
||||
const progress = (data.value - fromIndex) / (toIndex - fromIndex);
|
||||
this._navigationBarRef.updateProgress(progress, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
const diff = this._stack.index - data.value;
|
||||
// When animation stops, the `diff` can still be very a small non-zero value
|
||||
// (e.g. 0.00000002). Call `willFocus` when `diff` is small enough.
|
||||
if (diff < 0.05) {
|
||||
this._didFocus();
|
||||
}
|
||||
}
|
||||
|
||||
_applyAnimation(
|
||||
position: NavigationAnimatedValue,
|
||||
nextState: NavigationParentState,
|
||||
prevState: NavigationParentState,
|
||||
): void {
|
||||
const {index} = nextState;
|
||||
|
||||
if (!this._useAnimation) {
|
||||
position.setValue(index);
|
||||
return;
|
||||
}
|
||||
|
||||
Animated.timing(
|
||||
position,
|
||||
{
|
||||
duration: 500,
|
||||
toValue: index,
|
||||
}
|
||||
).start();
|
||||
}
|
||||
|
||||
_willFocus(): void {
|
||||
const route = this._stack.get(this._stack.index);
|
||||
if (this._routeToFocus === route) {
|
||||
return;
|
||||
}
|
||||
this._routeToFocus = route;
|
||||
this.navigationContext.emit('willfocus', {route: route});
|
||||
this.props.onWillFocus && this.props.onWillFocus(route);
|
||||
}
|
||||
|
||||
_didFocus(): void {
|
||||
const route = this._stack.get(this._stack.index);
|
||||
if (this._routeFocused === route) {
|
||||
return;
|
||||
}
|
||||
this._routeFocused = route;
|
||||
this.navigationContext.emit('didfocus', {route: route});
|
||||
this.props.onDidFocus && this.props.onDidFocus(route);
|
||||
}
|
||||
|
||||
_onNavigate(action: any): void {
|
||||
switch (action) {
|
||||
case NavigationCardStackPanResponder.Actions.BACK:
|
||||
this.pop();
|
||||
break;
|
||||
case NavigationPagerPanResponder.Actions.JUMP_BACK:
|
||||
this.jumpBack();
|
||||
break;
|
||||
case NavigationPagerPanResponder.Actions.JUMP_FORWARD:
|
||||
this.jumpForward();
|
||||
break;
|
||||
default:
|
||||
if (__DEV__) {
|
||||
console.warn('unsupported gesture action', action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy static members.
|
||||
NavigationLegacyNavigator.BreadcrumbNavigationBar = NavigatorBreadcrumbNavigationBar;
|
||||
NavigationLegacyNavigator.NavigationBar = NavigatorNavigationBar;
|
||||
NavigationLegacyNavigator.SceneConfigs = NavigatorSceneConfigs;
|
||||
|
||||
module.exports = NavigationLegacyNavigator;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user