Compare commits

...
18 Commits
Author SHA1 Message Date
Martin Konicek 6496feb61e [0.20.0] Bump version numbers 2016-02-15 17:31:49 +00:00
Andrei ComanandKonstantin Raev cb762b045b Expose screen metrics and window metrics
Summary:
public
https://github.com/facebook/react-native/pull/4935 changed the window dimensions for android by replacing them with the actual screen dimensions. This changes the window dimensions back to their original values and adds `Dimensions.get('screen')` for the actual screen dimensions of the device.

Reviewed By: astreet

Differential Revision: D2921584

fb-gh-sync-id: 5d2677029c71d50691691dc651a11e9c8b115e8f
shipit-source-id: 5d2677029c71d50691691dc651a11e9c8b115e8f
2016-02-15 16:48:24 +00:00
Andrei ComanandKonstantin Raev b74d0078f5 Make keyboard detection more robust
Reviewed By: nspaun

Differential Revision: D2905647

fb-gh-sync-id: 0bd5405f32a5e63c9f85178b4d1f777fe032f8d5
2016-02-15 16:48:11 +00:00
Andrei ComanandKonstantin Raev ff4ef2f633 Fix DisplayMetrics KeyboardListener dependency
Summary:
public
KeyboardListener needs DisplayMetrics to be initialized when it is attached. At
the moment, this breaks easily whenever we change these components, since DisplayMetrics are intialized
in a module and KeyboardListener is created eagerly in ReactRootView, whereas
ReactRootView can exist without the instance.
This changes to create DisplayMetrics as soon as possible, when the react
instance is built. The KeyboardListener is created and attached after the ReactRootView is
attached to an existing instance, point at which DisplayMetrics have to be
initialized.

Reviewed By: dmmiller

Differential Revision: D2911351

fb-gh-sync-id: 64d1805c5d5b2f6876adb694b565a2df059b381d
2016-02-15 16:45:34 +00:00
Adam MiskiewiczandKonstantin Raev d5ed811a2b Adding 'transform-symbol-member' transform to preset.
Summary:
Turns out, even after discussion that was had in https://github.com/facebook/react-native/pull/5294#issuecomment-174397103, we really do need this transform.

I've just included it in the preset...let me know if you all would rather publish to npm.

The actual reason why this is necessary is because in the latest sync from FB, fbjs was updated to use the `Symbol.iterator` express in it's isEmpty function: https://github.com/facebook/fbjs/commit/064a484e18b03f988f9eb540255ef8d742301c8d

