mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f65310ced | ||
|
|
a04a9c73e9 | ||
|
|
afcef0154e | ||
|
|
a769f91ccf | ||
|
|
b68bae447d | ||
|
|
52d2dbe8da | ||
|
|
8ed96be6b0 | ||
|
|
c4fbfa66c1 | ||
|
|
12d96eec91 | ||
|
|
d403c24493 | ||
|
|
9f07e1f306 | ||
|
|
ca47230955 | ||
|
|
0acba126f9 | ||
|
|
90dd33726c | ||
|
|
eb3df43818 | ||
|
|
f514409495 | ||
|
|
6f5acbd95a | ||
|
|
2f1ed20a6e |
+2
-18
@@ -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
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @providesModule AppStateExample
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
AppState,
|
||||
Text,
|
||||
View
|
||||
} = React;
|
||||
|
||||
var AppStateSubscription = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
appState: AppState.currentState,
|
||||
previousAppStates: [],
|
||||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
AppState.addEventListener('change', this._handleAppStateChange);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||
},
|
||||
_handleAppStateChange: function(appState) {
|
||||
var previousAppStates = this.state.previousAppStates.slice();
|
||||
previousAppStates.push(this.state.appState);
|
||||
this.setState({
|
||||
appState,
|
||||
previousAppStates,
|
||||
});
|
||||
},
|
||||
render() {
|
||||
if (this.props.showCurrentOnly) {
|
||||
return (
|
||||
<View>
|
||||
<Text>{this.state.appState}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<View>
|
||||
<Text>{JSON.stringify(this.state.previousAppStates)}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
exports.title = 'AppState';
|
||||
exports.description = 'app background status';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'AppState.currentState',
|
||||
description: 'Can be null on app initialization',
|
||||
render() { return <Text>{AppState.currentState}</Text>; }
|
||||
},
|
||||
{
|
||||
title: 'Subscribed AppState:',
|
||||
description: 'This changes according to the current state, so you can only ever see it rendered as "active"',
|
||||
render(): ReactElement { return <AppStateSubscription showCurrentOnly={true} />; }
|
||||
},
|
||||
{
|
||||
title: 'Previous states:',
|
||||
render(): ReactElement { return <AppStateSubscription showCurrentOnly={false} />; }
|
||||
},
|
||||
];
|
||||
@@ -16,25 +16,31 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const UIExplorerBlock = require('UIExplorerBlock');
|
||||
const UIExplorerPage = require('UIExplorerPage');
|
||||
|
||||
const {
|
||||
PickerAndroid,
|
||||
Picker,
|
||||
Text,
|
||||
TouchableWithoutFeedback,
|
||||
} = React;
|
||||
const Item = PickerAndroid.Item;
|
||||
const Item = Picker.Item;
|
||||
|
||||
const PickerExample = React.createClass({
|
||||
|
||||
statics: {
|
||||
title: '<Picker>',
|
||||
description: 'Provides multiple options to choose from, using either a dropdown menu or a dialog.',
|
||||
},
|
||||
|
||||
const PickerAndroidExample = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
selected1: 'key1',
|
||||
selected2: 'key1',
|
||||
selected3: 'key1',
|
||||
selected4: 'key1',
|
||||
color: 'red',
|
||||
mode: PickerAndroid.MODE_DIALOG,
|
||||
mode: Picker.MODE_DIALOG,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -42,101 +48,93 @@ const PickerAndroidExample = React.createClass({
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<UIExplorerPage title="<PickerAndroid>">
|
||||
<UIExplorerPage title="<Picker>">
|
||||
<UIExplorerBlock title="Basic Picker">
|
||||
<PickerAndroid
|
||||
style={{width: 100, height: 56}}
|
||||
onSelect={this.onSelect.bind(this, 'selected1')}>
|
||||
<Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
|
||||
<Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
|
||||
</PickerAndroid>
|
||||
<Picker
|
||||
style={styles.picker}
|
||||
selectedValue={this.state.selected1}
|
||||
onValueChange={this.onValueChange.bind(this, 'selected1')}>
|
||||
<Item label="hello" value="key0" />
|
||||
<Item label="world" value="key1" />
|
||||
</Picker>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title="Disabled picker">
|
||||
<PickerAndroid style={{width: 100, height: 56}} enabled={false}>
|
||||
<Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
|
||||
<Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
|
||||
</PickerAndroid>
|
||||
<Picker style={styles.picker} enabled={false} selectedValue={this.state.selected1}>
|
||||
<Item label="hello" value="key0" />
|
||||
<Item label="world" value="key1" />
|
||||
</Picker>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title="Dropdown Picker">
|
||||
<PickerAndroid
|
||||
style={{width: 100, height: 56}}
|
||||
onSelect={this.onSelect.bind(this, 'selected2')}
|
||||
<Picker
|
||||
style={styles.picker}
|
||||
selectedValue={this.state.selected2}
|
||||
onValueChange={this.onValueChange.bind(this, 'selected2')}
|
||||
mode="dropdown">
|
||||
<Item text="hello" value="key0" selected={this.state.selected2 === 'key0'} />
|
||||
<Item text="world" value="key1" selected={this.state.selected2 === 'key1'} />
|
||||
</PickerAndroid>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title="Alternating Picker">
|
||||
<PickerAndroid
|
||||
style={{width: 100, height: 56}}
|
||||
onSelect={this.onSelect.bind(this, 'selected3')}
|
||||
mode={this.state.mode}>
|
||||
<Item text="hello" value="key0" selected={this.state.selected3 === 'key0'} />
|
||||
<Item text="world" value="key1" selected={this.state.selected3 === 'key1'} />
|
||||
</PickerAndroid>
|
||||
<TouchableWithoutFeedback onPress={this.changeMode}>
|
||||
<Text>Tap here to switch between dialog/dropdown.</Text>
|
||||
</TouchableWithoutFeedback>
|
||||
<Item label="hello" value="key0" />
|
||||
<Item label="world" value="key1" />
|
||||
</Picker>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title="Picker with prompt message">
|
||||
<PickerAndroid
|
||||
style={{width: 100, height: 56}}
|
||||
onSelect={this.onSelect.bind(this, 'selected4')}
|
||||
<Picker
|
||||
style={styles.picker}
|
||||
selectedValue={this.state.selected3}
|
||||
onValueChange={this.onValueChange.bind(this, 'selected3')}
|
||||
prompt="Pick one, just one">
|
||||
<Item text="hello" value="key0" selected={this.state.selected4 === 'key0'} />
|
||||
<Item text="world" value="key1" selected={this.state.selected4 === 'key1'} />
|
||||
</PickerAndroid>
|
||||
<Item label="hello" value="key0" />
|
||||
<Item label="world" value="key1" />
|
||||
</Picker>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title="Picker with no listener">
|
||||
<PickerAndroid style={{width: 100, height: 56}}>
|
||||
<Item text="hello" value="key0" />
|
||||
<Item text="world" value="key1" />
|
||||
</PickerAndroid>
|
||||
<Picker style={styles.picker}>
|
||||
<Item label="hello" value="key0" />
|
||||
<Item label="world" value="key1" />
|
||||
</Picker>
|
||||
<Text>
|
||||
You can not change the value of this picker because it doesn't set a selected prop on
|
||||
its items.
|
||||
Cannot change the value of this picker because it doesn't update selectedValue.
|
||||
</Text>
|
||||
</UIExplorerBlock>
|
||||
<UIExplorerBlock title="Colorful pickers">
|
||||
<PickerAndroid style={{width: 100, height: 56, color: 'black'}}
|
||||
onSelect={this.onSelect.bind(this, 'color')}
|
||||
<Picker
|
||||
style={[styles.picker, {color: 'white', backgroundColor: '#333'}]}
|
||||
selectedValue={this.state.color}
|
||||
onValueChange={this.onValueChange.bind(this, 'color')}
|
||||
mode="dropdown">
|
||||
<Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
|
||||
<Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
|
||||
<Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'}/>
|
||||
</PickerAndroid>
|
||||
<PickerAndroid style={{width: 100, height: 56}}
|
||||
onSelect={this.onSelect.bind(this, 'color')}
|
||||
<Item label="red" color="red" value="red" />
|
||||
<Item label="green" color="green" value="green" />
|
||||
<Item label="blue" color="blue" value="blue" />
|
||||
</Picker>
|
||||
<Picker
|
||||
style={styles.picker}
|
||||
selectedValue={this.state.color}
|
||||
onValueChange={this.onValueChange.bind(this, 'color')}
|
||||
mode="dialog">
|
||||
<Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
|
||||
<Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
|
||||
<Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'} />
|
||||
</PickerAndroid>
|
||||
<Item label="red" color="red" value="red" />
|
||||
<Item label="green" color="green" value="green" />
|
||||
<Item label="blue" color="blue" value="blue" />
|
||||
</Picker>
|
||||
</UIExplorerBlock>
|
||||
</UIExplorerPage>
|
||||
);
|
||||
},
|
||||
|
||||
changeMode: function() {
|
||||
const newMode = this.state.mode === PickerAndroid.MODE_DIALOG
|
||||
? PickerAndroid.MODE_DROPDOWN
|
||||
: PickerAndroid.MODE_DIALOG;
|
||||
const newMode = this.state.mode === Picker.MODE_DIALOG
|
||||
? Picker.MODE_DROPDOWN
|
||||
: Picker.MODE_DIALOG;
|
||||
this.setState({mode: newMode});
|
||||
},
|
||||
|
||||
onSelect: function(key, value) {
|
||||
onValueChange: function(key: string, value: string) {
|
||||
const newState = {};
|
||||
newState[key] = value;
|
||||
this.setState(newState);
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = '<PickerAndroid>';
|
||||
exports.displayName = 'PickerAndroidExample';
|
||||
exports.description = 'The Android Picker component provides multiple options to choose from';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'PickerAndroidExample',
|
||||
render(): ReactElement { return <PickerAndroidExample />; }
|
||||
var styles = StyleSheet.create({
|
||||
picker: {
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
module.exports = PickerExample;
|
||||
|
||||
@@ -348,25 +348,19 @@ exports.examples = [
|
||||
placeholder="multiline, aligned top-left"
|
||||
placeholderTextColor="red"
|
||||
multiline={true}
|
||||
textAlign="start"
|
||||
textAlignVertical="top"
|
||||
style={styles.multiline}
|
||||
style={[styles.multiline, {textAlign: "left", textAlignVertical: "top"}]}
|
||||
/>
|
||||
<TextInput
|
||||
autoCorrect={true}
|
||||
placeholder="multiline, aligned center"
|
||||
placeholderTextColor="green"
|
||||
multiline={true}
|
||||
textAlign="center"
|
||||
textAlignVertical="center"
|
||||
style={[styles.multiline]}
|
||||
style={[styles.multiline, {textAlign: "center", textAlignVertical: "center"}]}
|
||||
/>
|
||||
<TextInput
|
||||
autoCorrect={true}
|
||||
multiline={true}
|
||||
textAlign="end"
|
||||
textAlignVertical="bottom"
|
||||
style={[styles.multiline, {color: 'blue'}]}>
|
||||
style={[styles.multiline, {color: 'blue'}, {textAlign: "right", textAlignVertical: "bottom"}]}>
|
||||
<Text style={styles.multiline}>multiline with children, aligned bottom-right</Text>
|
||||
</TextInput>
|
||||
</View>
|
||||
|
||||
@@ -43,6 +43,7 @@ var COMPONENTS = [
|
||||
var APIS = [
|
||||
require('./AccessibilityAndroidExample.android'),
|
||||
require('./AlertExample').AlertExample,
|
||||
require('./AppStateExample'),
|
||||
require('./BorderExample'),
|
||||
require('./CameraRollExample'),
|
||||
require('./ClipboardExample'),
|
||||
|
||||
@@ -64,6 +64,7 @@ var APIS = [
|
||||
require('./AnimatedExample'),
|
||||
require('./AnimatedGratuitousApp/AnExApp'),
|
||||
require('./AppStateIOSExample'),
|
||||
require('./AppStateExample'),
|
||||
require('./AsyncStorageExample'),
|
||||
require('./BorderExample'),
|
||||
require('./BoxShadowExample'),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule AppState
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var Map = require('Map');
|
||||
var NativeModules = require('NativeModules');
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var RCTAppState = NativeModules.AppState;
|
||||
|
||||
var logError = require('logError');
|
||||
var invariant = require('invariant');
|
||||
|
||||
var _eventHandlers = {
|
||||
change: new Map(),
|
||||
memoryWarning: new Map(),
|
||||
};
|
||||
|
||||
/**
|
||||
* `AppState` can tell you if the app is in the foreground or background,
|
||||
* and notify you when the state changes.
|
||||
*
|
||||
* AppState is frequently used to determine the intent and proper behavior when
|
||||
* handling push notifications.
|
||||
*
|
||||
* ### App States
|
||||
*
|
||||
* - `active` - The app is running in the foreground
|
||||
* - `background` - The app is running in the background. The user is either
|
||||
* in another app or on the home screen
|
||||
* - `inactive` - This is a transition state that currently never happens for
|
||||
* typical React Native apps.
|
||||
*
|
||||
* For more information, see
|
||||
* [Apple's documentation](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)
|
||||
*
|
||||
* ### Basic Usage
|
||||
*
|
||||
* To see the current state, you can check `AppState.currentState`, which
|
||||
* will be kept up-to-date. However, `currentState` will be null at launch
|
||||
* while `AppState` retrieves it over the bridge.
|
||||
*
|
||||
* ```
|
||||
* getInitialState: function() {
|
||||
* return {
|
||||
* currentAppState: AppState.currentState,
|
||||
* };
|
||||
* },
|
||||
* componentDidMount: function() {
|
||||
* AppState.addEventListener('change', this._handleAppStateChange);
|
||||
* },
|
||||
* componentWillUnmount: function() {
|
||||
* AppState.removeEventListener('change', this._handleAppStateChange);
|
||||
* },
|
||||
* _handleAppStateChange: function(currentAppState) {
|
||||
* this.setState({ currentAppState, });
|
||||
* },
|
||||
* render: function() {
|
||||
* return (
|
||||
* <Text>Current state is: {this.state.currentAppState}</Text>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*
|
||||
* This example will only ever appear to say "Current state is: active" because
|
||||
* the app is only visible to the user when in the `active` state, and the null
|
||||
* state will happen only momentarily.
|
||||
*/
|
||||
|
||||
var AppState = {
|
||||
|
||||
/**
|
||||
* Add a handler to AppState changes by listening to the `change` event type
|
||||
* and providing the handler
|
||||
*/
|
||||
addEventListener: function(
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
'Trying to subscribe to unknown event: "%s"', type
|
||||
);
|
||||
if (type === 'change') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
handler(appStateData.app_state);
|
||||
}
|
||||
));
|
||||
} else if (type === 'memoryWarning') {
|
||||
_eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
|
||||
'memoryWarning',
|
||||
handler
|
||||
));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a handler by passing the `change` event type and the handler
|
||||
*/
|
||||
removeEventListener: function(
|
||||
type: string,
|
||||
handler: Function
|
||||
) {
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
'Trying to remove listener for unknown event: "%s"', type
|
||||
);
|
||||
if (!_eventHandlers[type].has(handler)) {
|
||||
return;
|
||||
}
|
||||
_eventHandlers[type].get(handler).remove();
|
||||
_eventHandlers[type].delete(handler);
|
||||
},
|
||||
|
||||
// TODO: getCurrentAppState callback seems to be called at a really late stage
|
||||
// after app launch. Trying to get currentState when mounting App component
|
||||
// will likely to have the initial value here.
|
||||
// Initialize to 'active' instead of null.
|
||||
currentState: ('active' : ?string),
|
||||
|
||||
};
|
||||
|
||||
RCTDeviceEventEmitter.addListener(
|
||||
'appStateDidChange',
|
||||
(appStateData) => {
|
||||
AppState.currentState = appStateData.app_state;
|
||||
}
|
||||
);
|
||||
|
||||
RCTAppState.getCurrentAppState(
|
||||
(appStateData) => {
|
||||
AppState.currentState = appStateData.app_state;
|
||||
},
|
||||
logError
|
||||
);
|
||||
|
||||
module.exports = AppState;
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule Picker
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ColorPropType = require('ColorPropType');
|
||||
var PickerIOS = require('PickerIOS');
|
||||
var PickerAndroid = require('PickerAndroid');
|
||||
var Platform = require('Platform');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var TextStylePropTypes = require('TextStylePropTypes');
|
||||
var UnimplementedView = require('UnimplementedView');
|
||||
var View = require('View');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var itemStylePropType = StyleSheetPropType(TextStylePropTypes);
|
||||
|
||||
var pickerStyleType = StyleSheetPropType({
|
||||
...ViewStylePropTypes,
|
||||
color: ColorPropType,
|
||||
});
|
||||
|
||||
var MODE_DIALOG = 'dialog';
|
||||
var MODE_DROPDOWN = 'dropdown';
|
||||
|
||||
/**
|
||||
* Renders the native picker component on iOS and Android. Example:
|
||||
*
|
||||
* <Picker
|
||||
* selectedValue={this.state.language}
|
||||
* onValueChange={(lang) => this.setState({language: lang})}>
|
||||
* <Picker.Item label="Java" value="java" />
|
||||
* <Picker.Item label="JavaScript" value="js" />
|
||||
* </Picker>
|
||||
*
|
||||
* Note: The picker has a default fixed height which you can modify
|
||||
* using `style` if needed. To set the width, you can use `style`
|
||||
* as well, e.g. to set a fixed width or stretch the picker horizontally.
|
||||
*/
|
||||
var Picker = React.createClass({
|
||||
|
||||
statics: {
|
||||
/**
|
||||
* On Android, display the options in a dialog.
|
||||
*/
|
||||
MODE_DIALOG: MODE_DIALOG,
|
||||
/**
|
||||
* On Android, display the options in a dropdown (this is the default).
|
||||
*/
|
||||
MODE_DROPDOWN: MODE_DROPDOWN,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
mode: MODE_DIALOG,
|
||||
};
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
...View.propTypes,
|
||||
style: pickerStyleType,
|
||||
/**
|
||||
* Value matching value of one of the items. Can be a string or an integer.
|
||||
*/
|
||||
selectedValue: React.PropTypes.any,
|
||||
/**
|
||||
* Callback for when an item is selected. This is called with the following parameters:
|
||||
* - `itemValue`: the `value` prop of the item that was selected
|
||||
* - `itemPosition`: the index of the selected item in this picker
|
||||
*/
|
||||
onValueChange: React.PropTypes.func,
|
||||
/**
|
||||
* If set to false, the picker will be disabled, i.e. the user will not be able to make a
|
||||
* selection.
|
||||
* @platform android
|
||||
*/
|
||||
enabled: React.PropTypes.bool,
|
||||
/**
|
||||
* On Android, specifies how to display the selection items when the user taps on the picker:
|
||||
* - 'dialog': Show a modal dialog. This is the default.
|
||||
* - 'dropdown': Shows a dropdown anchored to the picker view
|
||||
*
|
||||
* @platform android
|
||||
*/
|
||||
mode: React.PropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
|
||||
/**
|
||||
* Style to apply to each of the item labels.
|
||||
* @platform ios
|
||||
*/
|
||||
itemStyle: itemStylePropType,
|
||||
/**
|
||||
* Prompt string for this picker, used on Android in dialog mode as the title of the dialog.
|
||||
* @platform android
|
||||
*/
|
||||
prompt: React.PropTypes.string,
|
||||
/**
|
||||
* Used to locate this view in end-to-end tests.
|
||||
*/
|
||||
testID: React.PropTypes.string,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (Platform.OS === 'ios') {
|
||||
return <PickerIOS {...this.props}>{this.props.children}</PickerIOS>;
|
||||
} else if (Platform.OS === 'android') {
|
||||
return <PickerAndroid {...this.props}>{this.props.children}</PickerAndroid>;
|
||||
} else {
|
||||
return <UnimplementedView />;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Individual selectable item in a Picker.
|
||||
*/
|
||||
Picker.Item = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* Text to display for this item.
|
||||
*/
|
||||
label: React.PropTypes.string.isRequired,
|
||||
/**
|
||||
* The value to be passed to picker's `onValueChange` callback when
|
||||
* this item is selected. Can be a string or an integer.
|
||||
*/
|
||||
value: React.PropTypes.any,
|
||||
/**
|
||||
* Color of this item's text.
|
||||
* @platform android
|
||||
*/
|
||||
color: ColorPropType,
|
||||
/**
|
||||
* Used to locate the item in end-to-end tests.
|
||||
*/
|
||||
testID: React.PropTypes.string,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// The items are not rendered directly
|
||||
throw null;
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Picker;
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule PickerAndroid
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ColorPropType = require('ColorPropType');
|
||||
var React = require('React');
|
||||
var ReactChildren = require('ReactChildren');
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var View = require('View');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var processColor = require('processColor');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
var REF_PICKER = 'picker';
|
||||
var MODE_DIALOG = 'dialog';
|
||||
var MODE_DROPDOWN = 'dropdown';
|
||||
|
||||
var pickerStyleType = StyleSheetPropType({
|
||||
...ViewStylePropTypes,
|
||||
color: ColorPropType,
|
||||
});
|
||||
|
||||
type Event = Object;
|
||||
|
||||
/**
|
||||
* Not exposed as a public API - use <Picker> instead.
|
||||
*/
|
||||
var PickerAndroid = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
...View.propTypes,
|
||||
style: pickerStyleType,
|
||||
selectedValue: React.PropTypes.any,
|
||||
enabled: ReactPropTypes.bool,
|
||||
mode: ReactPropTypes.oneOf(['dialog', 'dropdown']),
|
||||
onValueChange: ReactPropTypes.func,
|
||||
prompt: ReactPropTypes.string,
|
||||
testID: ReactPropTypes.string,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this._stateFromProps(this.props);
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
this.setState(this._stateFromProps(nextProps));
|
||||
},
|
||||
|
||||
// Translate prop and children into stuff that the native picker understands.
|
||||
_stateFromProps: function(props) {
|
||||
var selectedIndex = 0;
|
||||
let items = ReactChildren.map(props.children, (child, index) => {
|
||||
if (child.props.value === props.selectedValue) {
|
||||
selectedIndex = index;
|
||||
}
|
||||
let childProps = {
|
||||
value: child.props.value,
|
||||
label: child.props.label,
|
||||
};
|
||||
if (child.props.color) {
|
||||
childProps.color = processColor(child.props.color);
|
||||
}
|
||||
return childProps;
|
||||
});
|
||||
return {selectedIndex, items};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
|
||||
|
||||
var nativeProps = {
|
||||
enabled: this.props.enabled,
|
||||
items: this.state.items,
|
||||
mode: this.props.mode,
|
||||
onSelect: this._onChange,
|
||||
prompt: this.props.prompt,
|
||||
selected: this.state.selectedIndex,
|
||||
testID: this.props.testID,
|
||||
style: [styles.pickerAndroid, this.props.style],
|
||||
};
|
||||
|
||||
return <Picker ref={REF_PICKER} {...nativeProps} />;
|
||||
},
|
||||
|
||||
_onChange: function(event: Event) {
|
||||
if (this.props.onValueChange) {
|
||||
var position = event.nativeEvent.position;
|
||||
if (position >= 0) {
|
||||
var value = this.props.children[position].props.value;
|
||||
this.props.onValueChange(value);
|
||||
} else {
|
||||
this.props.onValueChange(null);
|
||||
}
|
||||
}
|
||||
|
||||
// The picker is a controlled component. This means we expect the
|
||||
// on*Change handlers to be in charge of updating our
|
||||
// `selectedValue` prop. That way they can also
|
||||
// disallow/undo/mutate the selection of certain values. In other
|
||||
// words, the embedder of this component should be the source of
|
||||
// truth, not the native component.
|
||||
if (this.refs[REF_PICKER] && this.state.selectedIndex !== event.nativeEvent.position) {
|
||||
this.refs[REF_PICKER].setNativeProps({selected: this.state.selectedIndex});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
pickerAndroid: {
|
||||
// We have to set the picker's dimensions explicitly to ensure
|
||||
// it gets rendered.
|
||||
// TODO would be better to export a native constant for this,
|
||||
// like in iOS the RCTDatePickerManager.m
|
||||
width: 80,
|
||||
height: 50,
|
||||
},
|
||||
});
|
||||
|
||||
var cfg = {
|
||||
nativeOnly: {
|
||||
items: true,
|
||||
selected: true,
|
||||
}
|
||||
}
|
||||
var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
|
||||
var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
|
||||
|
||||
module.exports = PickerAndroid;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule PickerAndroid
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = require('UnimplementedView');
|
||||
@@ -1,213 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule PickerAndroid
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ColorPropType = require('ColorPropType');
|
||||
var React = require('React');
|
||||
var ReactChildren = require('ReactChildren');
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var View = require('View');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var processColor = require('processColor');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
var MODE_DIALOG = 'dialog';
|
||||
var MODE_DROPDOWN = 'dropdown';
|
||||
var REF_PICKER = 'picker';
|
||||
|
||||
var pickerStyleType = StyleSheetPropType({
|
||||
...ViewStylePropTypes,
|
||||
color: ColorPropType,
|
||||
});
|
||||
|
||||
type Items = {
|
||||
selected: number;
|
||||
items: any[];
|
||||
};
|
||||
|
||||
type Event = Object;
|
||||
|
||||
/**
|
||||
* Individual selectable item in a Picker.
|
||||
*/
|
||||
var Item = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* Color of this item's text.
|
||||
*/
|
||||
color: ColorPropType,
|
||||
/**
|
||||
* Text to display for this item.
|
||||
*/
|
||||
text: ReactPropTypes.string.isRequired,
|
||||
/**
|
||||
* The value to be passed to picker's `onSelect` callback when this item is selected.
|
||||
*/
|
||||
value: ReactPropTypes.string,
|
||||
/**
|
||||
* If `true`, this item is selected and shown in the picker.
|
||||
* Usually this is set based on state.
|
||||
*/
|
||||
selected: ReactPropTypes.bool,
|
||||
/**
|
||||
* Used to locate this view in end-to-end tests.
|
||||
*/
|
||||
testID: ReactPropTypes.string,
|
||||
},
|
||||
|
||||
render: function() {
|
||||
throw new Error('Picker items should never be rendered');
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* <PickerAndroid> - A React component that renders the native Picker widget on Android. The items
|
||||
* that can be selected are specified as children views of type Item. Example usage:
|
||||
*
|
||||
* <PickerAndroid>
|
||||
* <PickerAndroid.Item text="Java" value="js" />
|
||||
* <PickerAndroid.Item text="JavaScript" value="java" selected={true} />
|
||||
* </PickerAndroid>
|
||||
*/
|
||||
var PickerAndroid = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
...View.propTypes,
|
||||
style: pickerStyleType,
|
||||
/**
|
||||
* If set to false, the picker will be disabled, i.e. the user will not be able to make a
|
||||
* selection.
|
||||
*/
|
||||
enabled: ReactPropTypes.bool,
|
||||
/**
|
||||
* Specifies how to display the selection items when the user taps on the picker:
|
||||
*
|
||||
* - dialog: Show a modal dialog
|
||||
* - dropdown: Shows a dropdown anchored to the picker view
|
||||
*/
|
||||
mode: ReactPropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
|
||||
/**
|
||||
* Callback for when an item is selected. This is called with the following parameters:
|
||||
*
|
||||
* - `itemValue`: the `value` prop of the item that was selected
|
||||
* - `itemPosition`: the index of the selected item in this picker
|
||||
*/
|
||||
onSelect: ReactPropTypes.func,
|
||||
/**
|
||||
* Prompt string for this picker, currently only used in `dialog` mode as the title of the
|
||||
* dialog.
|
||||
*/
|
||||
prompt: ReactPropTypes.string,
|
||||
/**
|
||||
* Used to locate this view in end-to-end tests.
|
||||
*/
|
||||
testID: ReactPropTypes.string,
|
||||
},
|
||||
|
||||
statics: {
|
||||
Item: Item,
|
||||
MODE_DIALOG: MODE_DIALOG,
|
||||
MODE_DROPDOWN: MODE_DROPDOWN,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
mode: MODE_DIALOG,
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
|
||||
|
||||
var { selected, items } = this._getItems();
|
||||
|
||||
var nativeProps = {
|
||||
enabled: this.props.enabled,
|
||||
items: items,
|
||||
mode: this.props.mode,
|
||||
onSelect: this._onSelect,
|
||||
prompt: this.props.prompt,
|
||||
selected: selected,
|
||||
style: this.props.style,
|
||||
testID: this.props.testID,
|
||||
};
|
||||
|
||||
return <Picker ref={REF_PICKER} {...nativeProps} />;
|
||||
},
|
||||
|
||||
/**
|
||||
* Transform this view's children into an array of items to be passed to the native component.
|
||||
* Since we're traversing the children, also determine the selected position.
|
||||
*
|
||||
* @returns an object with two keys:
|
||||
*
|
||||
* - `selected` (number) - the index of the selected item
|
||||
* - `items` (array) - the items of this picker, as an array of strings
|
||||
*/
|
||||
_getItems: function(): Items {
|
||||
var items = [];
|
||||
var selected = 0;
|
||||
ReactChildren.forEach(this.props.children, function(child, index) {
|
||||
var childProps = Object.assign({}, child.props);
|
||||
if (childProps.color) {
|
||||
childProps.color = processColor(childProps.color);
|
||||
}
|
||||
items.push(childProps);
|
||||
if (childProps.selected) {
|
||||
selected = index;
|
||||
}
|
||||
});
|
||||
return {
|
||||
selected: selected,
|
||||
items: items,
|
||||
};
|
||||
},
|
||||
|
||||
_onSelect: function(event: Event) {
|
||||
if (this.props.onSelect) {
|
||||
var position = event.nativeEvent.position;
|
||||
if (position >= 0) {
|
||||
var value = this.props.children[position].props.value;
|
||||
this.props.onSelect(value, position);
|
||||
} else {
|
||||
this.props.onSelect(null, position);
|
||||
}
|
||||
}
|
||||
|
||||
// The native Picker has changed, but the props haven't (yet). If
|
||||
// the handler decides to not accept the new value or do something
|
||||
// else with it we might end up in a bad state, so we reset the
|
||||
// selection on the native component.
|
||||
// tl;dr: PickerAndroid is a controlled component.
|
||||
var { selected } = this._getItems();
|
||||
if (this.refs[REF_PICKER]) {
|
||||
this.refs[REF_PICKER].setNativeProps({selected: selected});
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var cfg = {
|
||||
nativeOnly: {
|
||||
items: true,
|
||||
selected: true,
|
||||
}
|
||||
}
|
||||
var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
|
||||
var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
|
||||
|
||||
module.exports = PickerAndroid;
|
||||
@@ -298,7 +298,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,
|
||||
|
||||
|
||||
@@ -101,24 +101,6 @@ var TextInput = React.createClass({
|
||||
* The default value is false.
|
||||
*/
|
||||
autoFocus: PropTypes.bool,
|
||||
/**
|
||||
* Set the position of the cursor from where editing will begin.
|
||||
* @platform android
|
||||
*/
|
||||
textAlign: PropTypes.oneOf([
|
||||
'start',
|
||||
'center',
|
||||
'end',
|
||||
]),
|
||||
/**
|
||||
* Aligns text vertically within the TextInput.
|
||||
* @platform android
|
||||
*/
|
||||
textAlignVertical: PropTypes.oneOf([
|
||||
'top',
|
||||
'center',
|
||||
'bottom',
|
||||
]),
|
||||
/**
|
||||
* If false, text is not editable. The default value is true.
|
||||
*/
|
||||
@@ -491,10 +473,6 @@ var TextInput = React.createClass({
|
||||
|
||||
var autoCapitalize =
|
||||
UIManager.AndroidTextInput.Constants.AutoCapitalizationType[this.props.autoCapitalize];
|
||||
var textAlign = UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
|
||||
var textAlignVertical =
|
||||
UIManager.AndroidTextInput.Constants.TextAlignVertical[this.props.textAlignVertical];
|
||||
|
||||
var children = this.props.children;
|
||||
var childCount = 0;
|
||||
ReactChildren.forEach(children, () => ++childCount);
|
||||
@@ -512,8 +490,6 @@ var TextInput = React.createClass({
|
||||
style={[this.props.style]}
|
||||
autoCapitalize={autoCapitalize}
|
||||
autoCorrect={this.props.autoCorrect}
|
||||
textAlign={textAlign}
|
||||
textAlignVertical={textAlignVertical}
|
||||
keyboardType={this.props.keyboardType}
|
||||
mostRecentEventCount={0}
|
||||
multiline={this.props.multiline}
|
||||
|
||||
@@ -30,7 +30,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`
|
||||
|
||||
@@ -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__) {
|
||||
|
||||
@@ -46,6 +46,12 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
|
||||
textAlign: ReactPropTypes.oneOf(
|
||||
['auto' /*default*/, 'left', 'right', 'center', 'justify']
|
||||
),
|
||||
/**
|
||||
* @platform android
|
||||
*/
|
||||
textAlignVertical: ReactPropTypes.oneOf(
|
||||
['auto' /*default*/, 'top', 'bottom', 'center']
|
||||
),
|
||||
/**
|
||||
* @platform ios
|
||||
*/
|
||||
|
||||
+2
-1
@@ -25,7 +25,7 @@ var ReactNative = {
|
||||
get Modal() { return require('Modal'); },
|
||||
get Navigator() { return require('Navigator'); },
|
||||
get NavigatorIOS() { return require('NavigatorIOS'); },
|
||||
get PickerAndroid() { return require('PickerAndroid'); },
|
||||
get Picker() { return require('Picker'); },
|
||||
get PickerIOS() { return require('PickerIOS'); },
|
||||
get ProgressBarAndroid() { return require('ProgressBarAndroid'); },
|
||||
get ProgressViewIOS() { return require('ProgressViewIOS'); },
|
||||
@@ -60,6 +60,7 @@ var ReactNative = {
|
||||
get AlertIOS() { return require('AlertIOS'); },
|
||||
get Animated() { return require('Animated'); },
|
||||
get AppRegistry() { return require('AppRegistry'); },
|
||||
get AppState() { return require('AppState'); },
|
||||
get AppStateIOS() { return require('AppStateIOS'); },
|
||||
get AsyncStorage() { return require('AsyncStorage'); },
|
||||
get BackAndroid() { return require('BackAndroid'); },
|
||||
|
||||
@@ -37,7 +37,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
|
||||
Modal: require('Modal'),
|
||||
Navigator: require('Navigator'),
|
||||
NavigatorIOS: require('NavigatorIOS'),
|
||||
PickerAndroid: require('PickerAndroid'),
|
||||
Picker: require('Picker'),
|
||||
PickerIOS: require('PickerIOS'),
|
||||
ProgressBarAndroid: require('ProgressBarAndroid'),
|
||||
ProgressViewIOS: require('ProgressViewIOS'),
|
||||
@@ -72,6 +72,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
|
||||
AlertIOS: require('AlertIOS'),
|
||||
Animated: require('Animated'),
|
||||
AppRegistry: require('AppRegistry'),
|
||||
AppState: require('AppState'),
|
||||
AppStateIOS: require('AppStateIOS'),
|
||||
AsyncStorage: require('AsyncStorage'),
|
||||
BackAndroid: require('BackAndroid'),
|
||||
|
||||
@@ -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
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React"
|
||||
s.version = "0.0.0-master"
|
||||
s.version = "0.19.0"
|
||||
s.summary = "Build high quality mobile apps using React."
|
||||
s.description = <<-DESC
|
||||
React Native apps are built using the React JS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=0.12.0-SNAPSHOT
|
||||
VERSION_NAME=0.19.1
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.appstate;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
|
||||
|
||||
public class AppStateModule extends ReactContextBaseJavaModule
|
||||
implements LifecycleEventListener {
|
||||
|
||||
public static final String APP_STATE_ACTIVE = "active";
|
||||
public static final String APP_STATE_BACKGROUND = "background";
|
||||
|
||||
private String mAppState = "uninitialized";
|
||||
|
||||
public AppStateModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "AppState";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
getReactApplicationContext().addLifecycleEventListener(this);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getCurrentAppState(Callback success, Callback error) {
|
||||
success.invoke(createAppStateEventMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
mAppState = APP_STATE_ACTIVE;
|
||||
sendAppStateChangeEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
mAppState = APP_STATE_BACKGROUND;
|
||||
sendAppStateChangeEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostDestroy() {
|
||||
// do not set state to destroyed, do not send an event. By the current implementation, the
|
||||
// catalyst instance is going to be immediately dropped, and all JS calls with it.
|
||||
}
|
||||
|
||||
private WritableMap createAppStateEventMap() {
|
||||
WritableMap appState = Arguments.createMap();
|
||||
appState.putString("app_state", mAppState);
|
||||
return appState;
|
||||
}
|
||||
|
||||
private void sendAppStateChangeEvent() {
|
||||
getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
|
||||
.emit("appStateDidChange", createAppStateEventMap());
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.facebook.react.modules.netinfo.NetInfoModule;
|
||||
import com.facebook.react.modules.network.NetworkingModule;
|
||||
import com.facebook.react.modules.storage.AsyncStorageModule;
|
||||
import com.facebook.react.modules.toast.ToastModule;
|
||||
import com.facebook.react.modules.appstate.AppStateModule;
|
||||
import com.facebook.react.modules.websocket.WebSocketModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.react.views.art.ARTRenderableViewManager;
|
||||
@@ -59,6 +60,7 @@ public class MainReactPackage implements ReactPackage {
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
return Arrays.<NativeModule>asList(
|
||||
new AppStateModule(reactContext),
|
||||
new AsyncStorageModule(reactContext),
|
||||
new CameraRollManager(reactContext),
|
||||
new ClipboardModule(reactContext),
|
||||
@@ -68,8 +70,8 @@ public class MainReactPackage implements ReactPackage {
|
||||
new LocationModule(reactContext),
|
||||
new NetworkingModule(reactContext),
|
||||
new NetInfoModule(reactContext),
|
||||
new WebSocketModule(reactContext),
|
||||
new ToastModule(reactContext));
|
||||
new ToastModule(reactContext),
|
||||
new WebSocketModule(reactContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,17 +93,17 @@ public class MainReactPackage implements ReactPackage {
|
||||
new ReactImageManager(),
|
||||
new ReactProgressBarViewManager(),
|
||||
new ReactRawTextManager(),
|
||||
new RecyclerViewBackedScrollViewManager(),
|
||||
new ReactScrollViewManager(),
|
||||
new ReactSwitchManager(),
|
||||
new ReactTextInlineImageViewManager(),
|
||||
new ReactTextInputManager(),
|
||||
new ReactTextViewManager(),
|
||||
new ReactToolbarManager(),
|
||||
new ReactViewManager(),
|
||||
new ReactViewPagerManager(),
|
||||
new ReactTextInlineImageViewManager(),
|
||||
new ReactVirtualTextViewManager(),
|
||||
new SwipeRefreshLayoutManager(),
|
||||
new ReactWebViewManager());
|
||||
new ReactWebViewManager(),
|
||||
new RecyclerViewBackedScrollViewManager(),
|
||||
new SwipeRefreshLayoutManager());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ public class ViewProps {
|
||||
public static final String ON = "on";
|
||||
public static final String RESIZE_MODE = "resizeMode";
|
||||
public static final String TEXT_ALIGN = "textAlign";
|
||||
public static final String TEXT_ALIGN_VERTICAL = "textAlignVertical";
|
||||
|
||||
public static final String BORDER_WIDTH = "borderWidth";
|
||||
public static final String BORDER_LEFT_WIDTH = "borderLeftWidth";
|
||||
|
||||
@@ -352,11 +352,11 @@ public class ReactImageView extends GenericDraweeView {
|
||||
return resId > 0 ? context.getResources().getDrawable(resId) : null;
|
||||
}
|
||||
|
||||
private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
|
||||
private static Uri getResourceDrawableUri(Context context, @Nullable String name) {
|
||||
int resId = getResourceDrawableId(context, name);
|
||||
return resId > 0 ? new Uri.Builder()
|
||||
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
|
||||
.path(String.valueOf(resId))
|
||||
.build() : null;
|
||||
.build() : Uri.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public abstract class ReactPickerManager extends SimpleViewManager<ReactPicker>
|
||||
}
|
||||
|
||||
TextView textView = (TextView) convertView;
|
||||
textView.setText(item.getString("text"));
|
||||
textView.setText(item.getString("label"));
|
||||
if (!isDropdown && mPrimaryTextColor != null) {
|
||||
textView.setTextColor(mPrimaryTextColor);
|
||||
} else if (item.hasKey("color") && !item.isNull("color")) {
|
||||
|
||||
+28
-16
@@ -28,6 +28,8 @@ 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;
|
||||
@@ -202,14 +204,34 @@ public class ReactTextInputManager extends
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "textAlign")
|
||||
public void setTextAlign(ReactEditText view, int gravity) {
|
||||
view.setGravityHorizontal(gravity);
|
||||
@ReactProp(name = ViewProps.TEXT_ALIGN)
|
||||
public void setTextAlign(ReactEditText view, @Nullable String textAlign) {
|
||||
if (textAlign == null || "auto".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.NO_GRAVITY);
|
||||
} else if ("left".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.LEFT);
|
||||
} else if ("right".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.RIGHT);
|
||||
} else if ("center".equals(textAlign)) {
|
||||
view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL);
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "textAlignVertical")
|
||||
public void setTextAlignVertical(ReactEditText view, int gravity) {
|
||||
view.setGravityVertical(gravity);
|
||||
@ReactProp(name = ViewProps.TEXT_ALIGN_VERTICAL)
|
||||
public void setTextAlignVertical(ReactEditText view, @Nullable String textAlignVertical) {
|
||||
if (textAlignVertical == null || "auto".equals(textAlignVertical)) {
|
||||
view.setGravityVertical(Gravity.NO_GRAVITY);
|
||||
} else if ("top".equals(textAlignVertical)) {
|
||||
view.setGravityVertical(Gravity.TOP);
|
||||
} else if ("bottom".equals(textAlignVertical)) {
|
||||
view.setGravityVertical(Gravity.BOTTOM);
|
||||
} else if ("center".equals(textAlignVertical)) {
|
||||
view.setGravityVertical(Gravity.CENTER_VERTICAL);
|
||||
} else {
|
||||
throw new JSApplicationIllegalArgumentException("Invalid textAlignVertical: " + textAlignVertical);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "editable", defaultBoolean = true)
|
||||
@@ -474,16 +496,6 @@ public class ReactTextInputManager extends
|
||||
@Override
|
||||
public @Nullable Map getExportedViewConstants() {
|
||||
return MapBuilder.of(
|
||||
"TextAlign",
|
||||
MapBuilder.of(
|
||||
"start", Gravity.START,
|
||||
"center", Gravity.CENTER_HORIZONTAL,
|
||||
"end", Gravity.END),
|
||||
"TextAlignVertical",
|
||||
MapBuilder.of(
|
||||
"top", Gravity.TOP,
|
||||
"center", Gravity.CENTER_VERTICAL,
|
||||
"bottom", Gravity.BOTTOM),
|
||||
"AutoCapitalizationType",
|
||||
MapBuilder.of(
|
||||
"none",
|
||||
|
||||
+21
-4
@@ -13,12 +13,16 @@ machine:
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
# 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
|
||||
# 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
|
||||
cache_directories:
|
||||
- "ReactAndroid/build/downloads"
|
||||
override:
|
||||
- npm install
|
||||
- cd website && npm install
|
||||
|
||||
test:
|
||||
pre:
|
||||
# starting emulator in advance because it takes very long to boot
|
||||
@@ -28,6 +32,7 @@ test:
|
||||
- ./gradlew :ReactAndroid:assembleDebug -PdisablePreDex -Pjobs=1:
|
||||
timeout: 360
|
||||
- source scripts/circle-ci-android-setup.sh && waitForAVD
|
||||
|
||||
override:
|
||||
# unit tests
|
||||
- ./gradlew :ReactAndroid:testDebugUnitTest -PdisablePreDex
|
||||
@@ -36,9 +41,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
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||

|
||||
|
||||
**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:
|
||||
|
||||

|
||||

|
||||
|
||||
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`:
|
||||
|
||||

|
||||

|
||||
|
||||
### 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:
|
||||
|
||||

|
||||

|
||||
|
||||
### 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`:
|
||||
|
||||

|
||||

|
||||
|
||||
### 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`:
|
||||
|
||||

|
||||

|
||||
|
||||
## Identifying a culprit
|
||||
|
||||
A smooth animation should look something like the following:
|
||||
|
||||

|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||

|
||||
|
||||
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
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
```javascript
|
||||
var App = React.createClass({
|
||||
@@ -376,7 +376,7 @@ var App = React.createClass({
|
||||
```
|
||||
[Run this example](https://rnplay.org/apps/4FUQ-A)
|
||||
|
||||

|
||||

|
||||
|
||||
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`.
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
||||
 Screenshot from
|
||||
 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
 
|
||||
 
|
||||
|
||||
### 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...**
|
||||

|
||||

|
||||
2. With the new AVD selected, click `Start...`
|
||||
5. To bring up the developer menu press F2 (or install [Frappé](http://getfrappe.com))
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||

|
||||
|
||||
## Sharing a ReactInstance across multiple Activities / Fragments in your app
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
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`.
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
@@ -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
@@ -39,7 +39,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
|
||||
|
||||
@@ -64,7 +64,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
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ folder.
|
||||
Drag this file to your project on Xcode (usually under the `Libraries` group
|
||||
on Xcode);
|
||||
|
||||

|
||||

|
||||
|
||||
#### 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`
|
||||
|
||||

|
||||

|
||||
|
||||
#### 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).
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -44,7 +44,7 @@ Note that on 0.14 we'll change the API of `react-native bundle`. The major chang
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -110,8 +110,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>
|
||||
|
||||
|
||||
@@ -188,8 +188,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
|
||||
@@ -280,8 +280,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
|
||||
@@ -363,8 +363,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
@@ -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:
|
||||
|
||||
|
||||
@@ -60,8 +60,7 @@ import com.android.build.OutputFile
|
||||
apply from: "react.gradle"
|
||||
|
||||
/**
|
||||
* Set this to true to create three separate APKs instead of one:
|
||||
* - A universal APK that works on all devices
|
||||
* Set this to true to create two separate APKs instead of one:
|
||||
* - An APK that only works on ARM devices
|
||||
* - An APK that only works on x86 devices
|
||||
* The advantage is the size of the APK is reduced by about 4MB.
|
||||
@@ -92,7 +91,7 @@ android {
|
||||
splits {
|
||||
abi {
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk true
|
||||
universalApk false // Also generate an universal APK
|
||||
reset()
|
||||
include "armeabi-v7a", "x86"
|
||||
}
|
||||
@@ -121,5 +120,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.19.+"
|
||||
}
|
||||
|
||||
@@ -525,7 +525,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../node_modules/react-native/packager/react-native-xcode.sh";
|
||||
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
|
||||
showEnvVarsInLog = 1;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"version": "0.0.0-master",
|
||||
"version": "0.19.0",
|
||||
"description": "A framework for building native apps using React",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": {
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
# This script is supposed to be invoked as part of Xcode build process
|
||||
# and relies on envoronment variables (including PWD) set by Xcode
|
||||
|
||||
# There is no point in creating an offline package for simulator builds
|
||||
# because the packager is supposed to be running during development anyways
|
||||
if [[ "$PLATFORM_NAME" = "iphonesimulator" ]]; then
|
||||
echo "Skipping bundling for Simulator platform"
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
case "$CONFIGURATION" in
|
||||
Debug)
|
||||
DEV=true
|
||||
@@ -23,12 +30,12 @@ case "$CONFIGURATION" in
|
||||
;;
|
||||
esac
|
||||
|
||||
# Path to react-native folder inside node_modules
|
||||
REACT_NATIVE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
# Xcode project file for React Native apps is located in ios/ subfolder
|
||||
cd ..
|
||||
|
||||
set -x
|
||||
DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
|
||||
|
||||
# Define NVM_DIR and source the nvm.sh setup script
|
||||
[ -z "$NVM_DIR" ] && export NVM_DIR="$HOME/.nvm"
|
||||
|
||||
@@ -43,10 +50,25 @@ if [[ -x "$HOME/.nodenv/bin/nodenv" ]]; then
|
||||
eval "$($HOME/.nodenv/bin/nodenv init -)"
|
||||
fi
|
||||
|
||||
# npm global install path may be a non-standard location
|
||||
PATH="$(npm prefix -g)/bin:$PATH"
|
||||
[ -z "$NODE_BINARY" ] && export NODE_BINARY="node"
|
||||
|
||||
react-native bundle \
|
||||
nodejs_not_found()
|
||||
{
|
||||
echo "error: Can't find '$NODE_BINARY' binary to build React Native bundle" >&2
|
||||
echo "If you have non-standard nodejs installation, select your project in Xcode," >&2
|
||||
echo "find 'Build Phases' - 'Bundle React Native code and images'" >&2
|
||||
echo "and change NODE_BINARY to absolute path to your node executable" >&2
|
||||
echo "(you can find it by invoking 'which node' in the terminal)" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
type $NODE_BINARY >/dev/null 2>&1 || nodejs_not_found
|
||||
|
||||
# Print commands before executing them (useful for troubleshooting)
|
||||
set -x
|
||||
DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
|
||||
|
||||
$NODE_BINARY $REACT_NATIVE_DIR/local-cli/cli.js bundle \
|
||||
--entry-file index.ios.js \
|
||||
--platform ios \
|
||||
--dev $DEV \
|
||||
|
||||
@@ -47,7 +47,6 @@ 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"
|
||||
done
|
||||
|
||||
success "Generated artifacts for Maven"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
src/react-native/docs/**
|
||||
core/metadata.js
|
||||
*.log
|
||||
/build/
|
||||
|
||||
+2
-8
@@ -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
|
||||
```
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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>
|
||||
);
|
||||
|
||||
+10
-7
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -121,6 +121,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' +
|
||||
|
||||
@@ -225,6 +225,7 @@ var apis = [
|
||||
'../Libraries/Animated/src/AnimatedImplementation.js',
|
||||
'../Libraries/AppRegistry/AppRegistry.js',
|
||||
'../Libraries/AppStateIOS/AppStateIOS.ios.js',
|
||||
'../Libraries/AppState/AppState.js',
|
||||
'../Libraries/Storage/AsyncStorage.js',
|
||||
'../Libraries/Utilities/BackAndroid.android.js',
|
||||
'../Libraries/CameraRoll/CameraRoll.js',
|
||||
@@ -253,7 +254,7 @@ var styles = [
|
||||
];
|
||||
|
||||
var polyfills = [
|
||||
'../Libraries/GeoLocation/Geolocation.js',
|
||||
'../Libraries/Geolocation/Geolocation.js',
|
||||
];
|
||||
|
||||
var all = components
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
general:
|
||||
branches:
|
||||
ignore:
|
||||
- gh-pages
|
||||
@@ -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;
|
||||
@@ -1241,7 +1258,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;
|
||||
|
||||
Vendored
+1
-1
@@ -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>
|
||||
|
||||
Vendored
+49
@@ -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;
|
||||
Reference in New Issue
Block a user