Updates from Wed 25 Mar
- [RFC][ReactNative] Integrate dev menu directly into RootView | Alex Kotliarskyi - flowify Libraries/ReactIOS | Marshall Roch - [WIP] Added support for italics and additional font weights | Nick Lockwood - [ReactNative] Improve View documentation | Christopher Chedeau - [react-packager] Readme | Amjad Masad - Fix for incorrect contentSize reported by RCTScrollView | Nick Lockwood - [ReactNative] Flow and doc formatting for NetInfo | Eric Vicenti - [ReactNative] Document AppStateIOS | Eric Vicenti
This commit is contained in:
parent
bd64b14fbe
commit
c7efc4dd11
|
@ -10,7 +10,8 @@
|
||||||
# Ignore react-tools where there are overlaps, but don't ignore anything that
|
# Ignore react-tools where there are overlaps, but don't ignore anything that
|
||||||
# react-native relies on
|
# react-native relies on
|
||||||
.*/node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js
|
.*/node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js
|
||||||
.*/node_modules/react-tools/src/browser/.*
|
.*/node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js
|
||||||
|
.*/node_modules/react-tools/src/browser/ui/React.js
|
||||||
.*/node_modules/react-tools/src/core/ReactInstanceHandles.js
|
.*/node_modules/react-tools/src/core/ReactInstanceHandles.js
|
||||||
.*/node_modules/react-tools/src/event/EventPropagators.js
|
.*/node_modules/react-tools/src/event/EventPropagators.js
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,7 @@ var styles = StyleSheet.create({
|
||||||
tryAgainText: {
|
tryAgainText: {
|
||||||
color: '#ffffff',
|
color: '#ffffff',
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
cell: {
|
cell: {
|
||||||
width: CELL_SIZE,
|
width: CELL_SIZE,
|
||||||
|
@ -259,7 +259,7 @@ var styles = StyleSheet.create({
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: '#776666',
|
color: '#776666',
|
||||||
fontFamily: 'Verdana',
|
fontFamily: 'Verdana',
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
tile2: {
|
tile2: {
|
||||||
backgroundColor: '#eeeeee',
|
backgroundColor: '#eeeeee',
|
||||||
|
|
|
@ -62,7 +62,7 @@ var styles = StyleSheet.create({
|
||||||
movieTitle: {
|
movieTitle: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
marginBottom: 2,
|
marginBottom: 2,
|
||||||
},
|
},
|
||||||
movieYear: {
|
movieYear: {
|
||||||
|
|
|
@ -109,7 +109,7 @@ var styles = StyleSheet.create({
|
||||||
movieTitle: {
|
movieTitle: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
rating: {
|
rating: {
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
|
@ -119,7 +119,7 @@ var styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
ratingValue: {
|
ratingValue: {
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
mpaaWrapper: {
|
mpaaWrapper: {
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
|
@ -131,7 +131,7 @@ var styles = StyleSheet.create({
|
||||||
mpaaText: {
|
mpaaText: {
|
||||||
fontFamily: 'Palatino',
|
fontFamily: 'Palatino',
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
mainSection: {
|
mainSection: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -148,7 +148,7 @@ var styles = StyleSheet.create({
|
||||||
marginVertical: 10,
|
marginVertical: 10,
|
||||||
},
|
},
|
||||||
castTitle: {
|
castTitle: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
marginBottom: 3,
|
marginBottom: 3,
|
||||||
},
|
},
|
||||||
castActor: {
|
castActor: {
|
||||||
|
|
|
@ -101,7 +101,7 @@ var ShareActionSheetExample = React.createClass({
|
||||||
var style = StyleSheet.create({
|
var style = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,6 @@ var AdSupportIOSExample = React.createClass({
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
title: {
|
title: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -149,14 +149,14 @@ var styles = StyleSheet.create({
|
||||||
paddingVertical: 2,
|
paddingVertical: 2,
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
headingContainer: {
|
headingContainer: {
|
||||||
padding: 4,
|
padding: 4,
|
||||||
backgroundColor: '#f6f7f8',
|
backgroundColor: '#f6f7f8',
|
||||||
},
|
},
|
||||||
heading: {
|
heading: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -74,6 +74,6 @@ var GeolocationExample = React.createClass({
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
title: {
|
title: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -214,7 +214,7 @@ var styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
rowText: {
|
rowText: {
|
||||||
fontSize: 17,
|
fontSize: 17,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -254,7 +254,7 @@ var styles = StyleSheet.create({
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: '#666666',
|
color: '#666666',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
lineHeight: 32,
|
lineHeight: 32,
|
||||||
},
|
},
|
||||||
filterText: {
|
filterText: {
|
||||||
|
|
|
@ -107,7 +107,7 @@ var styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
navBarTitleText: {
|
navBarTitleText: {
|
||||||
color: cssVar('fbui-bluegray-60'),
|
color: cssVar('fbui-bluegray-60'),
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
marginVertical: 9,
|
marginVertical: 9,
|
||||||
},
|
},
|
||||||
navBarButtonText: {
|
navBarButtonText: {
|
||||||
|
|
|
@ -176,7 +176,7 @@ var styles = StyleSheet.create({
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: '#666666',
|
color: '#666666',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
lineHeight: 32,
|
lineHeight: 32,
|
||||||
},
|
},
|
||||||
filterText: {
|
filterText: {
|
||||||
|
|
|
@ -47,7 +47,7 @@ var styles = StyleSheet.create({
|
||||||
text: {
|
text: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
margin: 10,
|
margin: 10,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,7 +29,7 @@ var Entity = React.createClass({
|
||||||
|
|
||||||
var AttributeToggler = React.createClass({
|
var AttributeToggler = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {fontWeight: 'bold', fontSize: 15};
|
return {fontWeight: '500', fontSize: 15};
|
||||||
},
|
},
|
||||||
increaseSize: function() {
|
increaseSize: function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -129,9 +129,37 @@ exports.examples = [
|
||||||
title: 'Font Weight',
|
title: 'Font Weight',
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<Text style={{fontWeight: 'bold'}}>
|
<View>
|
||||||
Move fast and be bold
|
<Text style={{fontWeight: '100'}}>
|
||||||
</Text>
|
Move fast and be ultralight
|
||||||
|
</Text>
|
||||||
|
<Text style={{fontWeight: '200'}}>
|
||||||
|
Move fast and be light
|
||||||
|
</Text>
|
||||||
|
<Text style={{fontWeight: 'normal'}}>
|
||||||
|
Move fast and be normal
|
||||||
|
</Text>
|
||||||
|
<Text style={{fontWeight: 'bold'}}>
|
||||||
|
Move fast and be bold
|
||||||
|
</Text>
|
||||||
|
<Text style={{fontWeight: '900'}}>
|
||||||
|
Move fast and be ultrabold
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
title: 'Font Style',
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text style={{fontStyle: 'normal'}}>
|
||||||
|
Normal text
|
||||||
|
</Text>
|
||||||
|
<Text style={{fontStyle: 'italic'}}>
|
||||||
|
Italic text
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
@ -279,7 +307,7 @@ var styles = StyleSheet.create({
|
||||||
backgroundColor: 'rgba(100, 100, 100, 0.3)'
|
backgroundColor: 'rgba(100, 100, 100, 0.3)'
|
||||||
},
|
},
|
||||||
entity: {
|
entity: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
color: '#527fe4',
|
color: '#527fe4',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -187,7 +187,7 @@ var styles = StyleSheet.create({
|
||||||
backgroundColor: '#f9f9f9',
|
backgroundColor: '#f9f9f9',
|
||||||
},
|
},
|
||||||
textBlock: {
|
textBlock: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
|
||||||
#import "RCTDevelopmentViewController.h"
|
|
||||||
#import "RCTRootView.h"
|
#import "RCTRootView.h"
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
|
@ -42,7 +41,7 @@
|
||||||
rootView.moduleName = @"UIExplorerApp";
|
rootView.moduleName = @"UIExplorerApp";
|
||||||
|
|
||||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||||
UIViewController *rootViewController = [[RCTDevelopmentViewController alloc] init];
|
UIViewController *rootViewController = [[UIViewController alloc] init];
|
||||||
rootViewController.view = rootView;
|
rootViewController.view = rootView;
|
||||||
self.window.rootViewController = rootViewController;
|
self.window.rootViewController = rootViewController;
|
||||||
[self.window makeKeyAndVisible];
|
[self.window makeKeyAndVisible];
|
||||||
|
|
|
@ -76,7 +76,7 @@ var styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
titleText: {
|
titleText: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
descriptionText: {
|
descriptionText: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|
|
@ -204,7 +204,7 @@ var styles = StyleSheet.create({
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
},
|
},
|
||||||
sectionHeaderTitle: {
|
sectionHeaderTitle: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
},
|
},
|
||||||
row: {
|
row: {
|
||||||
|
@ -220,7 +220,7 @@ var styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
rowTitleText: {
|
rowTitleText: {
|
||||||
fontSize: 17,
|
fontSize: 17,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
rowDetailText: {
|
rowDetailText: {
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
|
|
|
@ -42,7 +42,7 @@ var styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: 19,
|
fontSize: 19,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,7 @@ var styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
errorTextTitle: {
|
errorTextTitle: {
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
},
|
},
|
||||||
errorText: {
|
errorText: {
|
||||||
|
|
|
@ -81,7 +81,7 @@ var styles = StyleSheet.create({
|
||||||
padding: 10,
|
padding: 10,
|
||||||
},
|
},
|
||||||
testName: {
|
testName: {
|
||||||
fontWeight: 'bold',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
separator: {
|
separator: {
|
||||||
height: 1,
|
height: 1,
|
||||||
|
|
|
@ -21,28 +21,92 @@ var DEVICE_APPSTATE_EVENT = 'appStateDidChange';
|
||||||
|
|
||||||
var _appStateHandlers = {};
|
var _appStateHandlers = {};
|
||||||
|
|
||||||
class AppStateIOS {
|
/**
|
||||||
|
* `AppStateIOS` can tell you if the app is in the foreground or background,
|
||||||
|
* and notify you when the state changes.
|
||||||
|
*
|
||||||
|
* AppStateIOS is frequently used to determine the intent and proper behavior when
|
||||||
|
* handling push notifications.
|
||||||
|
*
|
||||||
|
* ### iOS 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 `AppStateIOS.currentState`, which
|
||||||
|
* will be kept up-to-date. However, `currentState` will be null at launch
|
||||||
|
* while `AppStateIOS` retrieves it over the bridge.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* getInitialState: function() {
|
||||||
|
* return {
|
||||||
|
* currentAppState: AppStateIOS.currentState,
|
||||||
|
* };
|
||||||
|
* },
|
||||||
|
* componentDidMount: function() {
|
||||||
|
* AppStateIOS.addEventListener('change', this._handleAppStateChange);
|
||||||
|
* },
|
||||||
|
* componentWillUnmount: function() {
|
||||||
|
* AppStateIOS.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.
|
||||||
|
*/
|
||||||
|
|
||||||
static addEventListener(type, handler) {
|
var AppStateIOS = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a handler to AppState changes by listening to the `change` event type
|
||||||
|
* and providing the handler
|
||||||
|
*/
|
||||||
|
addEventListener: function(
|
||||||
|
type: string,
|
||||||
|
handler: Function
|
||||||
|
) {
|
||||||
_appStateHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
_appStateHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
||||||
DEVICE_APPSTATE_EVENT,
|
DEVICE_APPSTATE_EVENT,
|
||||||
(appStateData) => {
|
(appStateData) => {
|
||||||
handler(appStateData.app_state);
|
handler(appStateData.app_state);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
|
||||||
static removeEventListener(type, handler) {
|
/**
|
||||||
|
* Remove a handler by passing the `change` event type and the handler
|
||||||
|
*/
|
||||||
|
removeEventListener: function(
|
||||||
|
type: string,
|
||||||
|
handler: Function
|
||||||
|
) {
|
||||||
if (!_appStateHandlers[handler]) {
|
if (!_appStateHandlers[handler]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_appStateHandlers[handler].remove();
|
_appStateHandlers[handler].remove();
|
||||||
_appStateHandlers[handler] = null;
|
_appStateHandlers[handler] = null;
|
||||||
}
|
},
|
||||||
|
|
||||||
}
|
currentState: (null : ?String),
|
||||||
|
|
||||||
AppStateIOS.currentState = null;
|
};
|
||||||
|
|
||||||
RCTDeviceEventEmitter.addListener(
|
RCTDeviceEventEmitter.addListener(
|
||||||
DEVICE_APPSTATE_EVENT,
|
DEVICE_APPSTATE_EVENT,
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule View
|
* @providesModule View
|
||||||
* @flow
|
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -40,18 +39,8 @@ var stylePropType = StyleSheetPropType(ViewStylePropTypes);
|
||||||
* </View>
|
* </View>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* By default, `View`s have a primary flex direction of 'column', so children
|
|
||||||
* will stack up vertically by default. `View`s also expand to fill the parent
|
|
||||||
* in the direction of the parent's flex direction by default, so in the case of
|
|
||||||
* a default parent (flexDirection: 'column'), the children will fill the width,
|
|
||||||
* but not the height.
|
|
||||||
*
|
|
||||||
* Many library components can be treated like plain `Views` in many cases, for
|
|
||||||
* example passing them children, setting style, etc.
|
|
||||||
*
|
|
||||||
* `View`s are designed to be used with `StyleSheet`s for clarity and
|
* `View`s are designed to be used with `StyleSheet`s for clarity and
|
||||||
* performance, although inline styles are also supported. It is common for
|
* performance, although inline styles are also supported.
|
||||||
* `StyleSheet`s to be combined dynamically. See `StyleSheet.js` for more info.
|
|
||||||
*/
|
*/
|
||||||
var View = React.createClass({
|
var View = React.createClass({
|
||||||
mixins: [NativeMethodsMixin],
|
mixins: [NativeMethodsMixin],
|
||||||
|
@ -67,10 +56,18 @@ var View = React.createClass({
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
/**
|
/**
|
||||||
* When true, indicates that the view is an accessibility element
|
* When true, indicates that the view is an accessibility element. By default,
|
||||||
|
* all the touchable elements are accessible.
|
||||||
*/
|
*/
|
||||||
accessible: PropTypes.bool,
|
accessible: PropTypes.bool,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the text that's read by the screen reader when the user interacts
|
||||||
|
* with the element. By default, the label is constructed by traversing all the
|
||||||
|
* children and accumulating all the Text nodes separated by space.
|
||||||
|
*/
|
||||||
|
accessibilityLabel: PropTypes.string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to locate this view in end-to-end tests.
|
* Used to locate this view in end-to-end tests.
|
||||||
*/
|
*/
|
||||||
|
@ -78,16 +75,16 @@ var View = React.createClass({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For most touch interactions, you'll simply want to wrap your component in
|
* For most touch interactions, you'll simply want to wrap your component in
|
||||||
* `TouchableHighlight.js`. Check out `Touchable.js` and
|
* `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`,
|
||||||
* `ScrollResponder.js` for more discussion.
|
* `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion.
|
||||||
*/
|
*/
|
||||||
|
onMoveShouldSetResponder: PropTypes.func,
|
||||||
onResponderGrant: PropTypes.func,
|
onResponderGrant: PropTypes.func,
|
||||||
onResponderReject: PropTypes.func,
|
|
||||||
onResponderMove: PropTypes.func,
|
onResponderMove: PropTypes.func,
|
||||||
|
onResponderReject: PropTypes.func,
|
||||||
onResponderRelease: PropTypes.func,
|
onResponderRelease: PropTypes.func,
|
||||||
onResponderTerminate: PropTypes.func,
|
onResponderTerminate: PropTypes.func,
|
||||||
onResponderTerminationRequest: PropTypes.func,
|
onResponderTerminationRequest: PropTypes.func,
|
||||||
onMoveShouldSetResponder: PropTypes.func,
|
|
||||||
onStartShouldSetResponder: PropTypes.func,
|
onStartShouldSetResponder: PropTypes.func,
|
||||||
onStartShouldSetResponderCapture: PropTypes.func,
|
onStartShouldSetResponderCapture: PropTypes.func,
|
||||||
|
|
||||||
|
@ -95,12 +92,25 @@ var View = React.createClass({
|
||||||
* In the absence of `auto` property, `none` is much like `CSS`'s `none`
|
* In the absence of `auto` property, `none` is much like `CSS`'s `none`
|
||||||
* value. `box-none` is as if you had applied the `CSS` class:
|
* value. `box-none` is as if you had applied the `CSS` class:
|
||||||
*
|
*
|
||||||
* .cantTouchThis * {
|
* ```
|
||||||
* pointer-events: auto;
|
* .box-none {
|
||||||
* }
|
* pointer-events: none;
|
||||||
* .cantTouchThis {
|
* }
|
||||||
* pointer-events: none;
|
* .box-none * {
|
||||||
* }
|
* pointer-events: all;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* `box-only` is the equivalent of
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* .box-only {
|
||||||
|
* pointer-events: all;
|
||||||
|
* }
|
||||||
|
* .box-only * {
|
||||||
|
* pointer-events: none;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
*
|
*
|
||||||
* But since `pointerEvents` does not affect layout/appearance, and we are
|
* But since `pointerEvents` does not affect layout/appearance, and we are
|
||||||
* already deviating from the spec by adding additional modes, we opt to not
|
* already deviating from the spec by adding additional modes, we opt to not
|
||||||
|
@ -114,11 +124,6 @@ var View = React.createClass({
|
||||||
'box-only',
|
'box-only',
|
||||||
'auto',
|
'auto',
|
||||||
]),
|
]),
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to style and layout the `View`. See `StyleSheet.js` and
|
|
||||||
* `ViewStylePropTypes.js` for more info.
|
|
||||||
*/
|
|
||||||
style: stylePropType,
|
style: stylePropType,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,18 +21,25 @@ type ChangeEventName = $Enum<{
|
||||||
change: string;
|
change: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
type ReachabilityStateIOS = $Enum<{
|
||||||
|
cell: string;
|
||||||
|
none: string;
|
||||||
|
unknown: string;
|
||||||
|
wifi: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetInfo exposes info about online/offline status
|
* NetInfo exposes info about online/offline status
|
||||||
*
|
*
|
||||||
* == iOS Reachability
|
* ### reachabilityIOS
|
||||||
*
|
*
|
||||||
* Asyncronously determine if the device is online and on a cellular network.
|
* Asyncronously determine if the device is online and on a cellular network.
|
||||||
*
|
*
|
||||||
* - "none" - device is offline
|
* - `none` - device is offline
|
||||||
* - "wifi" - device is online and connected via wifi, or is the iOS simulator
|
* - `wifi` - device is online and connected via wifi, or is the iOS simulator
|
||||||
* - "cell" - device is connected via Edge, 3G, WiMax, or LTE
|
* - `cell` - device is connected via Edge, 3G, WiMax, or LTE
|
||||||
* - "unknown" - error case and the network status is unknown
|
* - `unknown` - error case and the network status is unknown
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* NetInfo.reachabilityIOS.fetch().done((reach) => {
|
* NetInfo.reachabilityIOS.fetch().done((reach) => {
|
||||||
|
@ -50,11 +57,37 @@ type ChangeEventName = $Enum<{
|
||||||
* handleFirstReachabilityChange
|
* handleFirstReachabilityChange
|
||||||
* );
|
* );
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
|
* ### isConnected
|
||||||
|
*
|
||||||
|
* Available on all platforms. Asyncronously fetch a boolean to determine
|
||||||
|
* internet connectivity.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* NetInfo.isConnected.fetch().done((isConnected) => {
|
||||||
|
* console.log('First, is ' + (isConnected ? 'online' : 'offline'));
|
||||||
|
* });
|
||||||
|
* function handleFirstConnectivityChange(isConnected) {
|
||||||
|
* console.log('Then, is ' + (isConnected ? 'online' : 'offline'));
|
||||||
|
* NetInfo.isConnected.removeEventListener(
|
||||||
|
* 'change',
|
||||||
|
* handleFirstConnectivityChange
|
||||||
|
* );
|
||||||
|
* }
|
||||||
|
* NetInfo.isConnected.addEventListener(
|
||||||
|
* 'change',
|
||||||
|
* handleFirstConnectivityChange
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var NetInfo = {};
|
var NetInfo = {};
|
||||||
|
|
||||||
if (RCTReachability) {
|
if (RCTReachability) {
|
||||||
|
|
||||||
|
// RCTReachability is exposed, so this is an iOS-like environment and we will
|
||||||
|
// expose reachabilityIOS
|
||||||
|
|
||||||
var _reachabilitySubscriptions = {};
|
var _reachabilitySubscriptions = {};
|
||||||
|
|
||||||
NetInfo.reachabilityIOS = {
|
NetInfo.reachabilityIOS = {
|
||||||
|
@ -84,7 +117,7 @@ if (RCTReachability) {
|
||||||
fetch: function(): Promise {
|
fetch: function(): Promise {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
RCTReachability.getCurrentReachability(
|
RCTReachability.getCurrentReachability(
|
||||||
(resp) => {
|
function(resp) {
|
||||||
resolve(resp.network_reachability);
|
resolve(resp.network_reachability);
|
||||||
},
|
},
|
||||||
reject
|
reject
|
||||||
|
@ -93,53 +126,42 @@ if (RCTReachability) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* == NetInfo.isConnected
|
|
||||||
*
|
|
||||||
* Available on all platforms. Asyncronously fetch a boolean to determine
|
|
||||||
* internet connectivity.
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* NetInfo.isConnected.fetch().done((isConnected) => {
|
|
||||||
* console.log('First, is ' + (isConnected ? 'online' : 'offline'));
|
|
||||||
* });
|
|
||||||
* function handleFirstConnectivityChange(isConnected) {
|
|
||||||
* console.log('Then, is ' + (isConnected ? 'online' : 'offline'));
|
|
||||||
* NetInfo.isConnected.removeEventListener(
|
|
||||||
* 'change',
|
|
||||||
* handleFirstConnectivityChange
|
|
||||||
* );
|
|
||||||
* }
|
|
||||||
* NetInfo.isConnected.addEventListener(
|
|
||||||
* 'change',
|
|
||||||
* handleFirstConnectivityChange
|
|
||||||
* );
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
var _isConnectedSubscriptions = {};
|
var _isConnectedSubscriptions = {};
|
||||||
|
|
||||||
|
var _iosReachabilityIsConnected = function(
|
||||||
|
reachability: ReachabilityStateIOS
|
||||||
|
): bool {
|
||||||
|
return reachability !== 'none' &&
|
||||||
|
reachability !== 'unknown';
|
||||||
|
};
|
||||||
|
|
||||||
NetInfo.isConnected = {
|
NetInfo.isConnected = {
|
||||||
addEventListener: function (
|
addEventListener: function (
|
||||||
eventName: ChangeEventName,
|
eventName: ChangeEventName,
|
||||||
handler: Function
|
handler: Function
|
||||||
): void {
|
): void {
|
||||||
_isConnectedSubscriptions[handler] = (reachability) => {
|
_isConnectedSubscriptions[handler] = (reachability) => {
|
||||||
handler(reachability !== 'none');
|
handler(_iosReachabilityIsConnected(reachability));
|
||||||
};
|
};
|
||||||
NetInfo.reachabilityIOS.addEventListener(eventName, _isConnectedSubscriptions[handler]);
|
NetInfo.reachabilityIOS.addEventListener(
|
||||||
|
eventName,
|
||||||
|
_isConnectedSubscriptions[handler]
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeEventListener: function(
|
removeEventListener: function(
|
||||||
eventName: ChangeEventName,
|
eventName: ChangeEventName,
|
||||||
handler: Function
|
handler: Function
|
||||||
): void {
|
): void {
|
||||||
NetInfo.reachabilityIOS.removeEventListener(eventName, _isConnectedSubscriptions[handler]);
|
NetInfo.reachabilityIOS.removeEventListener(
|
||||||
|
eventName,
|
||||||
|
_isConnectedSubscriptions[handler]
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
fetch: function(): Promise {
|
fetch: function(): Promise {
|
||||||
return NetInfo.reachabilityIOS.fetch().then(
|
return NetInfo.reachabilityIOS.fetch().then(
|
||||||
(reachability) => reachability !== 'none'
|
(reachability) => _iosReachabilityIsConnected(reachability)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule IOSDefaultEventPluginOrder
|
* @providesModule IOSDefaultEventPluginOrder
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule IOSNativeBridgeEventPlugin
|
* @providesModule IOSNativeBridgeEventPlugin
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
@ -51,10 +52,11 @@ var IOSNativeBridgeEventPlugin = {
|
||||||
* @see {EventPluginHub.extractEvents}
|
* @see {EventPluginHub.extractEvents}
|
||||||
*/
|
*/
|
||||||
extractEvents: function(
|
extractEvents: function(
|
||||||
topLevelType,
|
topLevelType: string,
|
||||||
topLevelTarget,
|
topLevelTarget: EventTarget,
|
||||||
topLevelTargetID,
|
topLevelTargetID: string,
|
||||||
nativeEvent) {
|
nativeEvent: Event
|
||||||
|
): ?Object {
|
||||||
var bubbleDispatchConfig = customBubblingEventTypes[topLevelType];
|
var bubbleDispatchConfig = customBubblingEventTypes[topLevelType];
|
||||||
var directDispatchConfig = customDirectEventTypes[topLevelType];
|
var directDispatchConfig = customDirectEventTypes[topLevelType];
|
||||||
var event = SyntheticEvent.getPooled(
|
var event = SyntheticEvent.getPooled(
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule NativeMethodsMixin
|
* @providesModule NativeMethodsMixin
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var NativeModules = require('NativeModules');
|
|
||||||
var NativeModules = require('NativeModules');
|
var NativeModules = require('NativeModules');
|
||||||
var RCTPOPAnimationManager = NativeModules.POPAnimationManager;
|
var RCTPOPAnimationManager = NativeModules.POPAnimationManager;
|
||||||
var RCTUIManager = NativeModules.UIManager;
|
var RCTUIManager = NativeModules.UIManager;
|
||||||
|
@ -20,7 +20,26 @@ var flattenStyle = require('flattenStyle');
|
||||||
var invariant = require('invariant');
|
var invariant = require('invariant');
|
||||||
var mergeFast = require('mergeFast');
|
var mergeFast = require('mergeFast');
|
||||||
|
|
||||||
var animationIDInvariant = function(funcName, anim) {
|
type MeasureOnSuccessCallback = (
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
pageX: number,
|
||||||
|
pageY: number
|
||||||
|
) => void
|
||||||
|
|
||||||
|
type MeasureLayoutOnSuccessCallback = (
|
||||||
|
left: number,
|
||||||
|
top: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
) => void
|
||||||
|
|
||||||
|
var animationIDInvariant = function(
|
||||||
|
funcName: string,
|
||||||
|
anim: number
|
||||||
|
) {
|
||||||
invariant(
|
invariant(
|
||||||
anim,
|
anim,
|
||||||
funcName + ' must be called with a valid animation ID returned from' +
|
funcName + ' must be called with a valid animation ID returned from' +
|
||||||
|
@ -29,21 +48,25 @@ var animationIDInvariant = function(funcName, anim) {
|
||||||
};
|
};
|
||||||
|
|
||||||
var NativeMethodsMixin = {
|
var NativeMethodsMixin = {
|
||||||
addAnimation: function(anim, callback) {
|
addAnimation: function(anim: number, callback?: (finished: bool) => void) {
|
||||||
animationIDInvariant('addAnimation', anim);
|
animationIDInvariant('addAnimation', anim);
|
||||||
RCTPOPAnimationManager.addAnimation(this.getNodeHandle(), anim, callback);
|
RCTPOPAnimationManager.addAnimation(this.getNodeHandle(), anim, callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeAnimation: function(anim) {
|
removeAnimation: function(anim: number) {
|
||||||
animationIDInvariant('removeAnimation', anim);
|
animationIDInvariant('removeAnimation', anim);
|
||||||
RCTPOPAnimationManager.removeAnimation(this.getNodeHandle(), anim);
|
RCTPOPAnimationManager.removeAnimation(this.getNodeHandle(), anim);
|
||||||
},
|
},
|
||||||
|
|
||||||
measure: function(callback) {
|
measure: function(callback: MeasureOnSuccessCallback) {
|
||||||
RCTUIManager.measure(this.getNodeHandle(), callback);
|
RCTUIManager.measure(this.getNodeHandle(), callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
measureLayout: function(relativeToNativeNode, onSuccess, onFail) {
|
measureLayout: function(
|
||||||
|
relativeToNativeNode: number,
|
||||||
|
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||||
|
onFail: () => void /* currently unused */
|
||||||
|
) {
|
||||||
RCTUIManager.measureLayout(
|
RCTUIManager.measureLayout(
|
||||||
this.getNodeHandle(),
|
this.getNodeHandle(),
|
||||||
relativeToNativeNode,
|
relativeToNativeNode,
|
||||||
|
@ -57,7 +80,7 @@ var NativeMethodsMixin = {
|
||||||
* in future diff process, this means that if you do not include them in the
|
* in future diff process, this means that if you do not include them in the
|
||||||
* next render, they will remain active.
|
* next render, they will remain active.
|
||||||
*/
|
*/
|
||||||
setNativeProps: function(nativeProps) {
|
setNativeProps: function(nativeProps: Object) {
|
||||||
// nativeProps contains a style attribute that's going to be flattened
|
// nativeProps contains a style attribute that's going to be flattened
|
||||||
// and all the attributes expanded in place. In order to make this
|
// and all the attributes expanded in place. In order to make this
|
||||||
// process do as few allocations and copies as possible, we return
|
// process do as few allocations and copies as possible, we return
|
||||||
|
@ -111,15 +134,19 @@ function throwOnStylesProp(component, props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
|
// hide this from Flow since we can't define these properties outside of
|
||||||
|
// __DEV__ without actually implementing them (setting them to undefined
|
||||||
|
// isn't allowed by ReactClass)
|
||||||
|
var NativeMethodsMixin_DEV = (NativeMethodsMixin: any);
|
||||||
invariant(
|
invariant(
|
||||||
!NativeMethodsMixin.componentWillMount &&
|
!NativeMethodsMixin_DEV.componentWillMount &&
|
||||||
!NativeMethodsMixin.componentWillReceiveProps,
|
!NativeMethodsMixin_DEV.componentWillReceiveProps,
|
||||||
'Do not override existing functions.'
|
'Do not override existing functions.'
|
||||||
);
|
);
|
||||||
NativeMethodsMixin.componentWillMount = function () {
|
NativeMethodsMixin_DEV.componentWillMount = function () {
|
||||||
throwOnStylesProp(this, this.props);
|
throwOnStylesProp(this, this.props);
|
||||||
};
|
};
|
||||||
NativeMethodsMixin.componentWillReceiveProps = function (newProps) {
|
NativeMethodsMixin_DEV.componentWillReceiveProps = function (newProps) {
|
||||||
throwOnStylesProp(this, newProps);
|
throwOnStylesProp(this, newProps);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule React
|
* @providesModule React
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule ReactIOS
|
* @providesModule ReactIOS
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var ReactChildren = require('ReactChildren');
|
var ReactChildren = require('ReactChildren');
|
||||||
|
@ -51,7 +51,7 @@ var resolveDefaultProps = function(element) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Experimental optimized element creation
|
// Experimental optimized element creation
|
||||||
var augmentElement = function(element) {
|
var augmentElement = function(element: ReactElement) {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
invariant(
|
invariant(
|
||||||
false,
|
false,
|
||||||
|
@ -67,7 +67,7 @@ var augmentElement = function(element) {
|
||||||
return element;
|
return element;
|
||||||
};
|
};
|
||||||
|
|
||||||
var render = function(component, mountInto) {
|
var render = function(component: ReactComponent, mountInto: number) {
|
||||||
ReactIOSMount.renderComponent(component, mountInto);
|
ReactIOSMount.renderComponent(component, mountInto);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule ReactIOSComponentEnvironment
|
* @providesModule ReactIOSComponentEnvironment
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule ReactIOSComponentMixin
|
* @providesModule ReactIOSComponentMixin
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule ReactIOSDOMIDOperations
|
* @providesModule ReactIOSDOMIDOperations
|
||||||
* @typechecks static-only
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule ReactIOSDefaultInjection
|
* @providesModule ReactIOSDefaultInjection
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule createReactIOSNativeComponentClass
|
* @providesModule createReactIOSNativeComponentClass
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
@ -14,11 +15,19 @@
|
||||||
var ReactElement = require('ReactElement');
|
var ReactElement = require('ReactElement');
|
||||||
var ReactIOSNativeComponent = require('ReactIOSNativeComponent');
|
var ReactIOSNativeComponent = require('ReactIOSNativeComponent');
|
||||||
|
|
||||||
|
// See also ReactIOSNativeComponent
|
||||||
|
type ReactIOSNativeComponentViewConfig = {
|
||||||
|
validAttributes: Object;
|
||||||
|
uiViewClassName: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} config iOS View configuration.
|
* @param {string} config iOS View configuration.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
var createReactIOSNativeComponentClass = function(viewConfig) {
|
var createReactIOSNativeComponentClass = function(
|
||||||
|
viewConfig: ReactIOSNativeComponentViewConfig
|
||||||
|
): Function { // returning Function is lossy :/
|
||||||
var Constructor = function(element) {
|
var Constructor = function(element) {
|
||||||
this._currentElement = element;
|
this._currentElement = element;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule diffRawProperties
|
* @providesModule diffRawProperties
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -21,34 +22,41 @@
|
||||||
* previous. These properties are as supplied to component construction.
|
* previous. These properties are as supplied to component construction.
|
||||||
* @return {?object}
|
* @return {?object}
|
||||||
*/
|
*/
|
||||||
function diffRawProperties(updatePayload, prevProps, nextProps, validAttributes) {
|
function diffRawProperties(
|
||||||
|
updatePayload: ?Object,
|
||||||
|
prevProps: ?Object,
|
||||||
|
nextProps: ?Object,
|
||||||
|
validAttributes: Object
|
||||||
|
): ?Object {
|
||||||
var validAttributeConfig;
|
var validAttributeConfig;
|
||||||
var nextProp;
|
var nextProp;
|
||||||
var prevProp;
|
var prevProp;
|
||||||
var isScalar;
|
var isScalar;
|
||||||
var shouldUpdate;
|
var shouldUpdate;
|
||||||
|
|
||||||
for (var propKey in nextProps) {
|
if (nextProps) {
|
||||||
validAttributeConfig = validAttributes[propKey];
|
for (var propKey in nextProps) {
|
||||||
if (!validAttributeConfig) {
|
validAttributeConfig = validAttributes[propKey];
|
||||||
continue; // not a valid native prop
|
if (!validAttributeConfig) {
|
||||||
}
|
continue; // not a valid native prop
|
||||||
prevProp = prevProps && prevProps[propKey];
|
}
|
||||||
nextProp = nextProps[propKey];
|
prevProp = prevProps && prevProps[propKey];
|
||||||
if (prevProp !== nextProp) {
|
nextProp = nextProps[propKey];
|
||||||
// If you want a property's diff to be detected, you must configure it
|
if (prevProp !== nextProp) {
|
||||||
// to be so - *or* it must be a scalar property. For now, we'll allow
|
// If you want a property's diff to be detected, you must configure it
|
||||||
// creation with any attribute that is not scalar, but we should
|
// to be so - *or* it must be a scalar property. For now, we'll allow
|
||||||
// eventually even reject those unless they are properly configured.
|
// creation with any attribute that is not scalar, but we should
|
||||||
isScalar = typeof nextProp !== 'object' || nextProp === null;
|
// eventually even reject those unless they are properly configured.
|
||||||
shouldUpdate = isScalar ||
|
isScalar = typeof nextProp !== 'object' || nextProp === null;
|
||||||
!prevProp ||
|
shouldUpdate = isScalar ||
|
||||||
validAttributeConfig.diff &&
|
!prevProp ||
|
||||||
validAttributeConfig.diff(prevProp, nextProp);
|
validAttributeConfig.diff &&
|
||||||
|
validAttributeConfig.diff(prevProp, nextProp);
|
||||||
|
|
||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
updatePayload = updatePayload || {};
|
updatePayload = updatePayload || {};
|
||||||
updatePayload[propKey] = nextProp;
|
updatePayload[propKey] = nextProp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,31 +64,33 @@ function diffRawProperties(updatePayload, prevProps, nextProps, validAttributes)
|
||||||
// Also iterate through all the previous props to catch any that have been
|
// Also iterate through all the previous props to catch any that have been
|
||||||
// removed and make sure native gets the signal so it can reset them to the
|
// removed and make sure native gets the signal so it can reset them to the
|
||||||
// default.
|
// default.
|
||||||
for (var propKey in prevProps) {
|
if (prevProps) {
|
||||||
validAttributeConfig = validAttributes[propKey];
|
for (var propKey in prevProps) {
|
||||||
if (!validAttributeConfig) {
|
validAttributeConfig = validAttributes[propKey];
|
||||||
continue; // not a valid native prop
|
if (!validAttributeConfig) {
|
||||||
}
|
continue; // not a valid native prop
|
||||||
if (updatePayload && updatePayload[propKey] !== undefined) {
|
|
||||||
continue; // Prop already specified
|
|
||||||
}
|
|
||||||
prevProp = prevProps[propKey];
|
|
||||||
nextProp = nextProps && nextProps[propKey];
|
|
||||||
if (prevProp !== nextProp) {
|
|
||||||
if (nextProp === undefined) {
|
|
||||||
nextProp = null; // null is a sentinel we explicitly send to native
|
|
||||||
}
|
}
|
||||||
// If you want a property's diff to be detected, you must configure it
|
if (updatePayload && updatePayload[propKey] !== undefined) {
|
||||||
// to be so - *or* it must be a scalar property. For now, we'll allow
|
continue; // Prop already specified
|
||||||
// creation with any attribute that is not scalar, but we should
|
}
|
||||||
// eventually even reject those unless they are properly configured.
|
prevProp = prevProps[propKey];
|
||||||
isScalar = typeof nextProp !== 'object' || nextProp === null;
|
nextProp = nextProps && nextProps[propKey];
|
||||||
shouldUpdate = isScalar && prevProp !== nextProp ||
|
if (prevProp !== nextProp) {
|
||||||
validAttributeConfig.diff &&
|
if (nextProp === undefined) {
|
||||||
validAttributeConfig.diff(prevProp, nextProp);
|
nextProp = null; // null is a sentinel we explicitly send to native
|
||||||
if (shouldUpdate) {
|
}
|
||||||
updatePayload = updatePayload || {};
|
// If you want a property's diff to be detected, you must configure it
|
||||||
updatePayload[propKey] = nextProp;
|
// to be so - *or* it must be a scalar property. For now, we'll allow
|
||||||
|
// creation with any attribute that is not scalar, but we should
|
||||||
|
// eventually even reject those unless they are properly configured.
|
||||||
|
isScalar = typeof nextProp !== 'object' || nextProp === null;
|
||||||
|
shouldUpdate = isScalar && prevProp !== nextProp ||
|
||||||
|
validAttributeConfig.diff &&
|
||||||
|
validAttributeConfig.diff(prevProp, nextProp);
|
||||||
|
if (shouldUpdate) {
|
||||||
|
updatePayload = updatePayload || {};
|
||||||
|
updatePayload[propKey] = nextProp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ extern NSString *const RCTReactTagAttributeName;
|
||||||
@property (nonatomic, copy) NSString *fontFamily;
|
@property (nonatomic, copy) NSString *fontFamily;
|
||||||
@property (nonatomic, assign) CGFloat fontSize;
|
@property (nonatomic, assign) CGFloat fontSize;
|
||||||
@property (nonatomic, copy) NSString *fontWeight;
|
@property (nonatomic, copy) NSString *fontWeight;
|
||||||
|
@property (nonatomic, copy) NSString *fontStyle;
|
||||||
@property (nonatomic, assign) BOOL isHighlighted;
|
@property (nonatomic, assign) BOOL isHighlighted;
|
||||||
@property (nonatomic, assign) CGFloat lineHeight;
|
@property (nonatomic, assign) CGFloat lineHeight;
|
||||||
@property (nonatomic, assign) NSInteger maxNumberOfLines;
|
@property (nonatomic, assign) NSInteger maxNumberOfLines;
|
||||||
|
|
|
@ -50,12 +50,14 @@ static css_dim_t RCTMeasure(void *context, float width)
|
||||||
{
|
{
|
||||||
return [self _attributedStringWithFontFamily:nil
|
return [self _attributedStringWithFontFamily:nil
|
||||||
fontSize:0
|
fontSize:0
|
||||||
fontWeight:nil];
|
fontWeight:nil
|
||||||
|
fontStyle:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSAttributedString *)_attributedStringWithFontFamily:(NSString *)fontFamily
|
- (NSAttributedString *)_attributedStringWithFontFamily:(NSString *)fontFamily
|
||||||
fontSize:(CGFloat)fontSize
|
fontSize:(CGFloat)fontSize
|
||||||
fontWeight:(NSString *)fontWeight
|
fontWeight:(NSString *)fontWeight
|
||||||
|
fontStyle:(NSString *)fontStyle
|
||||||
{
|
{
|
||||||
if (![self isTextDirty] && _cachedAttributedString) {
|
if (![self isTextDirty] && _cachedAttributedString) {
|
||||||
return _cachedAttributedString;
|
return _cachedAttributedString;
|
||||||
|
@ -67,6 +69,9 @@ static css_dim_t RCTMeasure(void *context, float width)
|
||||||
if (_fontWeight) {
|
if (_fontWeight) {
|
||||||
fontWeight = _fontWeight;
|
fontWeight = _fontWeight;
|
||||||
}
|
}
|
||||||
|
if (_fontStyle) {
|
||||||
|
fontStyle = _fontStyle;
|
||||||
|
}
|
||||||
if (_fontFamily) {
|
if (_fontFamily) {
|
||||||
fontFamily = _fontFamily;
|
fontFamily = _fontFamily;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +80,7 @@ static css_dim_t RCTMeasure(void *context, float width)
|
||||||
for (RCTShadowView *child in [self reactSubviews]) {
|
for (RCTShadowView *child in [self reactSubviews]) {
|
||||||
if ([child isKindOfClass:[RCTShadowText class]]) {
|
if ([child isKindOfClass:[RCTShadowText class]]) {
|
||||||
RCTShadowText *shadowText = (RCTShadowText *)child;
|
RCTShadowText *shadowText = (RCTShadowText *)child;
|
||||||
[attributedString appendAttributedString:[shadowText _attributedStringWithFontFamily:fontFamily fontSize:fontSize fontWeight:fontWeight]];
|
[attributedString appendAttributedString:[shadowText _attributedStringWithFontFamily:fontFamily fontSize:fontSize fontWeight:fontWeight fontStyle:fontStyle]];
|
||||||
} else if ([child isKindOfClass:[RCTShadowRawText class]]) {
|
} else if ([child isKindOfClass:[RCTShadowRawText class]]) {
|
||||||
RCTShadowRawText *shadowRawText = (RCTShadowRawText *)child;
|
RCTShadowRawText *shadowRawText = (RCTShadowRawText *)child;
|
||||||
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[shadowRawText text] ?: @""]];
|
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[shadowRawText text] ?: @""]];
|
||||||
|
@ -96,7 +101,7 @@ static css_dim_t RCTMeasure(void *context, float width)
|
||||||
[self _addAttribute:NSBackgroundColorAttributeName withValue:self.textBackgroundColor toAttributedString:attributedString];
|
[self _addAttribute:NSBackgroundColorAttributeName withValue:self.textBackgroundColor toAttributedString:attributedString];
|
||||||
}
|
}
|
||||||
|
|
||||||
_font = [RCTConvert UIFont:nil withFamily:fontFamily size:@(fontSize) weight:fontWeight];
|
_font = [RCTConvert UIFont:nil withFamily:fontFamily size:@(fontSize) weight:fontWeight style:fontStyle];
|
||||||
[self _addAttribute:NSFontAttributeName withValue:_font toAttributedString:attributedString];
|
[self _addAttribute:NSFontAttributeName withValue:_font toAttributedString:attributedString];
|
||||||
[self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString];
|
[self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString];
|
||||||
[self _setParagraphStyleOnAttributedString:attributedString];
|
[self _setParagraphStyleOnAttributedString:attributedString];
|
||||||
|
@ -110,7 +115,7 @@ static css_dim_t RCTMeasure(void *context, float width)
|
||||||
|
|
||||||
- (UIFont *)font
|
- (UIFont *)font
|
||||||
{
|
{
|
||||||
return _font ?: [RCTConvert UIFont:nil withFamily:_fontFamily size:@(_fontSize) weight:_fontWeight];
|
return _font ?: [RCTConvert UIFont:nil withFamily:_fontFamily size:@(_fontSize) weight:_fontWeight style:_fontStyle];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_addAttribute:(NSString *)attribute withValue:(id)attributeValue toAttributedString:(NSMutableAttributedString *)attributedString
|
- (void)_addAttribute:(NSString *)attribute withValue:(id)attributeValue toAttributedString:(NSMutableAttributedString *)attributedString
|
||||||
|
|
|
@ -12,3 +12,7 @@
|
||||||
// see also react-native.js
|
// see also react-native.js
|
||||||
|
|
||||||
declare var __DEV__: boolean;
|
declare var __DEV__: boolean;
|
||||||
|
|
||||||
|
declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: any; /*?{
|
||||||
|
inject: ?((stuff: Object) => void)
|
||||||
|
};*/
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#import "Layout.h"
|
#import "Layout.h"
|
||||||
#import "RCTAnimationType.h"
|
#import "RCTAnimationType.h"
|
||||||
|
#import "RCTLog.h"
|
||||||
#import "RCTPointerEvents.h"
|
#import "RCTPointerEvents.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,8 +70,13 @@
|
||||||
|
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withSize:(id)json;
|
+ (UIFont *)UIFont:(UIFont *)font withSize:(id)json;
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withWeight:(id)json;
|
+ (UIFont *)UIFont:(UIFont *)font withWeight:(id)json;
|
||||||
|
+ (UIFont *)UIFont:(UIFont *)font withStyle:(id)json;
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)json;
|
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)json;
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)json size:(id)json weight:(id)json;
|
+ (UIFont *)UIFont:(UIFont *)font
|
||||||
|
withFamily:(id)family
|
||||||
|
size:(id)size
|
||||||
|
weight:(id)weight
|
||||||
|
style:(id)style;
|
||||||
|
|
||||||
+ (NSArray *)NSStringArray:(id)json;
|
+ (NSArray *)NSStringArray:(id)json;
|
||||||
+ (NSArray *)NSURLArray:(id)json;
|
+ (NSArray *)NSURLArray:(id)json;
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
#import <objc/message.h>
|
#import <objc/message.h>
|
||||||
|
|
||||||
#import "RCTLog.h"
|
|
||||||
|
|
||||||
@implementation RCTConvert
|
@implementation RCTConvert
|
||||||
|
|
||||||
RCT_CONVERTER(BOOL, BOOL, boolValue)
|
RCT_CONVERTER(BOOL, BOOL, boolValue)
|
||||||
|
@ -135,7 +133,9 @@ RCT_CGSTRUCT_CONVERTER(CATransform3D, (@[
|
||||||
@"m41", @"m42", @"m43", @"m44"
|
@"m41", @"m42", @"m43", @"m44"
|
||||||
]), nil)
|
]), nil)
|
||||||
|
|
||||||
RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty"]), nil)
|
RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[
|
||||||
|
@"a", @"b", @"c", @"d", @"tx", @"ty"
|
||||||
|
]), nil)
|
||||||
|
|
||||||
+ (UIColor *)UIColor:(id)json
|
+ (UIColor *)UIColor:(id)json
|
||||||
{
|
{
|
||||||
|
@ -364,7 +364,8 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty
|
||||||
|
|
||||||
} else if (json && ![json isKindOfClass:[NSNull class]]) {
|
} else if (json && ![json isKindOfClass:[NSNull class]]) {
|
||||||
|
|
||||||
RCTLogError(@"Expected NSArray, NSDictionary or NSString for UIColor, received %@: %@", [json class], json);
|
RCTLogError(@"Expected NSArray, NSDictionary or NSString for UIColor, \
|
||||||
|
received %@: %@", [json class], json);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default color
|
// Default color
|
||||||
|
@ -418,100 +419,163 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty
|
||||||
return [self UIImage:json].CGImage;
|
return [self UIImage:json].CGImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __IPHONE_8_2
|
||||||
|
|
||||||
|
// These constants are defined in iPhone SDK 8.2
|
||||||
|
// They'll work fine in earlier iOS versions, but the app cannot be built with
|
||||||
|
// an SDK version < 8.2 unless we redefine them here. This will be removed
|
||||||
|
// in a future version of ReactKit, once 8.2 is more widely adopted.
|
||||||
|
|
||||||
|
static const CGFloat UIFontWeightUltraLight = -0.8;
|
||||||
|
static const CGFloat UIFontWeightThin = -0.6;
|
||||||
|
static const CGFloat UIFontWeightLight = -0.4;
|
||||||
|
static const CGFloat UIFontWeightRegular = 0;
|
||||||
|
static const CGFloat UIFontWeightMedium = 0.23;
|
||||||
|
static const CGFloat UIFontWeightSemibold = 0.3;
|
||||||
|
static const CGFloat UIFontWeightBold = 0.4;
|
||||||
|
static const CGFloat UIFontWeightHeavy = 0.56;
|
||||||
|
static const CGFloat UIFontWeightBlack = 0.62;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef CGFloat RCTFontWeight;
|
||||||
|
RCT_ENUM_CONVERTER(RCTFontWeight, (@{
|
||||||
|
@"normal": @(UIFontWeightRegular),
|
||||||
|
@"bold": @(UIFontWeightBold),
|
||||||
|
@"100": @(UIFontWeightUltraLight),
|
||||||
|
@"200": @(UIFontWeightThin),
|
||||||
|
@"300": @(UIFontWeightLight),
|
||||||
|
@"400": @(UIFontWeightRegular),
|
||||||
|
@"500": @(UIFontWeightMedium),
|
||||||
|
@"600": @(UIFontWeightSemibold),
|
||||||
|
@"700": @(UIFontWeightBold),
|
||||||
|
@"800": @(UIFontWeightHeavy),
|
||||||
|
@"900": @(UIFontWeightBlack),
|
||||||
|
}), UIFontWeightRegular, doubleValue)
|
||||||
|
|
||||||
|
typedef BOOL RCTFontStyle;
|
||||||
|
RCT_ENUM_CONVERTER(RCTFontStyle, (@{
|
||||||
|
@"normal": @NO,
|
||||||
|
@"italic": @YES,
|
||||||
|
@"oblique": @YES,
|
||||||
|
}), NO, boolValue)
|
||||||
|
|
||||||
|
static RCTFontWeight RCTWeightOfFont(UIFont *font)
|
||||||
|
{
|
||||||
|
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||||
|
return [traits[UIFontWeightTrait] doubleValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL RCTFontIsItalic(UIFont *font)
|
||||||
|
{
|
||||||
|
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||||
|
UIFontDescriptorSymbolicTraits symbolicTraits = [traits[UIFontSymbolicTrait] unsignedIntValue];
|
||||||
|
return (symbolicTraits & UIFontDescriptorTraitItalic) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL RCTFontIsCondensed(UIFont *font)
|
||||||
|
{
|
||||||
|
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||||
|
UIFontDescriptorSymbolicTraits symbolicTraits = [traits[UIFontSymbolicTrait] unsignedIntValue];
|
||||||
|
return (symbolicTraits & UIFontDescriptorTraitCondensed) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withSize:(id)json
|
+ (UIFont *)UIFont:(UIFont *)font withSize:(id)json
|
||||||
{
|
{
|
||||||
return [self UIFont:font withFamily:nil size:json weight:nil];
|
return [self UIFont:font withFamily:nil size:json weight:nil style:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withWeight:(id)json
|
+ (UIFont *)UIFont:(UIFont *)font withWeight:(id)json
|
||||||
{
|
{
|
||||||
return [self UIFont:font withFamily:nil size:nil weight:json];
|
return [self UIFont:font withFamily:nil size:nil weight:json style:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (UIFont *)UIFont:(UIFont *)font withStyle:(id)json
|
||||||
|
{
|
||||||
|
return [self UIFont:font withFamily:nil size:nil weight:nil style:json];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)json
|
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)json
|
||||||
{
|
{
|
||||||
return [self UIFont:font withFamily:json size:nil weight:nil];
|
return [self UIFont:font withFamily:json size:nil weight:nil style:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)family size:(id)size weight:(id)weight
|
+ (UIFont *)UIFont:(UIFont *)font
|
||||||
|
withFamily:(id)family
|
||||||
|
size:(id)size
|
||||||
|
weight:(id)weight
|
||||||
|
style:(id)style
|
||||||
{
|
{
|
||||||
CGFloat const RCTDefaultFontSize = 14;
|
// Defaults
|
||||||
NSString *const RCTDefaultFontName = @"HelveticaNeue";
|
NSString *const RCTDefaultFontFamily = @"Helvetica Neue";
|
||||||
NSString *const RCTDefaultFontWeight = @"normal";
|
const RCTFontWeight RCTDefaultFontWeight = UIFontWeightRegular;
|
||||||
NSString *const RCTBoldFontWeight = @"bold";
|
const CGFloat RCTDefaultFontSize = 14;
|
||||||
|
|
||||||
// Create descriptor
|
// Get existing properties
|
||||||
UIFontDescriptor *fontDescriptor = font.fontDescriptor ?: [UIFontDescriptor fontDescriptorWithName:RCTDefaultFontName size:RCTDefaultFontSize];
|
BOOL isItalic = NO;
|
||||||
|
BOOL isCondensed = NO;
|
||||||
// Get font size
|
RCTFontWeight fontWeight = RCTDefaultFontWeight;
|
||||||
CGFloat fontSize = [self CGFloat:size];
|
if (font) {
|
||||||
if (fontSize && !isnan(fontSize)) {
|
family = font.familyName;
|
||||||
fontDescriptor = [fontDescriptor fontDescriptorWithSize:fontSize];
|
fontWeight = RCTWeightOfFont(font);
|
||||||
}
|
isItalic = RCTFontIsItalic(font);
|
||||||
|
isCondensed = RCTFontIsCondensed(font);
|
||||||
// Get font family
|
|
||||||
NSString *familyName = [self NSString:family];
|
|
||||||
if (familyName) {
|
|
||||||
if ([UIFont fontNamesForFamilyName:familyName].count == 0) {
|
|
||||||
font = [UIFont fontWithName:familyName size:fontDescriptor.pointSize];
|
|
||||||
if (font) {
|
|
||||||
// It's actually a font name, not a font family name,
|
|
||||||
// but we'll do what was meant, not what was said.
|
|
||||||
familyName = font.familyName;
|
|
||||||
fontDescriptor = font.fontDescriptor;
|
|
||||||
} else {
|
|
||||||
// Not a valid font or family
|
|
||||||
RCTLogError(@"Unrecognized font family '%@'", familyName);
|
|
||||||
familyName = [UIFont fontWithDescriptor:fontDescriptor size:0].familyName;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Set font family
|
|
||||||
fontDescriptor = [fontDescriptor fontDescriptorWithFamily:familyName];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
familyName = [UIFont fontWithDescriptor:fontDescriptor size:0].familyName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get font weight
|
// Get font weight
|
||||||
NSString *fontWeight = [self NSString:weight];
|
if (weight) {
|
||||||
if (fontWeight) {
|
fontWeight = [self RCTFontWeight:weight];
|
||||||
|
}
|
||||||
|
|
||||||
static NSSet *values;
|
// Get font style
|
||||||
static dispatch_once_t onceToken;
|
if (style) {
|
||||||
dispatch_once(&onceToken, ^{
|
isItalic = [self RCTFontStyle:style];
|
||||||
values = [NSSet setWithObjects:RCTDefaultFontWeight, RCTBoldFontWeight, nil];
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (fontWeight && ![values containsObject:fontWeight]) {
|
// Get font size
|
||||||
RCTLogError(@"Unrecognized font weight '%@', must be one of %@", fontWeight, values);
|
CGFloat fontSize = [self CGFloat:size] ?: RCTDefaultFontSize;
|
||||||
fontWeight = RCTDefaultFontWeight;
|
|
||||||
|
// Get font family
|
||||||
|
NSString *familyName = [self NSString:family] ?: RCTDefaultFontFamily;
|
||||||
|
if ([UIFont fontNamesForFamilyName:familyName].count == 0) {
|
||||||
|
font = [UIFont fontWithName:familyName size:fontSize];
|
||||||
|
if (font) {
|
||||||
|
// It's actually a font name, not a font family name,
|
||||||
|
// but we'll do what was meant, not what was said.
|
||||||
|
familyName = font.familyName;
|
||||||
|
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||||
|
fontWeight = [traits[UIFontWeightTrait] doubleValue];
|
||||||
|
} else {
|
||||||
|
// Not a valid font or family
|
||||||
|
RCTLogError(@"Unrecognized font family '%@'", familyName);
|
||||||
|
familyName = RCTDefaultFontFamily;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this is hacky. we are appending the string -Medium because most fonts we currently use
|
// Get closest match
|
||||||
// just need to have -Medium appended to get the bold we want. we're going to revamp this
|
UIFont *bestMatch = font;
|
||||||
// to make it easier to know which options are available in JS. t4996115
|
CGFloat closestWeight = font ? RCTWeightOfFont(font) : INFINITY;
|
||||||
if ([fontWeight isEqualToString:RCTBoldFontWeight]) {
|
for (NSString *name in [UIFont fontNamesForFamilyName:familyName]) {
|
||||||
font = nil;
|
UIFont *match = [UIFont fontWithName:name size:fontSize];
|
||||||
for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) {
|
if (isItalic == RCTFontIsItalic(match) &&
|
||||||
if ([fontName hasSuffix:@"-Medium"]) {
|
isCondensed == RCTFontIsCondensed(match)) {
|
||||||
font = [UIFont fontWithName:fontName size:fontDescriptor.pointSize];
|
CGFloat testWeight = RCTWeightOfFont(match);
|
||||||
break;
|
if (ABS(testWeight - fontWeight) < ABS(closestWeight - fontWeight)) {
|
||||||
}
|
bestMatch = match;
|
||||||
if ([fontName hasSuffix:@"-Bold"]) {
|
closestWeight = testWeight;
|
||||||
font = [UIFont fontWithName:fontName size:fontDescriptor.pointSize];
|
|
||||||
// But keep searching in case there's a medium option
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (font) {
|
|
||||||
fontDescriptor = font.fontDescriptor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: font style
|
// Safety net
|
||||||
|
if (!bestMatch) {
|
||||||
|
RCTLogError(@"Could not find font with family: '%@', size: %@, \
|
||||||
|
weight: %@, style: %@", family, size, weight, style);
|
||||||
|
bestMatch = [UIFont fontWithName:[[UIFont fontNamesForFamilyName:familyName] firstObject]
|
||||||
|
size:fontSize];
|
||||||
|
}
|
||||||
|
|
||||||
// Create font
|
return bestMatch;
|
||||||
return [UIFont fontWithDescriptor:fontDescriptor size:0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_ARRAY_CONVERTER(NSString)
|
RCT_ARRAY_CONVERTER(NSString)
|
||||||
|
|
|
@ -9,6 +9,11 @@
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@interface RCTDevelopmentViewController : UIViewController
|
@class RCTRootView;
|
||||||
|
|
||||||
|
@interface RCTDevMenu : NSObject
|
||||||
|
|
||||||
|
- (instancetype)initWithRootView:(RCTRootView *)rootView;
|
||||||
|
- (void)show;
|
||||||
|
|
||||||
@end
|
@end
|
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "RCTDevMenu.h"
|
||||||
|
|
||||||
|
#import "RCTRedBox.h"
|
||||||
|
#import "RCTRootView.h"
|
||||||
|
|
||||||
|
@interface RCTDevMenu () <UIActionSheetDelegate> {
|
||||||
|
BOOL _liveReload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, weak) RCTRootView *view;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation RCTDevMenu
|
||||||
|
|
||||||
|
- (instancetype)initWithRootView:(RCTRootView *)rootView
|
||||||
|
{
|
||||||
|
if (self = [super init]) {
|
||||||
|
self.view = rootView;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)show
|
||||||
|
{
|
||||||
|
NSString *debugTitle = self.view.executorClass == nil ? @"Enable Debugging" : @"Disable Debugging";
|
||||||
|
NSString *liveReloadTitle = _liveReload ? @"Disable Live Reload" : @"Enable Live Reload";
|
||||||
|
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"React Native: Development"
|
||||||
|
delegate:self
|
||||||
|
cancelButtonTitle:@"Cancel"
|
||||||
|
destructiveButtonTitle:nil
|
||||||
|
otherButtonTitles:@"Reload", debugTitle, liveReloadTitle, nil];
|
||||||
|
actionSheet.actionSheetStyle = UIBarStyleBlack;
|
||||||
|
[actionSheet showInView:self.view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||||
|
{
|
||||||
|
if (buttonIndex == 0) {
|
||||||
|
[self.view reload];
|
||||||
|
} else if (buttonIndex == 1) {
|
||||||
|
self.view.executorClass = self.view.executorClass == nil ? NSClassFromString(@"RCTWebSocketExecutor") : nil;
|
||||||
|
[self.view reload];
|
||||||
|
} else if (buttonIndex == 2) {
|
||||||
|
_liveReload = !_liveReload;
|
||||||
|
[self _pollAndReload];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_pollAndReload
|
||||||
|
{
|
||||||
|
if (_liveReload) {
|
||||||
|
NSURL *url = [self.view scriptURL];
|
||||||
|
NSURL *longPollURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:url];
|
||||||
|
[self performSelectorInBackground:@selector(_checkForUpdates:) withObject:longPollURL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_checkForUpdates:(NSURL *)URL
|
||||||
|
{
|
||||||
|
NSMutableURLRequest *longPollRequest = [NSMutableURLRequest requestWithURL:URL];
|
||||||
|
longPollRequest.timeoutInterval = 30;
|
||||||
|
NSHTTPURLResponse *response;
|
||||||
|
[NSURLConnection sendSynchronousRequest:longPollRequest returningResponse:&response error:nil];
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (_liveReload && response.statusCode == 205) {
|
||||||
|
[[RCTRedBox sharedInstance] dismiss];
|
||||||
|
[self.view reload];
|
||||||
|
}
|
||||||
|
[self _pollAndReload];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -1,89 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "RCTDevelopmentViewController.h"
|
|
||||||
|
|
||||||
#import "RCTRedBox.h"
|
|
||||||
#import "RCTRootView.h"
|
|
||||||
|
|
||||||
@interface RCTDevelopmentViewController () <UIActionSheetDelegate> {
|
|
||||||
BOOL _liveReload;
|
|
||||||
}
|
|
||||||
|
|
||||||
@property (nonatomic, readonly) RCTRootView *RCTView;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation RCTDevelopmentViewController
|
|
||||||
|
|
||||||
- (BOOL)canBecomeFirstResponder
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (RCTRootView *)RCTView
|
|
||||||
{
|
|
||||||
return (RCTRootView *)self.view;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
|
|
||||||
{
|
|
||||||
if (motion == UIEventSubtypeMotionShake)
|
|
||||||
{
|
|
||||||
NSString *debugTitle = self.RCTView.executorClass == nil ? @"Enable Debugging" : @"Disable Debugging";
|
|
||||||
NSString *liveReloadTitle = _liveReload ? @"Disable Live Reload" : @"Enable Live Reload";
|
|
||||||
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"React Native: Development"
|
|
||||||
delegate:self
|
|
||||||
cancelButtonTitle:@"Cancel"
|
|
||||||
destructiveButtonTitle:nil
|
|
||||||
otherButtonTitles:@"Reload", debugTitle, liveReloadTitle, nil];
|
|
||||||
actionSheet.actionSheetStyle = UIBarStyleBlack;
|
|
||||||
[actionSheet showInView:self.view];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
|
||||||
{
|
|
||||||
if (buttonIndex == 0) {
|
|
||||||
[self.RCTView reload];
|
|
||||||
} else if (buttonIndex == 1) {
|
|
||||||
self.RCTView.executorClass = self.RCTView.executorClass == nil ? NSClassFromString(@"RCTWebSocketExecutor") : nil;
|
|
||||||
[self.RCTView reload];
|
|
||||||
} else if (buttonIndex == 2) {
|
|
||||||
_liveReload = !_liveReload;
|
|
||||||
[self _pollAndReload];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_pollAndReload
|
|
||||||
{
|
|
||||||
if (_liveReload) {
|
|
||||||
NSURL *url = [self.RCTView scriptURL];
|
|
||||||
NSURL *longPollURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:url];
|
|
||||||
[self performSelectorInBackground:@selector(_checkForUpdates:) withObject:longPollURL];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_checkForUpdates:(NSURL *)URL
|
|
||||||
{
|
|
||||||
NSMutableURLRequest *longPollRequest = [NSMutableURLRequest requestWithURL:URL];
|
|
||||||
longPollRequest.timeoutInterval = 30;
|
|
||||||
NSHTTPURLResponse *response;
|
|
||||||
[NSURLConnection sendSynchronousRequest:longPollRequest returningResponse:&response error:nil];
|
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
if (_liveReload && response.statusCode == 205) {
|
|
||||||
[[RCTRedBox sharedInstance] dismiss];
|
|
||||||
[self.RCTView reload];
|
|
||||||
}
|
|
||||||
[self _pollAndReload];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -48,6 +48,12 @@
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, strong) Class executorClass;
|
@property (nonatomic, strong) Class executorClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If YES will watch for shake gestures and show development menu
|
||||||
|
* with options like "Reload", "Enable Debugging", etc.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) BOOL enableDevMenu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload this root view, or all root views, respectively.
|
* Reload this root view, or all root views, respectively.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
#import "RCTContextExecutor.h"
|
#import "RCTContextExecutor.h"
|
||||||
|
#import "RCTDevMenu.h"
|
||||||
#import "RCTEventDispatcher.h"
|
#import "RCTEventDispatcher.h"
|
||||||
#import "RCTKeyCommands.h"
|
#import "RCTKeyCommands.h"
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
|
@ -26,6 +27,7 @@ NSString *const RCTReloadNotification = @"RCTReloadNotification";
|
||||||
|
|
||||||
@implementation RCTRootView
|
@implementation RCTRootView
|
||||||
{
|
{
|
||||||
|
RCTDevMenu *_devMenu;
|
||||||
RCTBridge *_bridge;
|
RCTBridge *_bridge;
|
||||||
RCTTouchHandler *_touchHandler;
|
RCTTouchHandler *_touchHandler;
|
||||||
id<RCTJavaScriptExecutor> _executor;
|
id<RCTJavaScriptExecutor> _executor;
|
||||||
|
@ -84,6 +86,9 @@ static Class _globalExecutorClass;
|
||||||
// Numbering of these tags goes from 1, 11, 21, 31, etc
|
// Numbering of these tags goes from 1, 11, 21, 31, etc
|
||||||
static NSInteger rootViewTag = 1;
|
static NSInteger rootViewTag = 1;
|
||||||
self.reactTag = @(rootViewTag);
|
self.reactTag = @(rootViewTag);
|
||||||
|
#ifdef DEBUG
|
||||||
|
self.enableDevMenu = YES;
|
||||||
|
#endif
|
||||||
rootViewTag += 10;
|
rootViewTag += 10;
|
||||||
|
|
||||||
// Add reload observer
|
// Add reload observer
|
||||||
|
@ -93,6 +98,21 @@ static Class _globalExecutorClass;
|
||||||
object:nil];
|
object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
|
||||||
|
{
|
||||||
|
if (motion == UIEventSubtypeMotionShake && self.enableDevMenu) {
|
||||||
|
if (!_devMenu) {
|
||||||
|
_devMenu = [[RCTDevMenu alloc] initWithRootView:self];
|
||||||
|
}
|
||||||
|
[_devMenu show];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+ (NSArray *)JSMethods
|
+ (NSArray *)JSMethods
|
||||||
{
|
{
|
||||||
return @[
|
return @[
|
||||||
|
|
|
@ -50,11 +50,11 @@ NSString *RCTMD5Hash(NSString *string)
|
||||||
CC_MD5(str, (CC_LONG)strlen(str), result);
|
CC_MD5(str, (CC_LONG)strlen(str), result);
|
||||||
|
|
||||||
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
result[0], result[1], result[2], result[3],
|
result[0], result[1], result[2], result[3],
|
||||||
result[4], result[5], result[6], result[7],
|
result[4], result[5], result[6], result[7],
|
||||||
result[8], result[9], result[10], result[11],
|
result[8], result[9], result[10], result[11],
|
||||||
result[12], result[13], result[14], result[15]
|
result[12], result[13], result[14], result[15]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
CGFloat RCTScreenScale()
|
CGFloat RCTScreenScale()
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */ = {isa = PBXBuildFile; fileRef = 000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */; };
|
000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */ = {isa = PBXBuildFile; fileRef = 000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */; };
|
||||||
00C1A2B31AC0B7E000E89A1C /* RCTDevelopmentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */; };
|
00C1A2B31AC0B7E000E89A1C /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C1A2B21AC0B7E000E89A1C /* RCTDevMenu.m */; };
|
||||||
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */; };
|
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */; };
|
||||||
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
|
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
|
||||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; };
|
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; };
|
||||||
|
@ -77,8 +77,8 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
000E6CE91AB0E97F000CDF4D /* RCTSourceCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSourceCode.h; sourceTree = "<group>"; };
|
000E6CE91AB0E97F000CDF4D /* RCTSourceCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSourceCode.h; sourceTree = "<group>"; };
|
||||||
000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSourceCode.m; sourceTree = "<group>"; };
|
000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSourceCode.m; sourceTree = "<group>"; };
|
||||||
00C1A2B11AC0B7E000E89A1C /* RCTDevelopmentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevelopmentViewController.h; sourceTree = "<group>"; };
|
00C1A2B11AC0B7E000E89A1C /* RCTDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevMenu.h; sourceTree = "<group>"; };
|
||||||
00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevelopmentViewController.m; sourceTree = "<group>"; };
|
00C1A2B21AC0B7E000E89A1C /* RCTDevMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenu.m; sourceTree = "<group>"; };
|
||||||
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationType.h; sourceTree = "<group>"; };
|
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationType.h; sourceTree = "<group>"; };
|
||||||
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPointerEvents.h; sourceTree = "<group>"; };
|
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPointerEvents.h; sourceTree = "<group>"; };
|
||||||
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTViewControllerProtocol.h; sourceTree = "<group>"; };
|
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTViewControllerProtocol.h; sourceTree = "<group>"; };
|
||||||
|
@ -368,8 +368,8 @@
|
||||||
83CBBA591A601E9000E9B192 /* RCTRedBox.m */,
|
83CBBA591A601E9000E9B192 /* RCTRedBox.m */,
|
||||||
830A229C1A66C68A008503DA /* RCTRootView.h */,
|
830A229C1A66C68A008503DA /* RCTRootView.h */,
|
||||||
830A229D1A66C68A008503DA /* RCTRootView.m */,
|
830A229D1A66C68A008503DA /* RCTRootView.m */,
|
||||||
00C1A2B11AC0B7E000E89A1C /* RCTDevelopmentViewController.h */,
|
00C1A2B11AC0B7E000E89A1C /* RCTDevMenu.h */,
|
||||||
00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */,
|
00C1A2B21AC0B7E000E89A1C /* RCTDevMenu.m */,
|
||||||
83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */,
|
83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */,
|
||||||
83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */,
|
83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */,
|
||||||
83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
|
83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
|
||||||
|
@ -499,7 +499,7 @@
|
||||||
13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
|
13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
|
||||||
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */,
|
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */,
|
||||||
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
|
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
|
||||||
00C1A2B31AC0B7E000E89A1C /* RCTDevelopmentViewController.m in Sources */,
|
00C1A2B31AC0B7E000E89A1C /* RCTDevMenu.m in Sources */,
|
||||||
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
|
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
|
||||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */,
|
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */,
|
||||||
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
|
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
|
||||||
|
|
|
@ -22,19 +22,25 @@
|
||||||
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the `contentSize` is not provided, then the `contentSize` will
|
|
||||||
* automatically be determined by the size of the `RKScrollView` subview.
|
|
||||||
*
|
|
||||||
* The `RCTScrollView` may have at most one single subview. This will ensure
|
* The `RCTScrollView` may have at most one single subview. This will ensure
|
||||||
* that the scroll view's `contentSize` will be efficiently set to the size of
|
* that the scroll view's `contentSize` will be efficiently set to the size of
|
||||||
* the single subview's frame. That frame size will be determined somewhat
|
* the single subview's frame. That frame size will be determined somewhat
|
||||||
* efficiently since it will have already been computed by the off-main-thread
|
* efficiently since it will have already been computed by the off-main-thread
|
||||||
* layout system.
|
* layout system.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, readonly) UIScrollView *scrollView;
|
|
||||||
@property (nonatomic, readonly) UIView *contentView;
|
@property (nonatomic, readonly) UIView *contentView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the `contentSize` is not specified (or is specified as {0, 0}, then the
|
||||||
|
* `contentSize` will automatically be determined by the size of the subview.
|
||||||
|
*/
|
||||||
@property (nonatomic, assign) CGSize contentSize;
|
@property (nonatomic, assign) CGSize contentSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying scrollView (TODO: can we remove this?)
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readonly) UIScrollView *scrollView;
|
||||||
|
|
||||||
@property (nonatomic, assign) UIEdgeInsets contentInset;
|
@property (nonatomic, assign) UIEdgeInsets contentInset;
|
||||||
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
|
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
|
||||||
@property (nonatomic, assign) NSUInteger throttleScrollCallbackMS;
|
@property (nonatomic, assign) NSUInteger throttleScrollCallbackMS;
|
||||||
|
|
|
@ -253,7 +253,6 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
||||||
@implementation RCTScrollView
|
@implementation RCTScrollView
|
||||||
{
|
{
|
||||||
RCTEventDispatcher *_eventDispatcher;
|
RCTEventDispatcher *_eventDispatcher;
|
||||||
BOOL _contentSizeManuallySet;
|
|
||||||
RCTCustomScrollView *_scrollView;
|
RCTCustomScrollView *_scrollView;
|
||||||
UIView *_contentView;
|
UIView *_contentView;
|
||||||
NSTimeInterval _lastScrollDispatchTime;
|
NSTimeInterval _lastScrollDispatchTime;
|
||||||
|
@ -273,6 +272,7 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
||||||
_scrollView.delaysContentTouches = NO;
|
_scrollView.delaysContentTouches = NO;
|
||||||
_automaticallyAdjustContentInsets = YES;
|
_automaticallyAdjustContentInsets = YES;
|
||||||
_contentInset = UIEdgeInsetsZero;
|
_contentInset = UIEdgeInsetsZero;
|
||||||
|
_contentSize = CGSizeZero;
|
||||||
|
|
||||||
_throttleScrollCallbackMS = 0;
|
_throttleScrollCallbackMS = 0;
|
||||||
_lastScrollDispatchTime = CACurrentMediaTime();
|
_lastScrollDispatchTime = CACurrentMediaTime();
|
||||||
|
@ -319,16 +319,6 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
||||||
_scrollView.stickyHeaderIndices = headerIndices;
|
_scrollView.stickyHeaderIndices = headerIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Once you set the `contentSize`, it's assumed to be managed by you forever
|
|
||||||
* and we'll never automatically compute the size for you.
|
|
||||||
*/
|
|
||||||
- (void)setContentSize:(CGSize)contentSize
|
|
||||||
{
|
|
||||||
_contentSize = contentSize;
|
|
||||||
_contentSizeManuallySet = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
_scrollView.delegate = nil;
|
_scrollView.delegate = nil;
|
||||||
|
@ -556,31 +546,42 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, RCTScrollEventTypeMove)
|
||||||
return newOffset;
|
return newOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reactBridgeDidFinishTransaction
|
/**
|
||||||
|
* Once you set the `contentSize`, to a nonzero value, it is assumed to be
|
||||||
|
* managed by you, and we'll never automatically compute the size for you,
|
||||||
|
* unless you manually reset it back to {0, 0}
|
||||||
|
*/
|
||||||
|
- (CGSize)contentSize
|
||||||
{
|
{
|
||||||
if (_contentSizeManuallySet) {
|
if (!CGSizeEqualToSize(_contentSize, CGSizeZero)) {
|
||||||
_scrollView.contentSize = _contentSize;
|
return _contentSize;
|
||||||
} else if (!_contentView) {
|
} else if (!_contentView) {
|
||||||
_scrollView.contentSize = CGSizeZero;
|
return CGSizeZero;
|
||||||
} else {
|
} else {
|
||||||
CGSize singleSubviewSize = _contentView.frame.size;
|
CGSize singleSubviewSize = _contentView.frame.size;
|
||||||
CGPoint singleSubviewPosition = _contentView.frame.origin;
|
CGPoint singleSubviewPosition = _contentView.frame.origin;
|
||||||
CGSize fittedSize = {
|
return (CGSize){
|
||||||
singleSubviewSize.width + singleSubviewPosition.x,
|
singleSubviewSize.width + singleSubviewPosition.x,
|
||||||
singleSubviewSize.height + singleSubviewPosition.y
|
singleSubviewSize.height + singleSubviewPosition.y
|
||||||
};
|
};
|
||||||
if (!CGSizeEqualToSize(_scrollView.contentSize, fittedSize)) {
|
|
||||||
// When contentSize is set manually, ScrollView internals will reset contentOffset to 0,0. Since
|
|
||||||
// we potentially set contentSize whenever anything in the ScrollView updates, we workaround this
|
|
||||||
// issue by manually adjusting contentOffset whenever this happens
|
|
||||||
CGPoint newOffset = [self calculateOffsetForContentSize:fittedSize];
|
|
||||||
_scrollView.contentSize = fittedSize;
|
|
||||||
_scrollView.contentOffset = newOffset;
|
|
||||||
}
|
|
||||||
[_scrollView dockClosestSectionHeader];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)reactBridgeDidFinishTransaction
|
||||||
|
{
|
||||||
|
CGSize contentSize = self.contentSize;
|
||||||
|
if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) {
|
||||||
|
// When contentSize is set manually, ScrollView internals will reset
|
||||||
|
// contentOffset to {0, 0}. Since we potentially set contentSize whenever
|
||||||
|
// anything in the ScrollView updates, we workaround this issue by manually
|
||||||
|
// adjusting contentOffset whenever this happens
|
||||||
|
CGPoint newOffset = [self calculateOffsetForContentSize:contentSize];
|
||||||
|
_scrollView.contentSize = contentSize;
|
||||||
|
_scrollView.contentOffset = newOffset;
|
||||||
|
}
|
||||||
|
[_scrollView dockClosestSectionHeader];
|
||||||
|
}
|
||||||
|
|
||||||
// Note: setting several properties of UIScrollView has the effect of
|
// Note: setting several properties of UIScrollView has the effect of
|
||||||
// resetting its contentOffset to {0, 0}. To prevent this, we generate
|
// resetting its contentOffset to {0, 0}. To prevent this, we generate
|
||||||
// setters here that will record the contentOffset beforehand, and
|
// setters here that will record the contentOffset beforehand, and
|
||||||
|
|
|
@ -41,7 +41,11 @@ RCT_CUSTOM_VIEW_PROPERTY(fontSize, RCTTextField)
|
||||||
}
|
}
|
||||||
RCT_CUSTOM_VIEW_PROPERTY(fontWeight, RCTTextField)
|
RCT_CUSTOM_VIEW_PROPERTY(fontWeight, RCTTextField)
|
||||||
{
|
{
|
||||||
view.font = [RCTConvert UIFont:view.font withWeight:json]; // TODO: default value
|
view.font = [RCTConvert UIFont:view.font withWeight:json]; // defaults to normal
|
||||||
|
}
|
||||||
|
RCT_CUSTOM_VIEW_PROPERTY(fontStyle, RCTTextField)
|
||||||
|
{
|
||||||
|
view.font = [RCTConvert UIFont:view.font withStyle:json]; // defaults to normal
|
||||||
}
|
}
|
||||||
RCT_CUSTOM_VIEW_PROPERTY(fontFamily, RCTTextField)
|
RCT_CUSTOM_VIEW_PROPERTY(fontFamily, RCTTextField)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
React Native Packager
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
React Native Packager is a project similar in scope to browserify or
|
||||||
|
webpack, it provides a CommonJS-like module system, JavaScript
|
||||||
|
compilation (ES6, Flow, JSX), bundling, and asset loading.
|
||||||
|
|
||||||
|
The main difference is the Packager's focus on compilation and
|
||||||
|
bundling speed. We aim for a sub-second edit-reload
|
||||||
|
cycles. Additionally, we don't want users -- with large code bases --
|
||||||
|
to wait more than a few seconds after starting the packager.
|
||||||
|
|
||||||
|
The main deviation from the node module system is the support for our
|
||||||
|
proprietary module format known as `@providesModule`. However, we
|
||||||
|
discourage people to use this module format because going forward, we
|
||||||
|
want to completely separate our infrastructure from React Native and
|
||||||
|
provide an experience most JavaScript developers are familiar with,
|
||||||
|
namely the node module format. We want to even go further, and let you
|
||||||
|
choose your own packager and asset pipeline or even integrate into
|
||||||
|
your existing infrastructure.
|
||||||
|
|
||||||
|
React Native users need not to understand how the packager work,
|
||||||
|
however, this documentation might be useful for advanced users and
|
||||||
|
people who want to fix bugs or add features to the packager (patches
|
||||||
|
welcome!).
|
||||||
|
|
||||||
|
## HTTP interface
|
||||||
|
|
||||||
|
The main way you'd interact with the packager is via the HTTP
|
||||||
|
interface. The following is the list of endpoints and their respective
|
||||||
|
functions.
|
||||||
|
|
||||||
|
### /path/to/moduleName.bundle
|
||||||
|
|
||||||
|
Does the following in order:
|
||||||
|
|
||||||
|
* parse out `path/to/moduleName`
|
||||||
|
* add a `.js` suffix to the path
|
||||||
|
* looks in your project root(s) for the file
|
||||||
|
* recursively collects all the dependencies from an in memory graph
|
||||||
|
* runs the modules through the transformer (might just be cached)
|
||||||
|
* concatenate the modules' content into a bundle
|
||||||
|
* responds to the client with the bundle (and a SourceMap URL)
|
||||||
|
|
||||||
|
### /path/to/moduleName.map
|
||||||
|
|
||||||
|
* if the package has been previously generated via the `.bundle`
|
||||||
|
endpoint then the source map will be generated from that package
|
||||||
|
* if the package has not been previously asked for, this will go
|
||||||
|
through the same steps outlined in the `.bundle` endpoint then
|
||||||
|
generate the source map.
|
||||||
|
|
||||||
|
Note that source map generation currently assumes that the code has
|
||||||
|
been compiled with jstransform, which preserves line and column
|
||||||
|
numbers which allows us to generate source maps super fast.
|
||||||
|
|
||||||
|
### /path/to/moduleName.(map|bundle) query params
|
||||||
|
|
||||||
|
You can pass options for the bundle creation through the query params,
|
||||||
|
if the option is boolean `1/0` or `true/false` is accepted.
|
||||||
|
|
||||||
|
Here are the current options the packager accepts:
|
||||||
|
|
||||||
|
* `dev` boolean, defaults to true: sets a global `__DEV__` variable
|
||||||
|
which will effect how the React Nativeg core libraries behave.
|
||||||
|
* `minify` boolean, defaults to false: whether to minify the bundle.
|
||||||
|
* `runModule` boolean, defaults to true: whether to require your entry
|
||||||
|
point module. So if you requested `moduleName`, this option will add
|
||||||
|
a `require('moduleName')` the end of your bundle.
|
||||||
|
* `inlineSourceMap` boolean, defaults to false: whether to inline
|
||||||
|
source maps.
|
||||||
|
|
||||||
|
### /debug
|
||||||
|
|
||||||
|
This is a page used for debugging, it has links to two pages:
|
||||||
|
|
||||||
|
* Cached Packages: which shows you the packages that's been already
|
||||||
|
generated and cached
|
||||||
|
* Dependency Graph: is the in-memory graph of all the modules and
|
||||||
|
their dependencies
|
||||||
|
|
||||||
|
## Programmatic API
|
||||||
|
|
||||||
|
The packager is made of two things:
|
||||||
|
|
||||||
|
* The core packager (which we're calling ReactPackager)
|
||||||
|
* The scripts, devtools launcher, server run etc.
|
||||||
|
|
||||||
|
ReactPackager is how you mainly interact with the API.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var ReactPackager = require('./react-packager');
|
||||||
|
```
|
||||||
|
|
||||||
|
### ReactPackager.middleware(options)
|
||||||
|
|
||||||
|
Returns a function that can be used in a connect-like
|
||||||
|
middleware. Takes the following options:
|
||||||
|
|
||||||
|
* `projectRoots` array (required): Is the roots where your JavaScript
|
||||||
|
file will exist
|
||||||
|
* `blacklistRE` regexp: Is a patter to ignore certain paths from the
|
||||||
|
packager
|
||||||
|
* `polyfillModuleName` array: Paths to polyfills you want to be
|
||||||
|
included at the start of the bundle
|
||||||
|
* `cacheVersion` string: used in creating the cache file
|
||||||
|
* `resetCache` boolean, defaults to false: whether to use the cache on
|
||||||
|
disk
|
||||||
|
* `transformModulePath` string: Path to the module used as a
|
||||||
|
JavaScript transformer
|
||||||
|
* `nonPersistent` boolean, defaults to false: Whether the server
|
||||||
|
should be used as a persistent deamon to watch files and update
|
||||||
|
itself
|
||||||
|
* `assetRoots` array: Where should the packager look for assets
|
||||||
|
|
||||||
|
### ReactPackager.buildPackageFromUrl(options, url)
|
||||||
|
|
||||||
|
Build a package from a url (see the `.bundle` endpoint). `options` is
|
||||||
|
the same options that is passed to `ReactPackager.middleware`
|
||||||
|
|
||||||
|
### ReactPackager.getDependencies(options, main)
|
||||||
|
|
||||||
|
Given an entry point module. Recursively collect all the dependent
|
||||||
|
modules and return it as an array. `options` is the same options that
|
||||||
|
is passed to `ReactPackager.middleware`
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### Can I use this in my own non-React Native project?
|
||||||
|
|
||||||
|
Yes. It's not really tied to React Native, however feature development
|
||||||
|
is informed by React Native needs.
|
||||||
|
|
||||||
|
### Why didn't you use webpack?
|
||||||
|
|
||||||
|
We love webpack, however, when we tried on our codebase it was slower
|
||||||
|
than our developers would like it to be. You find can more discussion about
|
||||||
|
the subject [here](https://github.com/facebook/react-native/issues/5)
|
Loading…
Reference in New Issue