We use this in RN in the ListView...and this change (once #5084 is merged) will cause ListView to break on older JSC context's.

This resolves that, and is probably something we should have had all along.
Closes https://github.com/facebook/react-native/pull/5824

Reviewed By: svcscm

Differential Revision: D2913315

Pulled By: vjeux

fb-gh-sync-id: abaf484a9431b3111e8118d01db8d2c0d2dd73ca
shipit-source-id: abaf484a9431b3111e8118d01db8d2c0d2dd73ca
2016-02-15 16:12:01 +00:00
Mark VayngribandKonstantin Raev 4ad141d4fb multiGet breaking test and fix
Summary:
the flush + optimized multiGet result in an obscure bug that results when two multiGet requests with overlapping key sets get issued. The result array for both requests ends up bigger than the key array (because it has duplicates)
Closes https://github.com/facebook/react-native/pull/5514

Reviewed By: svcscm

Differential Revision: D2908264

Pulled By: nicklockwood

fb-gh-sync-id: 60be1bce4acfc47083e4ae28bb8b63f9dfa56039
2016-02-15 16:11:41 +00:00
Keith NormanandKonstantin Raev 6cce770e7b fix issue that breaks scroll views w/ RefreshControl on Android
Summary:
Fixes the issue I mentioned here https://github.com/facebook/react-native/pull/5623#issuecomment-180583142
Closes https://github.com/facebook/react-native/pull/5784

Reviewed By: svcscm

Differential Revision: D2908112

Pulled By: nicklockwood

fb-gh-sync-id: 8a2f053de3f7dc19807ee21dd969c53a57b71345
2016-02-15 16:11:27 +00:00
Dave MillerandKonstantin Raev 2c6875effa Fix promises on iOS to no longer wrap values in Arrays
Summary:
public
In https://github.com/facebook/react-native/commit/9baff8f437eee49f8ab0e6f433bf86466ca16662#diff-8d9841e5b53fd6c9cf3a7f431827e319R331, I incorrectly assumed that iOS was wrapping promises in an extra Array.  What was really happening is that all the callers were doing this.  I removed the wrapping in the callers and the special case handling MessageQueue.

Now one can pass whatever object one wants to resolve and it will show properly in the resolve call on the js side.  This fixes issue https://github.com/facebook/react-native/issues/5851

Reviewed By: nicklockwood

Differential Revision: D2921565

fb-gh-sync-id: 9f81e2a87f6a48e9197413b843e452db345a7ff9
shipit-source-id: 9f81e2a87f6a48e9197413b843e452db345a7ff9
2016-02-15 16:11:13 +00:00
Konstantin RaevandKonstantin Raev dd1e949f12 Disable proguard
Summary:
until we have an automated test in CI
Closes https://github.com/facebook/react-native/pull/5775

Reviewed By: svcscm

Differential Revision: D2911639

Pulled By: mkonicek

fb-gh-sync-id: 26d8194dd5a6fd7210f4b014787e6847217dd7f1
2016-02-15 16:10:46 +00:00
Konstantin Raev e7b558ec44 fixed a link to android setup docs 2016-02-14 17:12:08 +00:00
Konstantin Raev d5df43a03e Added ability to switch version in documentation website
Website header now contains version number which is a link.
Clicking the link redirects you to a page that lists all the previous versions of the website.

Considering that we do a branch cut every 2 weeks a solution with dropdown did not feel right because it would grow fast.
As an improvement for the future - we could link change docs in the versions.html
2016-02-12 19:29:01 +00:00
Konstantin Raev b1533485f1 CI now builds docs website and deploys it to /%version% path
Summary:
Copy of #5760 reverted merge.

We need to preserve history of docs changes on the webserver.
The goal is to allow users to browse outdated versions of docs.
To make things simple all websites will be released to https://facebook.github.io/react-native/releases/version/XX folder when there is a branch cut.

I switched from Travis CI to Cirle CI because it works faster and I am more familiar with it.

How it works:

1. If code is pushed to `master` branch then CI will build a fresh version of docs and put it in https://github.com/facebook/react-native/tree/gh-pages/releases/next folder.
Github will serve this website from https://facebook.github.io/react-native/releases/version/next URL.
All relative URLs will work within that website

2. If code is pushed to `0.20-stable` branch then CI will build a fresh version of docs and put it in https://github.com/facebook/react-native/tree/gh-pages/releases/0.20 folder.
Github will serve this website from https://facebook.github.io/react-native/releases/v
Closes https://github.com/facebook/react-native/pull/5873

Reviewed By: svcscm

Differential Revision: D2926901

Pulled By: androidtrunkagent

fb-gh-sync-id: 16aea430bac815933d9c603f03921cc6353906f1
shipit-source-id: 16aea430bac815933d9c603f03921cc6353906f1

Conflicts:
	circle.yml
2016-02-12 13:11:33 +00:00
Konstantin Raev d4c6e60ced version 0.20.0-rc1 2016-02-06 17:53:40 +00:00
Martin KonicekandKonstantin Raev fa17a572c0 Disable menu option for HMR, it's not ready just yet 2016-02-05 14:54:58 +00:00
fangmobileandKonstantin Raev c71530259e added accessibility props for touchables
Summary:
accessibilityLabels are missing in these touchable*.js files.
for #5322
ide This is not tested yet. I will update with test.
Closes https://github.com/facebook/react-native/pull/5346

Reviewed By: svcscm

Differential Revision: D2882061

Pulled By: gkassabli

fb-gh-sync-id: dff0ef373e5f5895027cb1cc08c8887a6ace8eee
2016-02-05 14:50:39 +00:00
Adam MiskiewiczandKonstantin Raev 1ef0b8f4db Use new DisplayMetrics object in getDisplayMetrics as to not overwrite Android global state
Summary:
The change in https://github.com/facebook/react-native/commit/8e603940e3fca4ed2fe420c02a66d860b53f3076 actually causes a super bad bug when `context.getResources().getDisplayMetrics()` is accessed in other parts of the application.

It turns out that when you dive into the impl of `getRealMetrics`, it mutates whatever `DisplayMetrics` object is passed to it. In this case, `getDisplayMetrics` ends up mutating the `DisplayMetrics` object that sits on the application context's `Resources` instance.

This PR makes that not so.

/cc jesseruder ide jaysoo bestander astreet
Closes https://github.com/facebook/react-native/pull/5764

Reviewed By: svcscm

Differential Revision: D2902386

Pulled By: androidtrunkagent

fb-gh-sync-id: 3f24b68bc7e6b4ca83808c03ef3637e1ac9a673e
2016-02-05 14:49:07 +00:00
Janic DuplessisandKonstantin Raev 3eb5993044 Fix proguard template for ReactProp and ReactPropGroup
Summary:
ReactProp and ReactPropGroup were moved in the annotations package but the proguard file was not updated accordingly. This caused apps to crash when built in release using proguard.

Fixes #5655
Closes https://github.com/facebook/react-native/pull/5717

Reviewed By: svcscm

Differential Revision: D2905573

Pulled By: lexs

fb-gh-sync-id: 29ab14bacda7254d9896ff3991bf17d7fdfd6ea9
2016-02-05 14:44:49 +00:00
Konstantin Raev 29997b3644 [0.20.0-rc] Bump version numbers 2016-02-04 12:06:12 +00:00
90 changed files with 656 additions and 354 deletions
+2 -18
View File
@@ -42,24 +42,11 @@ script:
npm test -- '\/(local|private|react-native)-cli\/'
elif [ "$TEST_TYPE" = build_website ]
then
cd website
$(which npm) install
./setup.sh
if [ "$TRAVIS_PULL_REQUEST" = false ] && [ "$TRAVIS_BRANCH" = master ]; then
# Automatically publish the website
echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" >~/.netrc
./publish.sh
else
# Make sure the website builds without error
node server/generate.js
fi
elif [ "$TEST_TYPE" = e2e ]
then
./scripts/e2e-test.sh
else
echo "Unknown test type: $TEST_TYPE"
exit 1
@@ -71,11 +58,8 @@ env:
- TEST_TYPE=js
- TEST_TYPE=packager
- TEST_TYPE=cli
- TEST_TYPE=build_website
- TEST_TYPE=e2e
global:
# $GITHUB_TOKEN
- secure: "HlmG8M2DmBUSBh6KH1yVIe/8gR4iibg4WfcHq1x/xYQxGbvleq7NOo04V6eFHnl9cvZCu+PKH0841WLnGR7c4BBf47GVu/o16nXzggPumHKy++lDzxFPlJ1faMDfjg/5vjbAxRUe7D3y98hQSeGHH4tedc8LvTaFLVu7iiGqvjU="
# $APPETIZE_TOKEN
- secure: "egsvVSpszTzrNd6bN62DsVAzMiSZI/OHgdizfPryqvqWBf655ztE6XFQSEFNpuIAzSKDDF25ioT8iPfVsbC1iK6HDWHfmqYxML0L+OoU0gi+hV2oKUBFZDZ1fwSnFoWuBdNdMDpLlUxvJp6N1WyfNOB2dxuZUt8eTt48Hi3+Hpc="
# $S3_TOKEN
@@ -208,7 +208,13 @@ exports.examples = [
{
title: 'Auto-focus',
render: function() {
return <TextInput autoFocus={true} style={styles.singleLine} />;
return (
<TextInput
autoFocus={true}
style={styles.singleLine}
accessibilityLabel="I am the accessibility label for text input"
/>
);
}
},
{
+7 -1
View File
@@ -348,7 +348,13 @@ exports.examples = [
{
title: 'Auto-focus',
render: function() {
return <TextInput autoFocus={true} style={styles.default} />;
return (
<TextInput
autoFocus={true}
style={styles.default}
accessibilityLabel="I am the accessibility label for text input"
/>
);
}
},
{
+3
View File
@@ -144,6 +144,9 @@ var TouchableFeedbackEvents = React.createClass({
<TouchableOpacity
style={styles.wrapper}
testID="touchable_feedback_events_button"
accessibilityLabel="touchable feedback events"
accessibilityTraits="button"
accessibilityComponentType="button"
onPress={() => this._appendEvent('press')}
onPressIn={() => this._appendEvent('pressIn')}
onPressOut={() => this._appendEvent('pressOut')}
+18
View File
@@ -142,12 +142,30 @@ function testMerge() {
expectAsyncNoError('testMerge/setItem', err3);
expectEqual(JSON.parse(result), VAL_MERGE_EXPECT, 'testMerge');
updateMessage('objects deeply merged\nDone!');
runTestCase('multi set and get', testOptimizedMultiGet);
});
});
});
}
function testOptimizedMultiGet() {
let batch = [[KEY_1, VAL_1], [KEY_2, VAL_2]];
let keys = batch.map(([key, value]) => key);
AsyncStorage.multiSet(batch, (err1) => {
// yes, twice on purpose
;[1, 2].forEach((i) => {
expectAsyncNoError(`${i} testOptimizedMultiGet/multiSet`, err1);
AsyncStorage.multiGet(keys, (err2, result) => {
expectAsyncNoError(`${i} testOptimizedMultiGet/multiGet`, err2);
expectEqual(result, batch, `${i} testOptimizedMultiGet multiGet`);
updateMessage('multiGet([key_1, key_2]) correctly returned ' + JSON.stringify(result));
done();
});
});
});
}
var AsyncStorageTest = React.createClass({
getInitialState() {
return {
@@ -1556,7 +1556,7 @@ var event = function(
* interaction patterns, like drag-and-drop.
*
* You can see more example usage in `AnimationExample.js`, the Gratuitous
* Animation App, and [Animations documentation guide](http://facebook.github.io/react-native/docs/animations.html).
* Animation App, and [Animations documentation guide](docs/animations.html).
*
* Note that `Animated` is designed to be fully serializable so that animations
* can be run in a high performance way, independent of the normal JavaScript
+5 -5
View File
@@ -98,7 +98,7 @@ RCT_EXPORT_METHOD(saveImageWithTag:(NSString *)imageTag
RCTLogWarn(@"Error saving cropped image: %@", saveError);
reject(RCTErrorUnableToSave, nil, saveError);
} else {
resolve(@[assetURL.absoluteString]);
resolve(assetURL.absoluteString);
}
}];
});
@@ -110,22 +110,22 @@ static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
BOOL hasNextPage)
{
if (!assets.count) {
resolve(@[@{
resolve(@{
@"edges": assets,
@"page_info": @{
@"has_next_page": @NO,
}
}]);
});
return;
}
resolve(@[@{
resolve(@{
@"edges": assets,
@"page_info": @{
@"start_cursor": assets[0][@"node"][@"image"][@"uri"],
@"end_cursor": assets[assets.count - 1][@"node"][@"image"][@"uri"],
@"has_next_page": @(hasNextPage),
}
}]);
});
}
RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
@@ -315,7 +315,7 @@ var ScrollView = React.createClass({
* A RefreshControl component, used to provide pull-to-refresh
* functionality for the ScrollView.
*
* See [RefreshControl](http://facebook.github.io/react-native/docs/refreshcontrol.html).
* See [RefreshControl](docs/refreshcontrol.html).
*/
refreshControl: PropTypes.element,
@@ -530,7 +530,7 @@ var ScrollView = React.createClass({
// AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
return React.cloneElement(
refreshControl,
{style: this.props.style},
{style: props.style},
<ScrollViewClass {...props} style={styles.base} ref={SCROLLVIEW}>
{contentContainer}
</ScrollViewClass>
+6 -4
View File
@@ -290,10 +290,6 @@ var TextInput = React.createClass({
* Styles
*/
style: Text.propTypes.style,
/**
* Used to locate this view in end-to-end tests
*/
testID: PropTypes.string,
/**
* The color of the textInput underline.
* @platform android
@@ -457,6 +453,9 @@ var TextInput = React.createClass({
<TouchableWithoutFeedback
onPress={this._onPress}
rejectResponderTermination={true}
accessible={props.accessible}
accessibilityLabel={props.accessibilityLabel}
accessibilityTraits={props.accessibilityTraits}
testID={props.testID}>
{textContainer}
</TouchableWithoutFeedback>
@@ -520,6 +519,9 @@ var TextInput = React.createClass({
return (
<TouchableWithoutFeedback
onPress={this._onPress}
accessible={this.props.accessible}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityComponentType={this.props.accessibilityComponentType}
testID={this.props.testID}>
{textContainer}
</TouchableWithoutFeedback>
@@ -117,6 +117,9 @@ var TouchableBounce = React.createClass({
<Animated.View
style={[{transform: [{scale: this.state.scale}]}, this.props.style]}
accessible={true}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityComponentType={this.props.accessibilityComponentType}
accessibilityTraits={this.props.accessibilityTraits}
testID={this.props.testID}
onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
@@ -215,6 +215,7 @@ var TouchableHighlight = React.createClass({
return (
<View
accessible={true}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityComponentType={this.props.accessibilityComponentType}
accessibilityTraits={this.props.accessibilityTraits}
ref={UNDERLAY_REF}
@@ -200,6 +200,7 @@ var TouchableNativeFeedback = React.createClass({
...onlyChild(this.props.children).props,
nativeBackgroundAndroid: this.props.background,
accessible: this.props.accessible !== false,
accessibilityLabel: this.props.accessibilityLabel,
accessibilityComponentType: this.props.accessibilityComponentType,
accessibilityTraits: this.props.accessibilityTraits,
testID: this.props.testID,
@@ -154,6 +154,7 @@ var TouchableOpacity = React.createClass({
return (
<Animated.View
accessible={true}
accessibilityLabel={this.props.accessibilityLabel}
accessibilityComponentType={this.props.accessibilityComponentType}
accessibilityTraits={this.props.accessibilityTraits}
style={[this.props.style, {opacity: this.state.anim}]}
@@ -135,6 +135,7 @@ var TouchableWithoutFeedback = React.createClass({
// Note(avik): remove dynamic typecast once Flow has been upgraded
return (React: any).cloneElement(onlyChild(this.props.children), {
accessible: this.props.accessible !== false,
accessibilityLabel: this.props.accessibilityLabel,
accessibilityComponentType: this.props.accessibilityComponentType,
accessibilityTraits: this.props.accessibilityTraits,
testID: this.props.testID,
+3 -3
View File
@@ -80,7 +80,7 @@ RCT_EXPORT_METHOD(openURL:(NSURL *)URL
// TODO: we should really report success/failure via the promise here
// Doesn't really matter what thread we call this on since it exits the app
[RCTSharedApplication() openURL:URL];
resolve(@[@YES]);
resolve(@YES);
}
RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
@@ -90,13 +90,13 @@ RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
if (RCTRunningInAppExtension()) {
// Technically Today widgets can open urls, but supporting that would require
// a reference to the NSExtensionContext
resolve(@[@NO]);
resolve(@NO);
return;
}
// This can be expensive, so we deliberately don't call on main thread
BOOL canOpen = [RCTSharedApplication() canOpenURL:URL];
resolve(@[@(canOpen)]);
resolve(@(canOpen));
}
@end
@@ -29,7 +29,7 @@ var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
* To get up and running, [configure your notifications with Apple](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW6)
* and your server-side system. To get an idea, [this is the Parse guide](https://parse.com/tutorials/ios-push-notifications).
*
* [Manually link](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking) the PushNotificationIOS library
* [Manually link](docs/linking-libraries-ios.html#manual-linking) the PushNotificationIOS library
*
* - Be sure to add the following to your `Header Search Paths`:
* `$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS`
+3 -3
View File
@@ -56,7 +56,7 @@ function warnForStyleProps(props, validAttributes) {
* composite components that aren't directly backed by a native view. This will
* generally include most components that you define in your own app. For more
* information, see [Direct
* Manipulation](/react-native/docs/direct-manipulation.html).
* Manipulation](docs/direct-manipulation.html).
*/
var NativeMethodsMixin = {
/**
@@ -74,7 +74,7 @@ var NativeMethodsMixin = {
* Note that these measurements are not available until after the rendering
* has been completed in native. If you need the measurements as soon as
* possible, consider using the [`onLayout`
* prop](/react-native/docs/view.html#onlayout) instead.
* prop](docs/view.html#onlayout) instead.
*/
measure: function(callback: MeasureOnSuccessCallback) {
UIManager.measure(
@@ -108,7 +108,7 @@ var NativeMethodsMixin = {
* This function sends props straight to native. They will not participate in
* future diff process - this means that if you do not include them in the
* next render, they will remain active (see [Direct
* Manipulation](/react-native/docs/direct-manipulation.html)).
* Manipulation](docs/direct-manipulation.html)).
*/
setNativeProps: function(nativeProps: Object) {
if (__DEV__) {
+13 -5
View File
@@ -180,14 +180,16 @@ var AsyncStorage = {
// Even though the runtime complexity of this is theoretically worse vs if we used a map,
// it's much, much faster in practice for the data sets we deal with (we avoid
// allocating result pair arrays). This was heavily benchmarked.
//
// Is there a way to avoid using the map but fix the bug in this breaking test?
// https://github.com/facebook/react-native/commit/8dd8ad76579d7feef34c014d387bf02065692264
let map = {};
result.forEach(([key, value]) => map[key] = value);
const reqLength = getRequests.length;
for (let i = 0; i < reqLength; i++) {
const request = getRequests[i];
const requestKeys = request.keys;
var requestResult = result.filter(function(resultPair) {
return requestKeys.indexOf(resultPair[0]) !== -1;
});
let requestResult = requestKeys.map(key => [key, map[key]]);
request.callback && request.callback(null, requestResult);
request.resolve && request.resolve(requestResult);
}
@@ -214,6 +216,7 @@ var AsyncStorage = {
var getRequest = {
keys: keys,
callback: callback,
// do we need this?
keyIndex: this._getKeys.length,
resolve: null,
reject: null,
@@ -225,7 +228,12 @@ var AsyncStorage = {
});
this._getRequests.push(getRequest);
this._getKeys.push.apply(this._getKeys, keys);
// avoid fetching duplicates
keys.forEach(key => {
if (this._getKeys.indexOf(key) === -1) {
this._getKeys.push(key);
}
});
return promiseResult;
},
+1 -1
View File
@@ -45,7 +45,7 @@ type ButtonsArray = Array<{
class AlertIOS {
/**
* Creates a popup to alert the user. See
* [Alert](/react-native/docs/alert.html).
* [Alert](docs/alert.html).
*
* - title: string -- The dialog's title.
* - message: string -- An optional message that appears above the text input.
+15
View File
@@ -11,6 +11,7 @@
*/
'use strict';
var Platform = require('Platform');
var UIManager = require('UIManager');
var invariant = require('invariant');
@@ -31,7 +32,21 @@ if (dimensions && dimensions.windowPhysicalPixels) {
scale: windowPhysicalPixels.scale,
fontScale: windowPhysicalPixels.fontScale,
};
if (Platform.OS === 'android') {
// Screen and window dimensions are different on android
var screenPhysicalPixels = dimensions.screenPhysicalPixels;
dimensions.screen = {
width: screenPhysicalPixels.width / screenPhysicalPixels.scale,
height: screenPhysicalPixels.height / screenPhysicalPixels.scale,
scale: screenPhysicalPixels.scale,
fontScale: screenPhysicalPixels.fontScale,
};
// delete so no callers rely on this existing
delete dimensions.screenPhysicalPixels;
} else {
dimensions.screen = dimensions.window;
}
// delete so no callers rely on this existing
delete dimensions.windowPhysicalPixels;
}
+1 -5
View File
@@ -324,11 +324,7 @@ class MessageQueue {
method,
args,
(data) => {
// iOS always wraps the data in an Array regardless of what the
// shape of the data so we strip it out
// Android sends the data back properly
// TODO: Remove this once iOS has support for Promises natively (t9774697)
resolve(Platform.OS == 'ios' ? data[0] : data);
resolve(data);
},
(errorData) => {
var error = createErrorFromErrorData(errorData);
@@ -23,7 +23,7 @@ var currentCentroidY = TouchHistoryMath.currentCentroidY;
* recognize simple multi-touch gestures.
*
* It provides a predictable wrapper of the responder handlers provided by the
* [gesture responder system](/react-native/docs/gesture-responder-system.html).
* [gesture responder system](docs/gesture-responder-system.html).
* For each handler, it provides a new `gestureState` object alongside the
* native event object:
*
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "React"
s.version = "0.0.0-master"
s.version = "0.20.0"
s.summary = "Build high quality mobile apps using React."
s.description = <<-DESC
React Native apps are built using the React JS
+1 -1
View File
@@ -33,7 +33,7 @@ RCT_EXPORT_METHOD(getString:(RCTPromiseResolveBlock)resolve
rejecter:(__unused RCTPromiseRejectBlock)reject)
{
UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
resolve(@[RCTNullIfNil(clipboard.string)]);
resolve(RCTNullIfNil(clipboard.string));
}
@end
+1 -1
View File
@@ -32,7 +32,7 @@ RCT_EXPORT_METHOD(getScriptText:(RCTPromiseResolveBlock)resolve
if (RCT_DEV && self.scriptData && self.scriptURL) {
NSString *scriptText = [[NSString alloc] initWithData:self.scriptData encoding:NSUTF8StringEncoding];
resolve(@[@{@"text": scriptText, @"url": self.scriptURL.absoluteString}]);
resolve(@{@"text": scriptText, @"url": self.scriptURL.absoluteString});
} else {
reject(RCTErrorUnavailable, nil, RCTErrorWithMessage(@"Source code is not available"));
}
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_NAME=0.12.0-SNAPSHOT
VERSION_NAME=0.20.1
GROUP=com.facebook.react
POM_NAME=ReactNative
@@ -11,6 +11,8 @@ package com.facebook.react;
import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -21,8 +23,12 @@ import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
@@ -58,6 +64,7 @@ import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.uimanager.AppRegistry;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.UIImplementationProvider;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager;
@@ -248,6 +255,7 @@ import com.facebook.systrace.Systrace;
// TODO(9577825): remove this
ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext());
setDisplayMetrics(applicationContext);
mApplicationContext = applicationContext;
mJSBundleFile = jsBundleFile;
@@ -286,6 +294,40 @@ import com.facebook.systrace.Systrace;
SoLoader.init(applicationContext, /* native exopackage */ false);
}
private static void setDisplayMetrics(Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
DisplayMetrics screenDisplayMetrics = new DisplayMetrics();
screenDisplayMetrics.setTo(displayMetrics);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
// Get the real display metrics if we are using API level 17 or higher.
// The real metrics include system decor elements (e.g. soft menu bar).
//
// See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
if (Build.VERSION.SDK_INT >= 17) {
display.getRealMetrics(screenDisplayMetrics);
} else {
// For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions.
// Since react-native only supports API level 16+ we don't have to worry about other cases.
//
// Reflection exceptions are rethrown at runtime.
//
// See: http://stackoverflow.com/questions/14341041/how-to-get-real-screen-height-and-width/23861333#23861333
try {
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
screenDisplayMetrics.widthPixels = (Integer) mGetRawW.invoke(display);
screenDisplayMetrics.heightPixels = (Integer) mGetRawH.invoke(display);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
throw new RuntimeException("Error getting real dimensions for API level < 17", e);
}
}
DisplayMetricsHolder.setScreenDisplayMetrics(screenDisplayMetrics);
}
/**
* Trigger react context initialization asynchronously in a background async task. This enables
* applications to pre-load the application JS, and execute global code before
@@ -55,11 +55,10 @@ import com.facebook.react.uimanager.events.TouchEventType;
*/
public class ReactRootView extends SizeMonitoringFrameLayout implements RootView {
private final KeyboardListener mKeyboardListener = new KeyboardListener();
private @Nullable ReactInstanceManager mReactInstanceManager;
private @Nullable String mJSModuleName;
private @Nullable Bundle mLaunchOptions;
private @Nullable KeyboardListener mKeyboardListener;
private int mTargetTag = -1;
private final float[] mTargetCoordinates = new float[2];
private boolean mChildIsHandlingNativeGesture = false;
@@ -107,7 +106,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
Assertions.assertNotNull(mReactInstanceManager)
.attachMeasuredRootView(ReactRootView.this);
mIsAttachedToInstance = true;
getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
getViewTreeObserver().addOnGlobalLayoutListener(getKeyboardListener());
}
});
}
@@ -298,7 +297,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
if (mReactInstanceManager != null && !mAttachScheduled) {
mReactInstanceManager.detachRootView(this);
mIsAttachedToInstance = false;
getViewTreeObserver().removeOnGlobalLayoutListener(mKeyboardListener);
getViewTreeObserver().removeOnGlobalLayoutListener(getKeyboardListener());
}
}
@@ -356,7 +355,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
if (mWasMeasured && mIsAttachedToWindow) {
mReactInstanceManager.attachMeasuredRootView(this);
mIsAttachedToInstance = true;
getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
getViewTreeObserver().addOnGlobalLayoutListener(getKeyboardListener());
} else {
mAttachScheduled = true;
}
@@ -381,9 +380,23 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
mWasMeasured = true;
}
private KeyboardListener getKeyboardListener() {
if (mKeyboardListener == null) {
mKeyboardListener = new KeyboardListener();
}
return mKeyboardListener;
}
private class KeyboardListener implements ViewTreeObserver.OnGlobalLayoutListener {
private final Rect mVisibleViewArea;
private final int mMinKeyboardHeightDetected;
private int mKeyboardHeight = 0;
private final Rect mVisibleViewArea = new Rect();
/* package */ KeyboardListener() {
mVisibleViewArea = new Rect();
mMinKeyboardHeightDetected = (int) PixelUtil.toPixelFromDIP(60);
}
@Override
public void onGlobalLayout() {
@@ -397,8 +410,8 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea);
final int heightDiff =
DisplayMetricsHolder.getDisplayMetrics().heightPixels - mVisibleViewArea.bottom;
if (mKeyboardHeight != heightDiff && heightDiff > 0) {
DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom;
if (mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected) {
// keyboard is now showing, or the keyboard height has changed
mKeyboardHeight = heightDiff;
WritableMap params = Arguments.createMap();
@@ -409,9 +422,9 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
coordinates.putDouble("height", PixelUtil.toDIPFromPixel(mKeyboardHeight));
params.putMap("endCoordinates", coordinates);
sendEvent("keyboardDidShow", params);
} else if (mKeyboardHeight != 0 && heightDiff == 0) {
} else if (mKeyboardHeight != 0 && heightDiff <= mMinKeyboardHeightDetected) {
// keyboard is now hidden
mKeyboardHeight = heightDiff;
mKeyboardHeight = 0;
sendEvent("keyboardDidHide", null);
}
}
@@ -265,17 +265,6 @@ public class DevSupportManagerImpl implements DevSupportManager {
handleReloadJS();
}
});
options.put(
mDevSettings.isHotModuleReplacementEnabled()
? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
: mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
new DevOptionHandler() {
@Override
public void onOptionSelected() {
mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
handleReloadJS();
}
});
options.put(
mDevSettings.isReloadOnJSChangeEnabled()
? mApplicationContext.getString(R.string.catalyst_live_reload_off)
@@ -14,16 +14,39 @@ import android.util.DisplayMetrics;
/**
* Holds an instance of the current DisplayMetrics so we don't have to thread it through all the
* classes that need it.
* Note: windowDisplayMetrics are deprecated in favor of ScreenDisplayMetrics: window metrics
* are supposed to return the drawable area but there's no guarantee that they correspond to the
* actual size of the {@link ReactRootView}. Moreover, they are not consistent with what iOS
* returns. Screen metrics returns the metrics of the entire screen, is consistent with iOS and
* should be used instead.
*/
public class DisplayMetricsHolder {
private static DisplayMetrics sCurrentDisplayMetrics;
private static DisplayMetrics sWindowDisplayMetrics;
private static DisplayMetrics sScreenDisplayMetrics;
public static void setDisplayMetrics(DisplayMetrics displayMetrics) {
sCurrentDisplayMetrics = displayMetrics;
/**
* @deprecated Use {@link #setScreenDisplayMetrics(DisplayMetrics)} instead. See comment above as
* to why this is not correct to use.
*/
public static void setWindowDisplayMetrics(DisplayMetrics displayMetrics) {
sWindowDisplayMetrics = displayMetrics;
}
public static DisplayMetrics getDisplayMetrics() {
return sCurrentDisplayMetrics;
/**
* @deprecated Use {@link #getScreenDisplayMetrics()} instead. See comment above as to why this
* is not correct to use.
*/
@Deprecated
public static DisplayMetrics getWindowDisplayMetrics() {
return sWindowDisplayMetrics;
}
public static void setScreenDisplayMetrics(DisplayMetrics screenDisplayMetrics) {
sScreenDisplayMetrics = screenDisplayMetrics;
}
public static DisplayMetrics getScreenDisplayMetrics() {
return sScreenDisplayMetrics;
}
}
@@ -23,7 +23,7 @@ public class PixelUtil {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
value,
DisplayMetricsHolder.getDisplayMetrics());
DisplayMetricsHolder.getWindowDisplayMetrics());
}
/**
@@ -40,7 +40,7 @@ public class PixelUtil {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
value,
DisplayMetricsHolder.getDisplayMetrics());
DisplayMetricsHolder.getWindowDisplayMetrics());
}
/**
@@ -54,7 +54,7 @@ public class PixelUtil {
* Convert from PX to DP
*/
public static float toDIPFromPixel(float value) {
return value / DisplayMetricsHolder.getDisplayMetrics().density;
return value / DisplayMetricsHolder.getWindowDisplayMetrics().density;
}
}
@@ -11,22 +11,10 @@ package com.facebook.react.uimanager;
import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import com.facebook.csslayout.CSSLayoutContext;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.animation.Animation;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.OnBatchCompleteListener;
@@ -35,7 +23,6 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;
@@ -90,11 +77,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
UIImplementation uiImplementation) {
super(reactContext);
mEventDispatcher = new EventDispatcher(reactContext);
DisplayMetrics displayMetrics = getDisplayMetrics();
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
mModuleConstants = createConstants(displayMetrics, viewManagerList);
mModuleConstants = createConstants(viewManagerList);
mUIImplementation = uiImplementation;
reactContext.addLifecycleEventListener(this);
@@ -131,14 +114,10 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
mEventDispatcher.onCatalystInstanceDestroyed();
}
private static Map<String, Object> createConstants(
DisplayMetrics displayMetrics,
List<ViewManager> viewManagerList) {
private static Map<String, Object> createConstants(List<ViewManager> viewManagerList) {
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
try {
return UIManagerModuleConstantsHelper.createConstants(
displayMetrics,
viewManagerList);
return UIManagerModuleConstantsHelper.createConstants(viewManagerList);
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
@@ -460,39 +439,4 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
public void sendAccessibilityEvent(int tag, int eventType) {
mUIImplementation.sendAccessibilityEvent(tag, eventType);
}
private DisplayMetrics getDisplayMetrics() {
Context context = getReactApplicationContext();
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
// Get the real display metrics if we are using API level 17 or higher.
// The real metrics include system decor elements (e.g. soft menu bar).
//
// See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
if (Build.VERSION.SDK_INT >= 17){
display.getRealMetrics(displayMetrics);
} else {
// For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions.
// Since react-native only supports API level 16+ we don't have to worry about other cases.
//
// Reflection exceptions are rethrown at runtime.
//
// See: http://stackoverflow.com/questions/14341041/how-to-get-real-screen-height-and-width/23861333#23861333
try {
Method mGetRawH = Display.class.getMethod("getRawHeight");
Method mGetRawW = Display.class.getMethod("getRawWidth");
displayMetrics.widthPixels = (Integer) mGetRawW.invoke(display);
displayMetrics.heightPixels = (Integer) mGetRawH.invoke(display);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
throw new RuntimeException("Error getting real dimensions for API level < 17", e);
}
}
return displayMetrics;
}
}
@@ -12,7 +12,6 @@ package com.facebook.react.uimanager;
import java.util.HashMap;
import java.util.Map;
import android.text.InputType;
import android.util.DisplayMetrics;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
@@ -80,7 +79,7 @@ import com.facebook.react.uimanager.events.TouchEventType;
.build();
}
public static Map<String, Object> getConstants(DisplayMetrics displayMetrics) {
public static Map<String, Object> getConstants() {
HashMap<String, Object> constants = new HashMap<String, Object>();
constants.put(
"UIView",
@@ -92,6 +91,8 @@ import com.facebook.react.uimanager.events.TouchEventType;
"ScaleAspectFill",
ImageView.ScaleType.CENTER_CROP.ordinal())));
DisplayMetrics displayMetrics = DisplayMetricsHolder.getWindowDisplayMetrics();
DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics();
constants.put(
"Dimensions",
MapBuilder.of(
@@ -106,7 +107,19 @@ import com.facebook.react.uimanager.events.TouchEventType;
"fontScale",
displayMetrics.scaledDensity,
"densityDpi",
displayMetrics.densityDpi)));
displayMetrics.densityDpi),
"screenPhysicalPixels",
MapBuilder.of(
"width",
screenDisplayMetrics.widthPixels,
"height",
screenDisplayMetrics.heightPixels,
"scale",
screenDisplayMetrics.density,
"fontScale",
screenDisplayMetrics.scaledDensity,
"densityDpi",
screenDisplayMetrics.densityDpi)));
constants.put(
"StyleConstants",
@@ -9,12 +9,9 @@
package com.facebook.react.uimanager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.util.DisplayMetrics;
import com.facebook.react.common.MapBuilder;
/**
@@ -39,10 +36,8 @@ import com.facebook.react.common.MapBuilder;
* {@link UIManagerModuleConstants}.
* TODO(6845124): Create a test for this
*/
/* package */ static Map<String, Object> createConstants(
DisplayMetrics displayMetrics,
List<ViewManager> viewManagers) {
Map<String, Object> constants = UIManagerModuleConstants.getConstants(displayMetrics);
/* package */ static Map<String, Object> createConstants(List<ViewManager> viewManagers) {
Map<String, Object> constants = UIManagerModuleConstants.getConstants();
Map bubblingEventTypesConstants = UIManagerModuleConstants.getBubblingEventTypeConstants();
Map directEventTypesConstants = UIManagerModuleConstants.getDirectEventTypeConstants();
@@ -17,7 +17,6 @@ import android.graphics.Paint;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.ReactShadowNode;
@@ -39,7 +38,7 @@ public abstract class ARTVirtualNode extends ReactShadowNode {
protected final float mScale;
public ARTVirtualNode() {
mScale = DisplayMetricsHolder.getDisplayMetrics().density;
mScale = DisplayMetricsHolder.getWindowDisplayMetrics().density;
}
@Override
@@ -29,18 +29,17 @@ import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.JSApplicationCausedNativeException;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.BaseViewManager;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewDefaults;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.views.text.DefaultStyleValuesUtil;
import com.facebook.react.views.text.ReactTextUpdate;
@@ -82,7 +82,7 @@ public class RootViewTest {
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
mReactContext.initializeWithInstance(mCatalystInstanceMock);
DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
@@ -54,12 +54,14 @@ public class LayoutPropertyApplicatorTest {
@Before
public void setup() {
DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics());
DisplayMetricsHolder.setScreenDisplayMetrics(new DisplayMetrics());
}
@After
public void teardown() {
DisplayMetricsHolder.setDisplayMetrics(null);
DisplayMetricsHolder.setWindowDisplayMetrics(null);
DisplayMetricsHolder.setScreenDisplayMetrics(null);
}
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
@@ -309,7 +311,7 @@ public class LayoutPropertyApplicatorTest {
public void testPropertiesResetToDefault() {
DisplayMetrics displayMetrics = new DisplayMetrics();
displayMetrics.density = 1.0f;
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
ReactStylesDiffMap map = buildStyles(
@@ -13,6 +13,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import android.util.DisplayMetrics;
import android.view.View;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -145,6 +146,9 @@ public class ReactPropConstantsTest {
public void testNativePropsIncludeCorrectTypes() {
List<ViewManager> viewManagers = Arrays.<ViewManager>asList(new ViewManagerUnderTest());
ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
UIManagerModule uiManagerModule = new UIManagerModule(
reactContext,
viewManagers,
@@ -13,6 +13,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import android.util.DisplayMetrics;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.MapBuilder;
@@ -56,6 +58,10 @@ public class UIManagerModuleConstantsTest {
public void setUp() {
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
mUIImplementation = mock(UIImplementation.class);
DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
}
@Test
@@ -14,6 +14,7 @@ import java.util.Arrays;
import java.util.List;
import android.graphics.Color;
import android.util.DisplayMetrics;
import android.view.Choreographer;
import android.view.View;
import android.view.ViewGroup;
@@ -107,9 +108,14 @@ public class UIManagerModuleTest {
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
mReactContext.initializeWithInstance(mCatalystInstanceMock);
DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
.thenReturn(uiManagerModuleMock);
}
@Test
@@ -59,12 +59,12 @@ public class ReactImagePropertyTest {
mContext.initializeWithInstance(mCatalystInstanceMock);
mThemeContext = new ThemedReactContext(mContext, mContext);
Fresco.initialize(mContext);
DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics());
}
@After
public void teardown() {
DisplayMetricsHolder.setDisplayMetrics(null);
DisplayMetricsHolder.setWindowDisplayMetrics(null);
}
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
@@ -21,6 +21,7 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.text.style.AbsoluteSizeSpan;
import android.view.Choreographer;
import android.widget.TextView;
@@ -31,6 +32,7 @@ import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.ReactChoreographer;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIManagerModule;
@@ -371,6 +373,9 @@ public class ReactTextTest {
public UIManagerModule getUIManagerModule() {
ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
List<ViewManager> viewManagers = Arrays.asList(
new ViewManager[] {
new ReactTextViewManager(),
@@ -60,7 +60,7 @@ public class ReactTextInputPropertyTest {
mContext.initializeWithInstance(mCatalystInstanceMock);
mThemedContext = new ThemedReactContext(mContext, mContext);
mManager = new ReactTextInputManager();
DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics());
}
public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.util.DisplayMetrics;
import android.view.Choreographer;
import android.widget.EditText;
@@ -22,6 +23,7 @@ import com.facebook.react.bridge.ReactTestHelper;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.ReactChoreographer;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIManagerModule;
@@ -181,6 +183,9 @@ public class TextInputTest {
new ViewManager[] {
new ReactTextInputManager(),
});
DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
UIManagerModule uiManagerModule = new UIManagerModule(
reactContext,
viewManagers,
+1
View File
@@ -36,6 +36,7 @@ module.exports = {
'transform-react-jsx',
'transform-regenerator',
['transform-es2015-for-of', { loose: true }],
require('../transforms/transform-symbol-member'),
]),
retainLines: true,
sourceMaps: false,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "babel-preset-react-native",
"version": "1.2.4",
"version": "1.4.0",
"description": "Babel preset for React Native applications",
"main": "index.js",
"repository": "https://github.com/facebook/react-native/tree/master/babel-preset",
@@ -0,0 +1,61 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*/
'use strict';
/*eslint consistent-return: 0*/
/**
* Transforms function properties of the `Symbol` into
* the presence check, and fallback string "@@<name>".
*
* Example:
*
* Symbol.iterator;
*
* Transformed to:
*
* typeof Symbol.iterator === 'function' ? Symbol.iterator : '@@iterator';
*/
module.exports = function symbolMember(babel) {
const t = babel.types;
return {
visitor: {
MemberExpression(path) {
let node = path.node;
if (!isAppropriateMember(node)) {
return;
}
path.replaceWith(
t.conditionalExpression(
t.binaryExpression(
'===',
t.unaryExpression(
'typeof',
t.identifier('Symbol'),
true
),
t.stringLiteral('function')
),
node,
t.stringLiteral(`@@${node.property.name}`)
)
);
// We should stop to avoid infinite recursion, since Babel
// traverses replaced path, and again would hit our transform.
path.stop();
},
},
};
};
function isAppropriateMember(node) {
return node.object.type === 'Identifier' &&
node.object.name === 'Symbol' &&
node.property.type === 'Identifier';
}
+34 -16
View File
@@ -13,23 +13,28 @@ machine:
dependencies:
pre:
# BUCK
- if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
- cd buck && ant
- buck/bin/buck --version
- buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
- buck/bin/buck fetch ReactAndroid/src/test/...
- buck/bin/buck fetch ReactAndroid/src/androidTest/...
# using npm@3 because of problems with shrink-wrapped optional deps installs on linux
- npm install -g npm@3.2
- source scripts/circle-ci-android-setup.sh && getAndroidSDK
- ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
# BUCK
- if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
- cd buck && ant
- buck/bin/buck --version
- buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react
- buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
- buck/bin/buck fetch ReactAndroid/src/test/...
- buck/bin/buck fetch ReactAndroid/src/androidTest/...
# using npm@3 because of problems with shrink-wrapped optional deps installs on linux
- npm install -g npm@3.2
- source scripts/circle-ci-android-setup.sh && getAndroidSDK
- ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
- cd website && npm install
cache_directories:
- "ReactAndroid/build/downloads"
- "buck"
- "buck-out/bin"
- "ReactAndroid/build/downloads"
- "buck"
- "buck-out/bin"
- "website/node_modules"
override:
- npm install
test:
pre:
# starting emulator in advance because it takes very long to boot
@@ -39,6 +44,7 @@ test:
- ./gradlew :ReactAndroid:assembleDebug -PdisablePreDex -Pjobs=1:
timeout: 360
- source scripts/circle-ci-android-setup.sh && waitForAVD
override:
# buck tests
- buck/bin/buck test ReactAndroid/src/test/... --config build.threads=1
@@ -55,9 +61,21 @@ test:
# run tests on the emulator
- ./gradlew :ReactAndroid:connectedAndroidTest -PdisablePreDex --stacktrace --info:
timeout: 360
# testing docs generation is not broken
- cd website && node ./server/generate.js
post:
# copy test report for Circle CI to display
- mkdir -p $CIRCLE_TEST_REPORTS/junit/
- find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
- find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
deployment:
website:
branch: [/.*-stable/, /master/]
commands:
# generate docs website
- git config --global user.email "bestnader@fb.com"
- git config --global user.name "Website Deployment Script"
- echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
- cd website && GIT_USER=reactjs-bot npm run gh-pages
+12 -12
View File
@@ -43,7 +43,7 @@ Once the trace starts collecting, perform the animation or interaction you care
After opening the trace in your browser (preferably Chrome), you should see something like this:
![Example](/react-native/img/SystraceExample.png)
![Example](img/SystraceExample.png)
**HINT**: Use the WASD keys to strafe and zoom
@@ -51,7 +51,7 @@ After opening the trace in your browser (preferably Chrome), you should see some
The first thing you should do is highlight the 16ms frame boundaries if you haven't already done that. Check this checkbox at the top right of the screen:
![Enable VSync Highlighting](/react-native/img/SystraceHighlightVSync.png)
![Enable VSync Highlighting](img/SystraceHighlightVSync.png)
You should see zebra stripes as in the screenshot above. If you don't, try profiling on a different device: Samsung has been known to have issues displaying vsyncs while the Nexus series is generally pretty reliable.
@@ -65,43 +65,43 @@ On the left side, you'll see a set of threads which correspond to the timeline r
This is where standard android measure/layout/draw happens. The thread name on the right will be your package name (in my case book.adsmanager) or UI Thread. The events that you see on this thread should look something like this and have to do with `Choreographer`, `traversals`, and `DispatchUI`:
![UI Thread Example](/react-native/img/SystraceUIThreadExample.png)
![UI Thread Example](img/SystraceUIThreadExample.png)
### JS Thread
This is where JS is executed. The thread name will be either `mqt_js` or `<...>` depending on how cooperative the kernel on your device is being. To identify it if it doesn't have a name, look for things like `JSCall`, `Bridge.executeJSCall`, etc:
![JS Thread Example](/react-native/img/SystraceJSThreadExample.png)
![JS Thread Example](img/SystraceJSThreadExample.png)
### Native Modules Thread
This is where native module calls (e.g. the `UIManager`) are executed. The thread name will be either `mqt_native_modules` or `<...>`. To identify it in the latter case, look for things like `NativeCall`, `callJavaModuleMethod`, and `onBatchComplete`:
![Native Modules Thread Example](/react-native/img/SystraceNativeModulesThreadExample.png)
![Native Modules Thread Example](img/SystraceNativeModulesThreadExample.png)
### Bonus: Render Thread
If you're using Android L (5.0) and up, you will also have a render thread in your application. This thread generates the actual OpenGL commands used to draw your UI. The thread name will be either `RenderThread` or `<...>`. To identify it in the latter case, look for things like `DrawFrame` and `queueBuffer`:
![Render Thread Example](/react-native/img/SystraceRenderThreadExample.png)
![Render Thread Example](img/SystraceRenderThreadExample.png)
## Identifying a culprit
A smooth animation should look something like the following:
![Smooth Animation](/react-native/img/SystraceWellBehaved.png)
![Smooth Animation](img/SystraceWellBehaved.png)
Each change in color is a frame -- remember that in order to display a frame, all our UI work needs to be done by the end of that 16ms period. Notice that no thread is working close to the frame boundary. An application rendering like this is rendering at 60FPS.
If you noticed chop, however, you might see something like this:
![Choppy Animation from JS](/react-native/img/SystraceBadJS.png)
![Choppy Animation from JS](img/SystraceBadJS.png)
Notice that the JS thread is executing basically all the time, and across frame boundaries! This app is not rendering at 60FPS. In this case, **the problem lies in JS**.
You might also see something like this:
![Choppy Animation from UI](/react-native/img/SystraceBadUI.png)
![Choppy Animation from UI](img/SystraceBadUI.png)
In this case, the UI and render threads are the ones that have work crossing frame boundaries. The UI that we're trying to render on each frame is requiring too much work to be done. In this case, **the problem lies in the native views being rendered**.
@@ -111,7 +111,7 @@ At this point, you'll have some very helpful information to inform your next ste
If you identified a JS problem, look for clues in the specific JS that you're executing. In the scenario above, we see `RCTEventEmitter` being called multiple times per frame. Here's a zoom-in of the JS thread from the trace above:
![Too much JS](/react-native/img/SystraceBadJS2.png)
![Too much JS](img/SystraceBadJS2.png)
This doesn't seem right. Why is it being called so often? Are they actually different events? The answers to these questions will probably depend on your product code. And many times, you'll want to look into [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate).
@@ -128,7 +128,7 @@ If you identified a native UI problem, there are usually two scenarios:
In the first scenario, you'll see a trace that has the UI thread and/or Render Thread looking like this:
![Overloaded GPU](/react-native/img/SystraceBadUI.png)
![Overloaded GPU](img/SystraceBadUI.png)
Notice the long amount of time spent in `DrawFrame` that crosses frame boundaries. This is time spent waiting for the GPU to drain its command buffer from the previous frame.
@@ -143,7 +143,7 @@ If these don't help and you want to dig deeper into what the GPU is actually doi
In the second scenario, you'll see something more like this:
![Creating Views](/react-native/img/SystraceBadCreateUI.png)
![Creating Views](img/SystraceBadCreateUI.png)
Notice that first the JS thread thinks for a bit, then you see some work done on the native modules thread, followed by an expensive traversal on the UI thread.
+9 -9
View File
@@ -267,7 +267,7 @@ it provides much less control than `Animated` and other animation libraries, so
you may need to use another approach if you can't get `LayoutAnimation` to do
what you want.
![](/react-native/img/LayoutAnimationExample.gif)
![](img/LayoutAnimationExample.gif)
```javascript
var App = React.createClass({
@@ -376,7 +376,7 @@ var App = React.createClass({
```
[Run this example](https://rnplay.org/apps/4FUQ-A)
![](/react-native/img/TweenState.gif)
![](img/TweenState.gif)
Here we animated the opacity, but as you might guess, we can animate any
numeric value. Read more about react-tween-state in its
@@ -395,7 +395,7 @@ value and end value. Rebound [is used
internally](https://github.com/facebook/react-native/search?utf8=%E2%9C%93&q=rebound)
by React Native on `Navigator` and `WarningBox`.
![](/react-native/img/ReboundImage.gif)
![](img/ReboundImage.gif)
Notice that Rebound animations can be interrupted - if you release in
the middle of a press, it will animate back from the current state to
@@ -440,7 +440,7 @@ var App = React.createClass({
transform: [{scaleX: this.state.scale}, {scaleY: this.state.scale}],
};
var imageUri = "https://facebook.github.io/react-native/img/ReboundExample.png";
var imageUri = "img/ReboundExample.png";
return (
<View style={styles.container}>
@@ -461,13 +461,13 @@ oscillate around the end value. In the above example, we would add
See the below gif for an example of where in your interface you might
use this.
![](/react-native/img/Rebound.gif) Screenshot from
![](img/Rebound.gif) Screenshot from
[react-native-scrollable-tab-view](https://github.com/brentvatne/react-native-scrollable-tab-view).
You can run a similar example [here](https://rnplay.org/apps/qHU_5w).
#### A sidenote about setNativeProps
As mentioned [in the Direction Manipulation section](/react-native/docs/direct-manipulation.html),
As mentioned [in the Direction Manipulation section](docs/direct-manipulation.html),
`setNativeProps` allows us to modify properties of native-backed
components (components that are actually backed by native views, unlike
composite components) directly, without having to `setState` and
@@ -497,7 +497,7 @@ render: function() {
<View style={styles.container}>
<TouchableWithoutFeedback onPressIn={this._onPressIn} onPressOut={this._onPressOut}>
<Image ref={component => this._photo = component}
source={{uri: "https://facebook.github.io/react-native/img/ReboundExample.png"}}
source={{uri: "img/ReboundExample.png"}}
style={{width: 250, height: 200}} />
</TouchableWithoutFeedback>
</View>
@@ -516,14 +516,14 @@ frames per second), look into using `setNativeProps` or
`shouldComponentUpdate` to optimize them. You may also want to defer any
computationally intensive work until after animations are complete,
using the
[InteractionManager](/react-native/docs/interactionmanager.html). You
[InteractionManager](docs/interactionmanager.html). You
can monitor the frame rate by using the In-App Developer Menu "FPS
Monitor" tool.
### Navigator Scene Transitions
As mentioned in the [Navigator
Comparison](https://facebook.github.io/react-native/docs/navigator-comparison.html#content),
Comparison](docs/navigator-comparison.html#content),
`Navigator` is implemented in JavaScript and `NavigatorIOS` is a wrapper
around native functionality provided by `UINavigationController`, so
these scene transitions apply only to `Navigator`. In order to re-create
+6 -6
View File
@@ -7,7 +7,7 @@ permalink: docs/communication-ios.html
next: native-modules-android
---
In [Integrating with Existing Apps guide](http://facebook.github.io/react-native/docs/embedded-app-ios.html) and [Native UI Components guide](https://facebook.github.io/react-native/docs/native-components-ios.html) we learn how to embed React Native in a native component and vice versa. When we mix native and React Native components, we'll eventually find a need to communicate between these two worlds. Some ways to achieve that have been already mentioned in other guides. This article summarizes available techniques.
In [Integrating with Existing Apps guide](docs/embedded-app-ios.html) and [Native UI Components guide](docs/native-components-ios.html) we learn how to embed React Native in a native component and vice versa. When we mix native and React Native components, we'll eventually find a need to communicate between these two worlds. Some ways to achieve that have been already mentioned in other guides. This article summarizes available techniques.
## Introduction
@@ -80,13 +80,13 @@ There is no way to update only a few properties at a time. We suggest that you b
> Currently, JS functions `componentWillReceiveProps` and `componentWillUpdateProps` of the top level RN component will not be called after a prop update. However, you can access the new props in `componentWillMount` function.
### Passing properties from React Native to native
The problem exposing properties of native components is covered in detail in [this article](https://facebook.github.io/react-native/docs/native-components-ios.html#properties). In short, export properties with `RCT_CUSTOM_VIEW_PROPERTY` macro in your custom native component, then just use them in React Native as if the component was an ordinary React Native component.
The problem exposing properties of native components is covered in detail in [this article](docs/native-components-ios.html#properties). In short, export properties with `RCT_CUSTOM_VIEW_PROPERTY` macro in your custom native component, then just use them in React Native as if the component was an ordinary React Native component.
### Limits of properties
The main drawback of cross-language properties is that they do not support callbacks, which would allow us to handle bottom-up data bindings. Imagine you have a small RN view that you want to be removed from the native parent view as a result of a JS action. There is no way to do that with props, as the information would need to go bottom-up.
Although we have a flavor of cross-language callbacks ([described here](https://facebook.github.io/react-native/docs/native-modules-ios.html#callbacks)), these callbacks are not always the thing we need. The main problem is that they are not intended to be passed as properties. Rather, this mechanism allows us to trigger a native action from JS, and handle the result of that action in JS.
Although we have a flavor of cross-language callbacks ([described here](docs/native-modules-ios.html#callbacks)), these callbacks are not always the thing we need. The main problem is that they are not intended to be passed as properties. Rather, this mechanism allows us to trigger a native action from JS, and handle the result of that action in JS.
## Other ways of cross-language interaction (events and native modules)
@@ -96,7 +96,7 @@ React Native enables you to perform cross-language function calls. You can execu
### Calling React Native functions from native (events)
Events are described in detail in [this article](http://facebook.github.io/react-native/docs/native-components-ios.html#events). Note that using events gives us no guarantees about execution time, as the event is handled on a separate thread.
Events are described in detail in [this article](docs/native-components-ios.html#events). Note that using events gives us no guarantees about execution time, as the event is handled on a separate thread.
Events are powerful, because they allow us to change React Native components without needing a reference to them. However, there are some pitfalls that you can fall into while using them:
@@ -108,7 +108,7 @@ The common pattern we use when embedding native in React Native is to make the n
### Calling native functions from React Native (native modules)
Native modules are Objective-C classes that are available in JS. Typically one instance of each module is created per JS bridge. They can export arbitrary functions and constants to React Native. They have been covered in detail in [this article](https://facebook.github.io/react-native/docs/native-modules-ios.html#content).
Native modules are Objective-C classes that are available in JS. Typically one instance of each module is created per JS bridge. They can export arbitrary functions and constants to React Native. They have been covered in detail in [this article](docs/native-modules-ios.html#content).
The fact that native modules are singletons limits the mechanism in context of embedding. Let's say we have a React Native component embedded in a native view and we want to update the native, parent view. Using the native module mechanism, we would export a function that not only takes expected arguments, but also an identifier of the parent native view. The identifier would be used to retrieve a reference to the parent view to update. That said, we would need to keep a mapping from identifiers to native views in the module.
@@ -125,7 +125,7 @@ When integrating native and React Native, we also need a way to consolidate two
### Layout of a native component embedded in React Native
This case is covered in [this article](https://facebook.github.io/react-native/docs/native-components-ios.html#styles). Basically, as all our native react views are subclasses of `UIView`, most style and size attributes will work like you would expect out of the box.
This case is covered in [this article](docs/native-components-ios.html#styles). Basically, as all our native react views are subclasses of `UIView`, most style and size attributes will work like you would expect out of the box.
### Layout of a React Native component embedded in native
+2 -2
View File
@@ -55,7 +55,7 @@ React Native Android use [gradle](https://docs.gradle.org) as a build system. We
* Android Support Repository
2. Click "Install Packages"
![SDK Manager window](/react-native/img/AndroidSDK1.png) ![SDK Manager window](/react-native/img/AndroidSDK2.png)
![SDK Manager window](img/AndroidSDK1.png) ![SDK Manager window](img/AndroidSDK2.png)
### Install Genymotion
@@ -75,7 +75,7 @@ Genymotion is much easier to set up than stock Google emulators. However, it's o
3. [Configure hardware acceleration (HAXM)](http://developer.android.com/tools/devices/emulator.html#vm-mac), otherwise the emulator is going to be slow.
4. Create an Android Virtual Device (AVD):
1. Run `android avd` and click on **Create...**
![Create AVD dialog](/react-native/img/CreateAVD.png)
![Create AVD dialog](img/CreateAVD.png)
2. With the new AVD selected, click `Start...`
5. To bring up the developer menu press F2 (or install [Frappé](http://getfrappe.com))
+1 -1
View File
@@ -156,7 +156,7 @@ view using `{...this.props}`. The reason for this is that
`TouchableOpacity` is actually a composite component, and so in addition
to depending on `setNativeProps` on its child, it also requires that the
child perform touch handling. To do this, it passes on [various
props](https://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder)
props](docs/view.html#onmoveshouldsetresponder)
that call back to the `TouchableOpacity` component.
`TouchableHighlight`, in contrast, is backed by a native view and only
requires that we implement `setNativeProps`.
+1 -1
View File
@@ -166,7 +166,7 @@ To run your app, you need to first start the development server. To do this, sim
Now build and run your Android app as normal (e.g. `./gradlew installDebug`). Once you reach your React-powered activity inside the app, it should load the JavaScript code from the development server and display:
![Screenshot](/react-native/img/EmbeddedAppAndroid.png)
![Screenshot](img/EmbeddedAppAndroid.png)
## Sharing a ReactInstance across multiple Activities / Fragments in your app
+2 -2
View File
@@ -98,7 +98,7 @@ React.AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
You should now add a container view for the React Native component. It can be any `UIView` in your app.
![Container view example](/react-native/img/EmbeddedAppContainerViewExample.png)
![Container view example](img/EmbeddedAppContainerViewExample.png)
However, let's subclass `UIView` for the sake of clean code. Let's name it `ReactView`. Open up `Yourproject.xcworkspace` and create a new class `ReactView` (You can name it whatever you like :)).
@@ -186,7 +186,7 @@ If you don't do this, you will see the error - `Could not connect to development
Now compile and run your app. You shall now see your React Native app running inside of the `ReactView`.
![Example](/react-native/img/EmbeddedAppExample.png)
![Example](img/EmbeddedAppExample.png)
Live reload and all of the debugging tools will work from the simulator (make sure that DEBUG=1 is set under Build Settings -> Preprocessor Macros). You've got a simple React component totally encapsulated behind an Objective-C `UIView` subclass.
+1 -1
View File
@@ -68,4 +68,4 @@ However, sometimes a parent will want to make sure that it becomes responder. Th
### PanResponder
For higher-level gesture interpretation, check out [PanResponder](/react-native/docs/panresponder.html).
For higher-level gesture interpretation, check out [PanResponder](docs/panresponder.html).
+5 -5
View File
@@ -25,9 +25,9 @@ We recommend periodically running `brew update && brew upgrade` to keep your pro
## Android Setup
To write React Native apps for Android, you will need to install the Android SDK (and an Android emulator if you want to work on your app without having to use a physical device). See [Android setup guide](android-setup.html) for instructions on how to set up your Android environment.
To write React Native apps for Android, you will need to install the Android SDK (and an Android emulator if you want to work on your app without having to use a physical device). See [Android setup guide](docs/android-setup.html) for instructions on how to set up your Android environment.
_NOTE:_ There is experimental [Windows and Linux support](/react-native/docs/linux-windows-support.html) for Android development.
_NOTE:_ There is experimental [Windows and Linux support](docs/linux-windows-support.html) for Android development.
## Quick start
@@ -41,7 +41,7 @@ _NOTE:_ There is experimental [Windows and Linux support](/react-native/docs/lin
- Open `index.ios.js` in your text editor of choice and edit some lines.
- Hit ⌘-R in your iOS simulator to reload the app and see your change!
_Note: If you are using an iOS device, see the [Running on iOS Device page](http://facebook.github.io/react-native/docs/running-on-device-ios.html#content)._
_Note: If you are using an iOS device, see the [Running on iOS Device page](docs/running-on-device-ios.html#content)._
**To run the Android app:**
@@ -51,11 +51,11 @@ _Note: If you are using an iOS device, see the [Running on iOS Device page](http
- Press the menu button (F2 by default, or ⌘-M in Genymotion) and select *Reload JS* to see your change!
- Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to see your app's logs
_Note: If you are using an Android device, see the [Running on Android Device page](http://facebook.github.io/react-native/docs/running-on-device-android.html#content)._
_Note: If you are using an Android device, see the [Running on Android Device page](docs/running-on-device-android.html#content)._
Congratulations! You've successfully run and modified your first React Native app.
_If you run into any issues getting started, see the [troubleshooting page](/react-native/docs/troubleshooting.html#content)._
_If you run into any issues getting started, see the [troubleshooting page](docs/troubleshooting.html#content)._
## Adding Android to an existing React Native project
+1 -1
View File
@@ -90,7 +90,7 @@ Many of the images you will display in your app will not be available at compile
## Local Filesystem Images
See [CameraRoll](/react-native/docs/cameraroll.html) for an example of
See [CameraRoll](docs/cameraroll.html) for an example of
using local resources that are outside of `Images.xcassets`.
### Best Camera Roll Image
+2 -2
View File
@@ -38,7 +38,7 @@ PushNotificationIOS
### Some props are only supported on one platform
There are properties that work on one platform only, either because they can inherently only be supported on that platform or because they haven't been implemented on the other platforms yet. All of these are annotated with `@platform` in JS docs and have a small badge next to them on the website. See e.g. [Image](https://facebook.github.io/react-native/docs/image.html).
There are properties that work on one platform only, either because they can inherently only be supported on that platform or because they haven't been implemented on the other platforms yet. All of these are annotated with `@platform` in JS docs and have a small badge next to them on the website. See e.g. [Image](docs/image.html).
### Platform parity
@@ -62,7 +62,7 @@ Another issue with `overflow: 'hidden'` on Android: a view is not clipped by the
### View shadows
The `shadow*` [view styles](/react-native/docs/view.html#style) apply on iOS, and the `elevation` view prop is available on Android. Setting `elevation` on Android is equivalent to using the [native elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation), and has the same limitations (most significantly, it only works on Android 5.0+). Setting `elevation` on Android also affects the z-order for overlapping views.
The `shadow*` [view styles](docs/view.html#style) apply on iOS, and the `elevation` view prop is available on Android. Setting `elevation` on Android is equivalent to using the [native elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation), and has the same limitations (most significantly, it only works on Android 5.0+). Setting `elevation` on Android also affects the z-order for overlapping views.
### Android M permissions
+3 -3
View File
@@ -65,7 +65,7 @@ folder.
Drag this file to your project on Xcode (usually under the `Libraries` group
on Xcode);
![](/react-native/img/AddToLibraries.png)
![](img/AddToLibraries.png)
#### Step 2
@@ -73,7 +73,7 @@ Click on your main project file (the one that represents the `.xcodeproj`)
select `Build Phases` and drag the static library from the `Products` folder
inside the Library you are importing to `Link Binary With Libraries`
![](/react-native/img/AddToBuildPhases.png)
![](img/AddToBuildPhases.png)
#### Step 3
@@ -97,4 +97,4 @@ Paths`. There you should include the path to your library (if it has relevant
files on subdirectories remember to make it `recursive`, like `React` on the
example).
![](/react-native/img/AddToSearchPaths.png)
![](img/AddToSearchPaths.png)
+2 -2
View File
@@ -7,8 +7,8 @@ permalink: docs/navigator-comparison.html
next: known-issues
---
The differences between [Navigator](/react-native/docs/navigator.html)
and [NavigatorIOS](/react-native/docs/navigatorios.html) are a common
The differences between [Navigator](docs/navigator.html)
and [NavigatorIOS](docs/navigatorios.html) are a common
source of confusion for newcomers.
Both `Navigator` and `NavigatorIOS` are components that allow you to
+1 -1
View File
@@ -72,7 +72,7 @@ out of the box than `Navigator`. The reason for this is that the
animations for the transitions are done entirely on the main thread, and
so they are not interrupted by frame drops on the JavaScript thread.
([Read about why you should probably use Navigator
anyways.](/react-native/docs/navigator-comparison.html))
anyways.](docs/navigator-comparison.html))
Similarly, you can happily scroll up and down through a ScrollView when
the JavaScript thread is locked up because the ScrollView lives on the
+1 -1
View File
@@ -31,7 +31,7 @@ When you run your app on device, we pack all the JavaScript code and the images
## Disabling in-app developer menu
When building your app for production, your app's scheme should be set to `Release` as detailed in [the debugging documentation](/react-native/docs/debugging.html#debugging-react-native-apps) in order to disable the in-app developer menu.
When building your app for production, your app's scheme should be set to `Release` as detailed in [the debugging documentation](docs/debugging.html#debugging-react-native-apps) in order to disable the in-app developer menu.
## Troubleshooting
+1 -1
View File
@@ -78,7 +78,7 @@ If you need to change the way the JavaScript bundle and/or drawable resources ar
#### If you *don't* have a `react.gradle` file:
You can [upgrade](/react-native/docs/upgrading.html) to the latest version of React Native to get this file. Alternatively, you can bundle the JavaScript package and drawable resources manually by doing the following in a terminal:
You can [upgrade](docs/upgrading.html) to the latest version of React Native to get this file. Alternatively, you can bundle the JavaScript package and drawable resources manually by doing the following in a terminal:
```sh
$ mkdir -p android/app/src/main/assets
+6 -6
View File
@@ -33,7 +33,7 @@ var styles = StyleSheet.create({
`StyleSheet.create` construct is optional but provides some key advantages. It ensures that the values are **immutable** and **opaque** by transforming them into plain numbers that reference an internal table. By putting it at the end of the file, you also ensure that they are only created once for the application and not on every render.
All the attribute names and values are a subset of what works on the web. For layout, React Native implements [Flexbox](/react-native/docs/flexbox.html).
All the attribute names and values are a subset of what works on the web. For layout, React Native implements [Flexbox](docs/flexbox.html).
## Using Styles
@@ -95,8 +95,8 @@ var List = React.createClass({
You can checkout latest support of CSS Properties in following Links.
- [View Properties](/react-native/docs/view.html#style)
- [Image Properties](/react-native/docs/image.html#style)
- [Text Properties](/react-native/docs/text.html#style)
- [Flex Properties](/react-native/docs/flexbox.html#content)
- [Transform Properties](/react-native/docs/transforms.html#content)
- [View Properties](docs/view.html#style)
- [Image Properties](docs/image.html#style)
- [Text Properties](docs/text.html#style)
- [Flex Properties](docs/flexbox.html#content)
- [Transform Properties](docs/transforms.html#content)
+1 -1
View File
@@ -78,7 +78,7 @@ pod 'React', :path => '../node_modules/react-native', :subspecs => [
```
Next, make sure you have run `pod install` and that a `Pods/` directory has been created in your project with React installed. CocoaPods will instruct you to use the generated `.xcworkspace` file henceforth to be able to use these installed dependencies.
If you are adding React manually, make sure you have included all the relevant dependencies, like `RCTText.xcodeproj`, `RCTImage.xcodeproj` depending on the ones you are using. Next, the binaries built by these dependencies have to be linked to your app binary. Use the `Linked Frameworks and Binaries` section in the Xcode project settings. More detailed steps are here: [Linking Libraries](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#content).
If you are adding React manually, make sure you have included all the relevant dependencies, like `RCTText.xcodeproj`, `RCTImage.xcodeproj` depending on the ones you are using. Next, the binaries built by these dependencies have to be linked to your app binary. Use the `Linked Frameworks and Binaries` section in the Xcode project settings. More detailed steps are here: [Linking Libraries](docs/linking-libraries-ios.html#content).
##### Argument list too long: recursive header expansion failed
+9 -9
View File
@@ -16,7 +16,7 @@ We assume you have experience writing applications with React. If not, you can l
## Setup
React Native requires the basic setup explained at [React Native Getting Started](https://facebook.github.io/react-native/docs/getting-started.html#content).
React Native requires the basic setup explained at [React Native Getting Started](docs/getting-started.html#content).
After installing these dependencies there are two simple commands to get a React Native project all set up for development.
@@ -111,8 +111,8 @@ And lastly we need to apply this style to the Image component:
Press `⌘+R` / `Reload JS` and the image should now render.
<div class="tutorial-mock">
<img src="/react-native/img/TutorialMock.png" />
<img src="/react-native/img/TutorialMock2.png" />
<img src="img/TutorialMock.png" />
<img src="img/TutorialMock2.png" />
</div>
@@ -189,8 +189,8 @@ Styling the text is pretty straightforward:
Go ahead and press `⌘+R` / `Reload JS` and you'll see the updated view.
<div class="tutorial-mock">
<img src="/react-native/img/TutorialStyledMock.png" />
<img src="/react-native/img/TutorialStyledMock2.png" />
<img src="img/TutorialStyledMock.png" />
<img src="img/TutorialStyledMock2.png" />
</div>
### Fetching real data
@@ -282,8 +282,8 @@ Now modify the render function to render a loading view if we don't have any mov
Now press `⌘+R` / `Reload JS` and you should see "Loading movies..." until the response comes back, then it will render the first movie it fetched from Rotten Tomatoes.
<div class="tutorial-mock">
<img src="/react-native/img/TutorialSingleFetched.png" />
<img src="/react-native/img/TutorialSingleFetched2.png" />
<img src="img/TutorialSingleFetched.png" />
<img src="img/TutorialSingleFetched2.png" />
</div>
## ListView
@@ -367,8 +367,8 @@ Finally, we add styles for the `ListView` component to the `styles` JS object:
And here's the final result:
<div class="tutorial-mock">
<img src="/react-native/img/TutorialFinal.png" />
<img src="/react-native/img/TutorialFinal2.png" />
<img src="img/TutorialFinal.png" />
<img src="img/TutorialFinal2.png" />
</div>
There's still some work to be done to make it a fully functional app such as: adding navigation, search, infinite scroll loading, etc. Check the [Movies Example](https://github.com/facebook/react-native/tree/master/Examples/Movies) to see it all working.
+1 -1
View File
@@ -50,7 +50,7 @@ Xcode project format is pretty complex and sometimes it's tricky to upgrade and
### From 0.13 to 0.14
The major change in this version happened to the CLI ([see changelog](https://github.com/facebook/react-native/releases/tag/v0.14.0-rc)) and static images ([see docs](http://facebook.github.io/react-native/docs/images.html)). To use the new asset system in existing Xcode project, do the following:
The major change in this version happened to the CLI ([see changelog](https://github.com/facebook/react-native/releases/tag/v0.14.0-rc)) and static images ([see docs](docs/images.html)). To use the new asset system in existing Xcode project, do the following:
Add new "Run Script" step to your project's build phases:
@@ -73,7 +73,7 @@ def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = true
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 23
@@ -121,5 +121,5 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.13.0"
compile "com.facebook.react:react-native:0.20.+"
}
@@ -42,8 +42,8 @@
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "react-native",
"version": "0.0.0-master",
"version": "0.20.0",
"description": "A framework for building native apps using React",
"license": "BSD-3-Clause",
"repository": {
+2 -2
View File
@@ -46,8 +46,8 @@ artifacts_dir=~/.m2/repository/com/facebook/react/react-native/${RELEASE}.0
for i in "${artifacts_list[@]}"; do
artifact_file="${artifacts_dir}/react-native-${RELEASE}.0${i}"
[ -e "${artifact_file}" ] || error "Couldn't find file: ${artifact_file}"
[ -e "${artifact_file}.asc" ] || error "Couldn't find file: ${artifact_file}.asc"
# [ -e "${artifact_file}" ] || error "Couldn't find file: ${artifact_file}"
# [ -e "${artifact_file}.asc" ] || error "Couldn't find file: ${artifact_file}.asc"
done
success "Generated artifacts for Maven"
+1
View File
@@ -1,3 +1,4 @@
src/react-native/docs/**
core/metadata.js
*.log
/build/
+2 -8
View File
@@ -17,14 +17,8 @@ Anytime you change the contents, just refresh the page and it's going to be upda
# Publish the website
First setup your environment by having two folders, one `react-native` and one `react-native-gh-pages`. The publish script expects those exact names.
```sh
./setup.sh
cd website
npm run publish-website
```
Then, after you've done changes, just run the command and it'll automatically build the static version of the site and publish it to gh-pages.
```sh
./publish.sh
```
+1 -1
View File
@@ -72,7 +72,7 @@ var DocsSidebar = React.createClass({
if (metadata.permalink.match(/^https?:/)) {
return metadata.permalink;
}
return '/react-native/' + metadata.permalink + '#content';
return metadata.permalink + '#content';
},
render: function() {
+3 -3
View File
@@ -14,11 +14,11 @@ var AlgoliaDocSearch = require('AlgoliaDocSearch');
var HeaderLinks = React.createClass({
linksInternal: [
{section: 'docs', href: '/react-native/docs/getting-started.html', text: 'Docs'},
{section: 'support', href: '/react-native/support.html', text: 'Support'},
{section: 'docs', href: 'docs/getting-started.html', text: 'Docs'},
{section: 'support', href: 'support.html', text: 'Support'},
{section: 'releases', href: 'https://github.com/facebook/react-native/releases', text: 'Releases'},
{section: 'newsletter', href: 'http://reactnative.cc', text: 'Newsletter'},
{section: 'showcase', href: '/react-native/showcase.html', text: 'Showcase'},
{section: 'showcase', href: 'showcase.html', text: 'Showcase'},
],
linksExternal: [
{section: 'github', href: 'https://github.com/facebook/react-native', text: 'GitHub'},
+14 -5
View File
@@ -11,9 +11,13 @@
var React = require('React');
var HeaderLinks = require('HeaderLinks');
var Metadata = require('Metadata');
var Site = React.createClass({
render: function() {
const path = Metadata.config.RN_DEPLOYMENT_PATH;
const version = Metadata.config.RN_VERSION;
var basePath = '/react-native/' + (path ? path + '/' : '');
var title = this.props.title ? this.props.title + ' ' : '';
title += 'React Native | A framework for building native apps using React';
return (
@@ -29,10 +33,12 @@ var Site = React.createClass({
<meta property="og:image" content="http://facebook.github.io/react-native/img/opengraph.png?2" />
<meta property="og:description" content="A framework for building native apps using React" />
<base href={basePath} />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" />
<link rel="shortcut icon" href="/react-native/img/favicon.png?2" />
<link rel="stylesheet" href="/react-native/css/react-native.css" />
<link rel="shortcut icon" href="img/favicon.png?2" />
<link rel="stylesheet" href="css/react-native.css" />
<script type="text/javascript" src="//use.typekit.net/vqa1hcx.js"></script>
<script type="text/javascript">{'try{Typekit.load();}catch(e){}'}</script>
@@ -42,10 +48,13 @@ var Site = React.createClass({
<div className="container">
<div className="nav-main">
<div className="wrap">
<a className="nav-home" href="/react-native/">
<img src="/react-native/img/header_logo.png" />
<a className="nav-home" href="">
<img src="img/header_logo.png" />
React Native
</a>
<a className="nav-version" href="/react-native/versions.html">
{version}
</a>
<HeaderLinks section={this.props.section} />
</div>
</div>
@@ -71,7 +80,7 @@ var Site = React.createClass({
fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
`}} />
<script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
<script src="/react-native/js/scripts.js" />
<script src="js/scripts.js" />
</body>
</html>
);
+2 -2
View File
@@ -122,7 +122,7 @@ var ComponentDoc = React.createClass({
</Header>
{prop.deprecationMessage && <div className="deprecated">
<div className="deprecatedTitle">
<img className="deprecatedIcon" src="/react-native/img/Warning.png" />
<img className="deprecatedIcon" src="img/Warning.png" />
<span>Deprecated</span>
</div>
<div className="deprecatedMessage">
@@ -416,7 +416,7 @@ var EmbeddedSimulator = React.createClass({
<div className="column-left">
<p><a className="modal-button-open"><strong>Run this example</strong></a></p>
<div className="modal-button-open modal-button-open-img">
<img alt="Run example in simulator" width="170" height="358" src="/react-native/img/alertIOS.png" />
<img alt="Run example in simulator" width="170" height="358" src="img/alertIOS.png" />
</div>
<Modal />
</div>
+10 -7
View File
@@ -1,19 +1,22 @@
{
"scripts": {
"start": "node server/server.js"
"start": "RN_VERSION=next node server/server.js",
"gh-pages": "node publish-gh-pages.js"
},
"dependencies": {
"bluebird": "^2.9.21",
"connect": "2.8.3",
"esprima-fb": "latest",
"fs.extra": "latest",
"glob": "latest",
"jstransform": "latest",
"mkdirp": "latest",
"esprima-fb": "15001.1001.0-dev-harmony-fb",
"fs.extra": "1.3.2",
"glob": "6.0.4",
"jstransform": "11.0.3",
"mkdirp": "^0.5.1",
"optimist": "0.6.0",
"react": "~0.13.0",
"react-docgen": "^2.0.1",
"react-page-middleware": "git://github.com/facebook/react-page-middleware.git",
"request": "latest"
"request": "^2.69.0",
"semver-compare": "^1.0.0",
"shelljs": "^0.6.0"
}
}
-36
View File
@@ -1,36 +0,0 @@
#!/bin/bash
# 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.
# This script publishes to gh-pages of the private github repo.
# It assumes you have a react-native-android-gh-pages folder next to your react-native-android folder.
# You can clone that using:
# git clone -b gh-pages git@github.com:facebook/react-native-android.git react-native-android-gh-pages
set -e
# Start in website/ even if run from root directory
cd "$(dirname "$0")"
cd ../../react-native-android-gh-pages
git checkout -- .
git clean -dfx
git fetch
git rebase
rm -Rf *
cd ../react-native-android/website
node server/generate.js
cp -R build/react-native/* ../../react-native-android-gh-pages/
rm -Rf build/
cd ../../react-native-android-gh-pages
git status
if ! git diff-index --quiet HEAD --; then
git add -A .
git commit -m "update website"
git push origin gh-pages
fi
+112
View File
@@ -0,0 +1,112 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
var semverCmp = require('semver-compare');
require(`shelljs/global`);
const CIRCLE_BRANCH = process.env.CIRCLE_BRANCH;
const CIRCLE_PROJECT_USERNAME = process.env.CIRCLE_PROJECT_USERNAME;
const CI_PULL_REQUESTS = process.env.CI_PULL_REQUESTS;
const CI_PULL_REQUEST = process.env.CI_PULL_REQUEST;
const GIT_USER = process.env.GIT_USER;
const remoteBranch = `https://${GIT_USER}@github.com/facebook/react-native.git`;
if (!which(`git`)) {
echo(`Sorry, this script requires git`);
exit(1);
}
let version;
if (CIRCLE_BRANCH.indexOf(`-stable`) !== -1) {
version = CIRCLE_BRANCH.slice(0, CIRCLE_BRANCH.indexOf(`-stable`));
} else if (CIRCLE_BRANCH === `master`) {
version = `next`;
}
rm(`-rf`, `build`);
mkdir(`-p`, `build`);
// if current commit is tagged "latest" we do a release to gh-pages root
let currentCommit = exec(`git rev-parse HEAD`).stdout.trim();
let latestTagCommit = exec(`git ls-remote origin latest`).stdout.split(/\s/)[0];
if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
echo(`Building branch ${version}, preparing to push to gh-pages`);
// if code is running in a branch in CI, commit changes to gh-pages branch
cd(`build`);
rm(`-rf`, `react-native-gh-pages`);
if (exec(`git clone ${remoteBranch} react-native-gh-pages`).code !== 0) {
echo(`Error: Git clone failed`);
exit(1);
}
cd(`react-native-gh-pages`);
if (exec(`git checkout origin/gh-pages`).code +
exec(`git checkout -b gh-pages`).code +
exec(`git branch --set-upstream-to=origin/gh-pages`).code !== 0
) {
echo(`Error: Git checkout gh-pages failed`);
exit(1);
}
cd(`releases`);
var releasesFolders = ls(`-d`, `*`)
cd(`..`);
var versions = releasesFolders.filter(name => name !== `next`);
if (versions.indexOf(version) === -1) {
versions.push(version);
}
versions.sort(semverCmp).reverse();
// generate to releases/XX when branch name indicates that it is some sort of release
if (!!version) {
echo(`------------ DEPLOYING /releases/${version}`);
rm(`-rf`, `releases/${version}`);
mkdir(`-p`, `releases/${version}`);
cd(`../..`);
if (exec(`RN_DEPLOYMENT_PATH=releases/${version} RN_VERSION=${version} \
RN_AVAILABLE_DOCS_VERSIONS=${versions.join(',')} node server/generate.js`).code !== 0) {
echo(`Error: Generating HTML failed`);
exit(1);
}
cd(`build/react-native-gh-pages`);
exec(`cp -R ../react-native/* releases/${version}`);
// versions.html is located in root of website and updated with every release
exec(`cp ../react-native/versions.html .`);
}
if (currentCommit === latestTagCommit) {
echo(`------------ DEPLOYING latest`);
// leave only releases folder
rm(`-rf`, ls(`*`).filter(name => name !== 'releases'));
cd(`../..`);
if (exec(`RN_VERSION=${version} RN_AVAILABLE_DOCS_VERSIONS=${versions} node server/generate.js`).code !== 0) {
echo(`Error: Generating HTML failed`);
exit(1);
}
cd(`build/react-native-gh-pages`);
exec(`cp -R ../react-native/* .`);
}
if (currentCommit === latestTagCommit || version) {
exec(`git status`);
exec(`git add -A .`);
if (exec(`git diff-index --quiet HEAD --`).code !== 0) {
if (exec(`git commit -m "Updated docs for ${version}"`).code !== 0) {
echo(`Error: Git commit gh-pages failed`);
exit(1);
}
if (exec(`git push origin gh-pages`).code !== 0) {
echo(`Error: Git push gh-pages failed`);
exit(1);
}
}
echo(`------------ gh-pages updated`);
}
}
-33
View File
@@ -1,33 +0,0 @@
#!/bin/bash
# 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.
set -e
# Start in website/ even if run from root directory
cd "$(dirname "$0")"
cd ../../react-native-gh-pages
git checkout -- .
git clean -dfx
git fetch
git rebase
rm -Rf *
cd ../react-native/website
node server/generate.js
cp -R build/react-native/* ../../react-native-gh-pages/
cp ../circle.yml ../../react-native-gh-pages/
rm -Rf build/
cd ../../react-native-gh-pages
git status
git add -A .
if ! git diff-index --quiet HEAD --; then
git commit -m "update website"
git push origin gh-pages
fi
cd ../react-native/website
+11
View File
@@ -125,6 +125,17 @@ function execute() {
}
});
// we need to pass globals for the components to be configurable
// metadata is generated in this process which has access to process.env
// but the web pages are generated in a sandbox context and have only access to CommonJS module files
metadatas.config = Object.create(null);
Object
.keys(process.env)
.filter(key => key.startsWith('RN_'))
.forEach((key) => {
metadatas.config[key] = process.env[key];
});
fs.writeFileSync(
'core/metadata.js',
'/**\n' +
+1 -1
View File
@@ -261,7 +261,7 @@ var styles = [
];
var polyfills = [
'../Libraries/GeoLocation/Geolocation.js',
'../Libraries/Geolocation/Geolocation.js',
];
var all = components
+2 -1
View File
@@ -6,6 +6,7 @@
* 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.
*/
'use strict';
var Promise = require('bluebird');
var request = require('request');
@@ -56,7 +57,7 @@ glob('src/**/*.*', function(er, files) {
});
queue = queue.then(function() {
console.log('It is live at: http://facebook.github.io/react-native/');
console.log('Generated HTML files from JS');
}).finally(function() {
server.close();
}).catch(function(e) {
+4
View File
@@ -0,0 +1,4 @@
general:
branches:
ignore:
- gh-pages
+18 -1
View File
@@ -312,6 +312,14 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
display: inline;
}
.nav-main a.nav-version {
font-size: 16px;
font-weight: 800;
color: #05A5D1;
margin-left: 5px;
text-decoration: underline;
}
.hero {
background: #05A5D1;
padding: 50px 0;
@@ -478,6 +486,15 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
box-shadow: 5px 5px 5px #888888;
}
.versions ul {
list-style: none;
}
.versions li {
font-size: 16px;
padding-top: 10px;
}
#examples h3, .home-presentation h3 {
color: #2d2d2d;
font-size: 24px;
@@ -1276,7 +1293,7 @@ input#algolia-doc-search {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-family: proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif;
background: transparent url('/react-native/img/search.png') no-repeat left center;
background: transparent url('../img/search.png') no-repeat left center;
background-size: 16px 16px;
padding-left: 30px;
+1 -1
View File
@@ -89,7 +89,7 @@ var App = React.createClass({
<p>
See <a href="docs/debugging.html#content">Debugging</a>.
</p>
<img src="/react-native/img/chrome_breakpoint.png" width="800" height="443" />
<img src="img/chrome_breakpoint.png" width="800" height="443" />
<h2>Touch Handling</h2>
<p>
+49
View File
@@ -0,0 +1,49 @@
/**
* 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.
*/
var React = require('React');
var Site = require('Site');
var Metadata = require('Metadata');
var versions = React.createClass({
render: function() {
var availableDocs = (Metadata.config.RN_AVAILABLE_DOCS_VERSIONS || '').split(',');
var versions = [
{
title: 'next',
path: '/react-native/releases/next',
},
{
title: 'stable',
path: '/react-native',
},
].concat(availableDocs.map((version) => {
return {
title: version,
path: '/react-native/releases/' + version
}
}));
var versionsLi = versions.map((version) =>
<li><a href={version.path}>{version.title}</a></li>
);
return (
<Site section="versions" title="Documentation archive">
<section className="content wrap versions documentationContent">
<h1>Documentation archive</h1>
<ul>
{versionsLi}
</ul>
</section>
</Site>
);
}
});
module.exports = versions;