Compare commits

...
Author SHA1 Message Date
James Ide 9347583d8a [0.41.2] Bump version numbers 2017-02-06 00:30:33 -08:00
James Ide 71785a06b3 [Release] Support the --remote option in bump-oss-version.js script
In my RN checkout, I use "upstream" as my remote instead of "origin" -> this lets me run `scripts/bump-oss-version.js --remote upstream 0.41.1` for example.

Also made the script executable so we don't need to put `node` in front of it, and updated the Releases.md doc.

Test Plan: Did a dry run, saw that without the `--remote` flag the default remote is still `origin` and that specifying the flag let me override the origin.
2017-02-06 00:29:42 -08:00
James Ide fa68531ba2 [React] Use ~15.4.0 (not RC) 2017-02-06 00:16:16 -08:00
Eric VicentiandJames Ide 516d97397b Eject CLI command to re-create native folders
Summary:
The iOS and Android native folders of a React Native app can be difficult to maintain. This introduces a new workflow for creating and maintaining the native code of your app.

Now it will be possible to:

1. Remove the native iOS or Android folders
2. Create an `app.json` for your app, with at least a `name` and `displayName`
3. Run `react-native eject`, and the native code for your app will be generated

Then, as usual, you can run `react-native run-ios` and `react-native run-android`, to build and launch your app

For apps that don't have any native code, it will be possible to ignore the `ios` and `android` folders from version control.

Eject step tested in RN app by deleting native folders.

mkonicek, what is the best way to test `react-native init`?

As follow-up items, we can enable the following:

- Configuring app icon and launch screen from the `app.json`
- Automatically run `react-native link` for native libraries
- A
Closes https://github.com/facebook/react-native/pull/12162

Differential Revision: D4509138

Pulled By: ericvicenti

fbshipit-source-id: 0ee213e68f0a3d44bfce337e3ec43e5024bacc66
2017-02-06 00:11:34 -08:00
Martin Konicek 8b1a34d0ee [0.41.1] Bump version numbers 2017-02-03 18:54:03 +00:00
Mike GrabowskiandMartin Konicek bc72cf1514 Remove build artifacts
Summary:
Ignores `bundle.js` that is a webpack bundle and got most likely accidentally released. Already cherry-picked to 0.42

Fixes #12183
Closes https://github.com/facebook/react-native/pull/12185

Differential Revision: D4507535

Pulled By: mkonicek

fbshipit-source-id: 2ab404534b345cf531f408b654c34a30abd01458
2017-02-03 18:52:35 +00:00
Mike Grabowski 5db36da8a1 [0.41.0] Bump version numbers 2017-02-02 18:51:58 +01:00
Emil SjolanderandMike Grabowski d32cf68ff8 Resolve conflicts 2017-02-02 18:50:41 +01:00
rh389andMike Grabowski 2b087c2c94 Fix template release build: Add -ObjC and -lc++ to tests target
Summary:
Fixes https://github.com/facebook/react-native/issues/11861 - the release config is currently broken for projects created by `react-native init` in `master`, 0.40 and 0.39.

I'm still investigating when and how this got broken but this seems to be a clean fix. I've added `-ObjC` as well to match the main target but I'm not sure yet whether that's necessary.

To test:
```
react-native init fooproject --version react-native@rh389/react-native#missinglinkerflags
```
Open in XCode, Edit scheme (⌘<), Change `Build Configuration` to `Release`, build.

Update: The `-lc++` flag became necessary when https://github.com/facebook/react-native/commit/33deaad196834e77a507cad7b13039161258c059 landed because of the libstdc++ dependencies of `RCTLog`. Still not sure about `-ObjC`. javache ?
Closes https://github.com/facebook/react-native/pull/11889

Differential Revision: D4421685

Pulled By: javache

fbshipit-source-id: 954edaef773f8cef7b7ad671fa4d1f2bfc2f20f2
2017-02-02 17:45:45 +01:00
Tomas RoosandMike Grabowski 7f98028e71 Fixes podspec for master #11640
Summary:
Currently the master Podspec is broken because tvOS files are being included, to avoid this compile error the file is being excluded.

https://github.com/facebook/react-native/commit/c92ad5f6ae74c1d398c7cd93d5c4c50da0ca0430

Thats the commit which introduced the breakage anything later that that will fail. Aka RN 0.41 will fail because of this.

**Test plan (required)**

Tested on new project against master

// cc ide
Closes https://github.com/facebook/react-native/pull/11667

Differential Revision: D4375453

Pulled By: ericvicenti

fbshipit-source-id: 035cdb8ef36054b40d1aaf59551cdc2e16f0cb19
2017-02-02 17:45:18 +01:00
Martin Konicek f1fdd8914a [0.41.0-rc.1] Bump version numbers 2017-01-30 18:44:24 +00:00
Martin Konicek 75f4033ca0 Support ScrollView.scrollToEnd on Android natively
Summary:
This is a followup for https://github.com/facebook/react-native/pull/12088 and implements the scrolling to end on Android natively rather than sending a large scroll offset from JS.

This turned out to be an OK amount of code, and some reduction in the amount of JavaScript. The only part I'm not particularly happy about is:

```
// ScrollView always has one child - the scrollable area
int bottom = scrollView.getChildAt(0).getHeight() + scrollView.getPaddingBottom();
```

According to multiple sources (e.g. [this SO answer](http://stackoverflow.com/questions/3609297/android-total-height-of-scrollview)) it is the way to get the total size of the scrollable area, similar to`scrollView.contentSize` on iOS but more ugly and relying on the fact the ScrollView always has a single child (hopefully this won't change in future versions of Android).

An alternative is:

```
View lastChild = scrollLayout.getChildAt(scrollLayout.getChildCount() - 1);
int bottom = lastChild.getBottom() + scrollLayout.getPadd
Closes https://github.com/facebook/react-native/pull/12101

Differential Revision: D4481523

Pulled By: mkonicek

fbshipit-source-id: 8c7967a0b9e06890c1e1ea70ad573c6eceb03daf
2017-01-30 18:42:46 +00:00
Martin Konicek 7f42a44751 Add scrollToEnd to ScrollView and ListView
Summary:
**Motivation**

A basic task of making a React Native ScrollView or ListView scroll to the bottom is currently very hard to accomplish:
- https://github.com/facebook/react-native/issues/8003
- https://github.com/facebook/react-native/issues/913
- http://stackoverflow.com/questions/29829375/how-to-scroll-to-bottom-in-react-native-listview

**NOTE:** If you're building something like a chat app where you want a ListView to keep scrolling to the bottom at all times, it's easiest to use the [react-native-invertible-scrollview](https://github.com/exponent/react-native-invertible-scroll-view) component rather calling `scrollToEnd` manually when layout changes. The invertible-scrollview uses a clever trick to invert the direction of the ScrollView.

This pull request adds a `scrollToEnd` method which scrolls to the bottom if the ScrollView is vertical, to the right if the ScrollView is horizontal.

The implementation is based on this SO answer:
http://stackoverflow.com/questions/952412/uiscrollview-scrol
Closes https://github.com/facebook/react-native/pull/12088

Differential Revision: D4474974

Pulled By: mkonicek

fbshipit-source-id: 6ecf8b3435f47dd3a31e2fd5be6859062711c233
2017-01-30 18:42:35 +00:00
Mike Grabowski b570c23cfe [0.41.0-rc.0] Bump version numbers 2017-01-04 13:48:22 +01:00
27 changed files with 345 additions and 22713 deletions
@@ -57,6 +57,11 @@ exports.examples = [
onPress={() => { _scrollView.scrollTo({y: 0}); }}>
<Text>Scroll to top</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => { _scrollView.scrollToEnd({animated: true}); }}>
<Text>Scroll to bottom</Text>
</TouchableOpacity>
</View>
);
}
@@ -79,6 +84,11 @@ exports.examples = [
onPress={() => { _scrollView.scrollTo({x: 0}); }}>
<Text>Scroll to start</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => { _scrollView.scrollToEnd({animated: true}); }}>
<Text>Scroll to end</Text>
</TouchableOpacity>
</View>
);
}
+23 -3
View File
@@ -377,11 +377,11 @@ var ScrollResponderMixin = {
},
/**
* A helper function to scroll to a specific point in the scrollview.
* This is currently used to help focus on child textviews, but can also
* A helper function to scroll to a specific point in the ScrollView.
* This is currently used to help focus child TextViews, but can also
* be used to quickly scroll to any element we want to focus. Syntax:
*
* scrollResponderScrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
* `scrollResponderScrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})`
*
* Note: The weird argument signature is due to the fact that, for historical reasons,
* the function also accepts separate arguments as as alternative to the options object.
@@ -404,6 +404,26 @@ var ScrollResponderMixin = {
);
},
/**
* Scrolls to the end of the ScrollView, either immediately or with a smooth
* animation.
*
* Example:
*
* `scrollResponderScrollToEnd({animated: true})`
*/
scrollResponderScrollToEnd: function(
options?: { animated?: boolean },
) {
// Default to true
const animated = (options && options.animated) !== false;
UIManager.dispatchViewManagerCommand(
this.scrollResponderGetScrollableNode(),
UIManager.RCTScrollView.Commands.scrollToEnd,
[animated],
);
},
/**
* Deprecated, do not use.
*/
+22 -4
View File
@@ -382,11 +382,11 @@ const ScrollView = React.createClass({
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
*
* Syntax:
* Example:
*
* `scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})`
* `scrollTo({x: 0; y: 0; animated: true})`
*
* Note: The weird argument signature is due to the fact that, for historical reasons,
* Note: The weird function signature is due to the fact that, for historical reasons,
* the function also accepts separate arguments as as alternative to the options object.
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/
@@ -404,7 +404,25 @@ const ScrollView = React.createClass({
},
/**
* Deprecated, do not use.
* If this is a vertical ScrollView scrolls to the bottom.
* If this is a horizontal ScrollView scrolls to the right.
*
* Use `scrollToEnd({animated: true})` for smooth animated scrolling,
* `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true.
*/
scrollToEnd: function(
options?: { animated?: boolean },
) {
// Default to true
const animated = (options && options.animated) !== false;
this.getScrollResponder().scrollResponderScrollToEnd({
animated: animated,
});
},
/**
* Deprecated, use `scrollTo` instead.
*/
scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
@@ -287,6 +287,29 @@ var ListView = React.createClass({
}
},
/**
* If this is a vertical ListView scrolls to the bottom.
* If this is a horizontal ListView scrolls to the right.
*
* Use `scrollToEnd({animated: true})` for smooth animated scrolling,
* `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true.
*
* See `ScrollView#scrollToEnd`.
*/
scrollToEnd: function(options?: { animated?: boolean }) {
if (this._scrollComponent) {
if (this._scrollComponent.scrollToEnd) {
this._scrollComponent.scrollToEnd(options);
} else {
console.warn(
'The scroll component used by the ListView does not support ' +
'scrollToEnd. Check the renderScrollComponent prop of your ListView.'
);
}
}
},
setNativeProps: function(props: Object) {
if (this._scrollComponent) {
this._scrollComponent.setNativeProps(props);
+7 -2
View File
@@ -4,7 +4,7 @@ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
Pod::Spec.new do |s|
s.name = "React"
s.version = package['version']
s.version = "0.41.2"
s.summary = package['description']
s.description = <<-DESC
React Native apps are built using the React JS
@@ -34,11 +34,16 @@ Pod::Spec.new do |s|
ss.dependency 'React/yoga'
ss.dependency 'React/cxxreact'
ss.source_files = "React/**/*.{c,h,m,mm,S}"
ss.exclude_files = "**/__tests__/*", "IntegrationTests/*", "ReactCommon/yoga/*"
ss.exclude_files = "**/__tests__/*", "IntegrationTests/*", "React/**/RCTTVView.*", "ReactCommon/yoga/*"
ss.frameworks = "JavaScriptCore"
ss.libraries = "stdc++"
end
s.subspec 'tvOS' do |ss|
ss.dependency 'React/Core'
ss.source_files = "React/**/RCTTVView.{h, m}"
end
s.subspec 'jschelpers' do |ss|
ss.source_files = 'ReactCommon/jschelpers/{JavaScriptCore,JSCWrapper}.{cpp,h}'
ss.header_dir = 'jschelpers'
+4 -4
View File
@@ -480,10 +480,10 @@ SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument
expectedCount -= 2;
}
RCTLogError(@"%@.%@ was called with %zd arguments, but expects %zd. \
If you haven\'t changed this method yourself, this usually means that \
your versions of the native code and JavaScript code are out of sync. \
Updating both should make this error go away.",
RCTLogError(@"%@.%@ was called with %zd arguments but expects %zd arguments. "
@"If you haven\'t changed this method yourself, this usually means that "
@"your versions of the native code and JavaScript code are out of sync. "
@"Updating both should make this error go away.",
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName,
actualCount, expectedCount);
return nil;
+26 -1
View File
@@ -588,6 +588,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
_scrollView.contentOffset = contentOffset;
}
- (BOOL)isHorizontal:(UIScrollView *)scrollView
{
return scrollView.contentSize.width > self.frame.size.width;
}
- (void)scrollToOffset:(CGPoint)offset
{
[self scrollToOffset:offset animated:YES];
@@ -602,6 +607,26 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
}
}
/**
* If this is a vertical scroll view, scrolls to the bottom.
* If this is a horizontal scroll view, scrolls to the right.
*/
- (void)scrollToEnd:(BOOL)animated
{
BOOL isHorizontal = [self isHorizontal:_scrollView];
CGPoint offset;
if (isHorizontal) {
offset = CGPointMake(_scrollView.contentSize.width - _scrollView.bounds.size.width, 0);
} else {
offset = CGPointMake(0, _scrollView.contentSize.height - _scrollView.bounds.size.height);
}
if (!CGPointEqualToPoint(_scrollView.contentOffset, offset)) {
// Ensure at least one scroll event will fire
_allowNextScrollNoMatterWhat = YES;
[_scrollView setContentOffset:offset animated:animated];
}
}
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated
{
[_scrollView zoomToRect:rect animated:animated];
@@ -727,7 +752,7 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll)
CGFloat snapToIntervalF = (CGFloat)self.snapToInterval;
// Find which axis to snap
BOOL isHorizontal = (scrollView.contentSize.width > self.frame.size.width);
BOOL isHorizontal = [self isHorizontal:scrollView];
// What is the current offset?
CGFloat targetContentOffsetAlongAxis = isHorizontal ? targetContentOffset->x : targetContentOffset->y;
+15
View File
@@ -147,6 +147,21 @@ RCT_EXPORT_METHOD(scrollTo:(nonnull NSNumber *)reactTag
}];
}
RCT_EXPORT_METHOD(scrollToEnd:(nonnull NSNumber *)reactTag
animated:(BOOL)animated)
{
[self.bridge.uiManager addUIBlock:
^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
UIView *view = viewRegistry[reactTag];
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
[(id<RCTScrollableProtocol>)view scrollToEnd:animated];
} else {
RCTLogError(@"tried to scrollTo: on non-RCTScrollableProtocol view %@ "
"with tag #%@", view, reactTag);
}
}];
}
RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag
withRect:(CGRect)rect
animated:(BOOL)animated)
+5
View File
@@ -19,6 +19,11 @@
- (void)scrollToOffset:(CGPoint)offset;
- (void)scrollToOffset:(CGPoint)offset animated:(BOOL)animated;
/**
* If this is a vertical scroll view, scrolls to the bottom.
* If this is a horizontal scroll view, scrolls to the right.
*/
- (void)scrollToEnd:(BOOL)animated;
- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated;
- (void)addScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener;
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_NAME=1000.0.0-master
VERSION_NAME=0.41.2
GROUP=com.facebook.react
POM_NAME=ReactNative
@@ -80,6 +80,15 @@ public class RecyclerViewBackedScrollViewManager extends
scrollView.scrollTo(data.mDestX, data.mDestY, data.mAnimated);
}
@Override
public void scrollToEnd(
RecyclerViewBackedScrollView scrollView,
ReactScrollViewCommandHelper.ScrollToEndCommandData data) {
// Not implemented.
// RecyclerViewBackedScrollView is deprecated and will be removed.
// People should use a standard ScrollView or ListView instead.
}
@Override
public @Nullable
Map getExportedCustomDirectEventTypeConstants() {
@@ -117,6 +117,20 @@ public class ReactHorizontalScrollViewManager
}
}
@Override
public void scrollToEnd(
ReactHorizontalScrollView scrollView,
ReactScrollViewCommandHelper.ScrollToEndCommandData data) {
// ScrollView always has one child - the scrollable area
int right =
scrollView.getChildAt(0).getWidth() + scrollView.getPaddingRight();
if (data.mAnimated) {
scrollView.smoothScrollTo(right, scrollView.getScrollY());
} else {
scrollView.scrollTo(right, scrollView.getScrollY());
}
}
/**
* When set, fills the rest of the scrollview with a color to avoid setting a background and
* creating unnecessary overdraw.
@@ -25,9 +25,11 @@ import com.facebook.react.common.MapBuilder;
public class ReactScrollViewCommandHelper {
public static final int COMMAND_SCROLL_TO = 1;
public static final int COMMAND_SCROLL_TO_END = 2;
public interface ScrollCommandHandler<T> {
void scrollTo(T scrollView, ScrollToCommandData data);
void scrollToEnd(T scrollView, ScrollToEndCommandData data);
}
public static class ScrollToCommandData {
@@ -42,10 +44,21 @@ public class ReactScrollViewCommandHelper {
}
}
public static class ScrollToEndCommandData {
public final boolean mAnimated;
ScrollToEndCommandData(boolean animated) {
mAnimated = animated;
}
}
public static Map<String,Integer> getCommandsMap() {
return MapBuilder.of(
"scrollTo",
COMMAND_SCROLL_TO);
COMMAND_SCROLL_TO,
"scrollToEnd",
COMMAND_SCROLL_TO_END);
}
public static <T> void receiveCommand(
@@ -64,6 +77,11 @@ public class ReactScrollViewCommandHelper {
viewManager.scrollTo(scrollView, new ScrollToCommandData(destX, destY, animated));
return;
}
case COMMAND_SCROLL_TO_END: {
boolean animated = args.getBoolean(0);
viewManager.scrollToEnd(scrollView, new ScrollToEndCommandData(animated));
return;
}
default:
throw new IllegalArgumentException(String.format(
"Unsupported command %d received by %s.",
@@ -131,6 +131,20 @@ public class ReactScrollViewManager
}
}
@Override
public void scrollToEnd(
ReactScrollView scrollView,
ReactScrollViewCommandHelper.ScrollToEndCommandData data) {
// ScrollView always has one child - the scrollable area
int bottom =
scrollView.getChildAt(0).getHeight() + scrollView.getPaddingBottom();
if (data.mAnimated) {
scrollView.smoothScrollTo(scrollView.getScrollX(), bottom);
} else {
scrollView.scrollTo(scrollView.getScrollX(), bottom);
}
}
@Override
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
return createExportedCustomDirectEventTypeConstants();
+8 -4
View File
@@ -2520,19 +2520,22 @@ static void YGNodelayoutImpl(const YGNodeRef node,
// If the user didn't specify a width or height for the node, set the
// dimensions based on the children.
if (measureModeMainDim == YGMeasureModeUndefined) {
if (measureModeMainDim == YGMeasureModeUndefined ||
(node->style.overflow != YGOverflowScroll && measureModeMainDim == YGMeasureModeAtMost)) {
// Clamp the size to the min/max size, if specified, and make sure it
// doesn't go below the padding and border amount.
node->layout.measuredDimensions[dim[mainAxis]] =
YGNodeBoundAxis(node, mainAxis, maxLineMainDim, mainAxisParentSize, parentWidth);
} else if (measureModeMainDim == YGMeasureModeAtMost) {
} else if (measureModeMainDim == YGMeasureModeAtMost &&
node->style.overflow == YGOverflowScroll) {
node->layout.measuredDimensions[dim[mainAxis]] = fmaxf(
fminf(availableInnerMainDim + paddingAndBorderAxisMain,
YGNodeBoundAxisWithinMinAndMax(node, mainAxis, maxLineMainDim, mainAxisParentSize)),
paddingAndBorderAxisMain);
}
if (measureModeCrossDim == YGMeasureModeUndefined) {
if (measureModeCrossDim == YGMeasureModeUndefined ||
(node->style.overflow != YGOverflowScroll && measureModeCrossDim == YGMeasureModeAtMost)) {
// Clamp the size to the min/max size, if specified, and make sure it
// doesn't go below the padding and border amount.
node->layout.measuredDimensions[dim[crossAxis]] =
@@ -2541,7 +2544,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
totalLineCrossDim + paddingAndBorderAxisCross,
crossAxisParentSize,
parentWidth);
} else if (measureModeCrossDim == YGMeasureModeAtMost) {
} else if (measureModeCrossDim == YGMeasureModeAtMost &&
node->style.overflow == YGOverflowScroll) {
node->layout.measuredDimensions[dim[crossAxis]] =
fmaxf(fminf(availableInnerCrossDim + paddingAndBorderAxisCross,
YGNodeBoundAxisWithinMinAndMax(node,
+7 -6
View File
@@ -44,8 +44,9 @@ Run:
git checkout -b <version_you_are_releasing>-stable
# e.g. git checkout -b 0.22-stable
node ./scripts/bump-oss-version.js <exact-version_you_are_releasing>
# e.g. node ./scripts/bump-oss-version.js 0.22.0-rc
./scripts/bump-oss-version.js <exact-version_you_are_releasing>
# e.g. ./scripts/bump-oss-version.js 0.22.0-rc
# You can use the --remote option to specify a Git remote other than the default "origin"
```
Circle CI will automatically run the tests and publish to npm with the version you have specified (e.g `0.22.0-rc`) and tag `next` meaning that this version will not be installed for users by default.
@@ -112,8 +113,8 @@ git cherry-pick commitHash1
If everything worked:
```bash
node ./scripts/bump-oss-version.js <exact_version_you_are_releasing>
# e.g. node ./scripts/bump-oss-version.js 0.28.0-rc.1
./scripts/bump-oss-version.js <exact_version_you_are_releasing>
# e.g. ./scripts/bump-oss-version.js 0.28.0-rc.1
````
-------------------
@@ -141,8 +142,8 @@ git cherry-pick commitHash1
If everything worked:
```bash
node ./scripts/bump-oss-version.js <exact_version_you_are_releasing>
# e.g. node ./scripts/bump-oss-version.js 0.22.0
./scripts/bump-oss-version.js <exact_version_you_are_releasing>
# e.g. ./scripts/bump-oss-version.js 0.22.0
```
#### Update the release notes
+1
View File
@@ -42,6 +42,7 @@ const documentedCommands = [
require('./library/library'),
require('./bundle/bundle'),
require('./bundle/unbundle'),
require('./eject/eject'),
require('./link/link'),
require('./link/unlink'),
require('./install/install'),
+96
View File
@@ -0,0 +1,96 @@
/**
* 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';
const copyProjectTemplateAndReplace = require('../generator/copyProjectTemplateAndReplace');
const path = require('path');
const fs = require('fs');
/**
* The eject command re-creates the `android` and `ios` native folders. Because native code can be
* difficult to maintain, this new script allows an `app.json` to be defined for the project, which
* is used to configure the native app.
*
* The `app.json` config may contain the following keys:
*
* - `name` - The short name used for the project, should be TitleCase
* - `displayName` - The app's name on the home screen
*/
function eject() {
const doesIOSExist = fs.existsSync(path.resolve('ios'));
const doesAndroidExist = fs.existsSync(path.resolve('android'));
if (doesIOSExist && doesAndroidExist) {
console.error(
'Both the iOS and Android folders already exist! Please delete `ios` and/or `android` ' +
'before ejecting.'
);
process.exit(1);
}
let appConfig = null;
try {
appConfig = require(path.resolve('app.json'));
} catch(e) {
console.error(
`Eject requires an \`app.json\` config file to be located at ` +
`${path.resolve('app.json')}, and it must at least specify a \`name\` for the project ` +
`name, and a \`displayName\` for the app's home screen label.`
);
process.exit(1);
}
const appName = appConfig.name;
if (!appName) {
console.error(
`App \`name\` must be defined in the \`app.json\` config file to define the project name. `+
`It must not contain any spaces or dashes.`
);
process.exit(1);
}
const displayName = appConfig.displayName;
if (!displayName) {
console.error(
`App \`displayName\` must be defined in the \`app.json\` config file, to define the label ` +
`of the app on the home screen.`
);
process.exit(1);
}
const templateOptions = { displayName };
if (!doesIOSExist) {
console.log('Generating the iOS folder.');
copyProjectTemplateAndReplace(
path.resolve('node_modules', 'react-native', 'local-cli', 'templates', 'HelloWorld', 'ios'),
path.resolve('ios'),
appName,
templateOptions
);
}
if (!doesAndroidExist) {
console.log('Generating the Android folder.');
copyProjectTemplateAndReplace(
path.resolve('node_modules', 'react-native', 'local-cli', 'templates', 'HelloWorld', 'android'),
path.resolve('android'),
appName,
templateOptions
);
}
}
module.exports = {
name: 'eject',
description: 'Re-create the iOS and Android folders and native code',
func: eject,
options: [],
};
@@ -27,10 +27,12 @@ function copyProjectTemplateAndReplace(srcPath, destPath, newProjectName, option
if (!destPath) { throw new Error('Need a path to copy to'); }
if (!newProjectName) { throw new Error('Need a project name'); }
options = options || {};
walk(srcPath).forEach(absoluteSrcFilePath => {
// 'react-native upgrade'
if (options && options.upgrade) {
if (options.upgrade) {
// Don't upgrade these files
const fileName = path.basename(absoluteSrcFilePath);
// This also includes __tests__/index.*.js
@@ -44,7 +46,7 @@ function copyProjectTemplateAndReplace(srcPath, destPath, newProjectName, option
.replace(/helloworld/g, newProjectName.toLowerCase());
let contentChangedCallback = null;
if (options && options.upgrade && (!options.force)) {
if (options.upgrade && (!options.force)) {
contentChangedCallback = (_, contentChanged) => {
return upgradeFileContentChangedCallback(
absoluteSrcFilePath,
@@ -57,6 +59,7 @@ function copyProjectTemplateAndReplace(srcPath, destPath, newProjectName, option
absoluteSrcFilePath,
path.resolve(destPath, relativeRenamedPath),
{
'Hello App Display Name': options.displayName || newProjectName,
'HelloWorld': newProjectName,
'helloworld': newProjectName.toLowerCase(),
},
@@ -1,2 +1,3 @@
/captures/*
preLoadedCapture.js
bundle.js
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
<resources>
<string name="app_name">HelloWorld</string>
<string name="app_name">Hello App Display Name</string>
</resources>
+4
View File
@@ -0,0 +1,4 @@
{
"name": "HelloWorld",
"displayName": "HelloWorld"
}
@@ -966,6 +966,10 @@
INFOPLIST_FILE = HelloWorldTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld";
};
@@ -979,6 +983,10 @@
INFOPLIST_FILE = HelloWorldTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld";
};
@@ -4,6 +4,8 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Hello App Display Name</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "react-native",
"version": "1000.0.0",
"version": "0.41.2",
"description": "A framework for building native apps using React",
"license": "BSD-3-Clause",
"repository": {
@@ -113,7 +113,7 @@
"react-native": "local-cli/wrong-react-native.js"
},
"peerDependencies": {
"react": "~15.4.0-rc.4"
"react": "~15.4.0"
},
"dependencies": {
"absolute-path": "^0.0.0",
@@ -203,10 +203,10 @@
"jest-repl": "18.0.0",
"jest-runtime": "18.0.0",
"mock-fs": "^3.11.0",
"react": "~15.4.0-rc.4",
"react-dom": "~15.4.0-rc.4",
"react-test-renderer": "~15.4.0-rc.4",
"react": "~15.4.0",
"react-dom": "~15.4.0",
"react-test-renderer": "~15.4.0",
"shelljs": "0.6.0",
"sinon": "^2.0.0-pre.2"
}
}
}
Regular → Executable
+14 -5
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env node
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
@@ -17,6 +18,13 @@
/*eslint-disable no-undef */
require(`shelljs/global`);
const minimist = require('minimist');
let argv = minimist(process.argv.slice(2), {
alias: {remote: 'r'},
default: {remote: 'origin'},
});
// - check we are in release branch, e.g. 0.33-stable
let branch = exec(`git symbolic-ref --short HEAD`, {silent: true}).stdout.trim();
@@ -30,7 +38,7 @@ let versionMajor = branch.slice(0, branch.indexOf(`-stable`));
// - check that argument version matches branch
// e.g. 0.33.1 or 0.33.0-rc4
let version = process.argv[2];
let version = argv._[0];
if (!version || version.indexOf(versionMajor) !== 0) {
echo(`You must pass a tag like ${versionMajor}.[X]-rc[Y] to bump a version`);
exit(1);
@@ -77,17 +85,18 @@ if (exec(`git tag v${version}`).code) {
}
// Push newly created tag
exec(`git push origin v${version}`);
let remote = argv.remote;
exec(`git push ${remote} v${version}`);
// Tag latest if doing stable release
if (version.indexOf(`rc`) === -1) {
exec(`git tag -d latest`);
exec(`git push origin :latest`);
exec(`git push ${remote} :latest`);
exec(`git tag latest`);
exec(`git push origin latest`);
exec(`git push ${remote} latest`);
}
exec(`git push origin ${branch} --follow-tags`);
exec(`git push ${remote} ${branch} --follow-tags`);
exit(0);
/*eslint-enable no-undef */