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
|
||||
# react-native relies on
|
||||
.*/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/event/EventPropagators.js
|
||||
|
||||
|
|
|
@ -233,7 +233,7 @@ var styles = StyleSheet.create({
|
|||
tryAgainText: {
|
||||
color: '#ffffff',
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
cell: {
|
||||
width: CELL_SIZE,
|
||||
|
@ -259,7 +259,7 @@ var styles = StyleSheet.create({
|
|||
fontSize: 24,
|
||||
color: '#776666',
|
||||
fontFamily: 'Verdana',
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
tile2: {
|
||||
backgroundColor: '#eeeeee',
|
||||
|
|
|
@ -62,7 +62,7 @@ var styles = StyleSheet.create({
|
|||
movieTitle: {
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
marginBottom: 2,
|
||||
},
|
||||
movieYear: {
|
||||
|
|
|
@ -109,7 +109,7 @@ var styles = StyleSheet.create({
|
|||
movieTitle: {
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
rating: {
|
||||
marginTop: 10,
|
||||
|
@ -119,7 +119,7 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
ratingValue: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
mpaaWrapper: {
|
||||
alignSelf: 'flex-start',
|
||||
|
@ -131,7 +131,7 @@ var styles = StyleSheet.create({
|
|||
mpaaText: {
|
||||
fontFamily: 'Palatino',
|
||||
fontSize: 13,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
mainSection: {
|
||||
flexDirection: 'row',
|
||||
|
@ -148,7 +148,7 @@ var styles = StyleSheet.create({
|
|||
marginVertical: 10,
|
||||
},
|
||||
castTitle: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
marginBottom: 3,
|
||||
},
|
||||
castActor: {
|
||||
|
|
|
@ -101,7 +101,7 @@ var ShareActionSheetExample = React.createClass({
|
|||
var style = StyleSheet.create({
|
||||
button: {
|
||||
marginBottom: 10,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -94,6 +94,6 @@ var AdSupportIOSExample = React.createClass({
|
|||
|
||||
var styles = StyleSheet.create({
|
||||
title: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -149,14 +149,14 @@ var styles = StyleSheet.create({
|
|||
paddingVertical: 2,
|
||||
},
|
||||
label: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
headingContainer: {
|
||||
padding: 4,
|
||||
backgroundColor: '#f6f7f8',
|
||||
},
|
||||
heading: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
fontSize: 14,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -74,6 +74,6 @@ var GeolocationExample = React.createClass({
|
|||
|
||||
var styles = StyleSheet.create({
|
||||
title: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -214,7 +214,7 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
rowText: {
|
||||
fontSize: 17,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -254,7 +254,7 @@ var styles = StyleSheet.create({
|
|||
fontSize: 18,
|
||||
color: '#666666',
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
lineHeight: 32,
|
||||
},
|
||||
filterText: {
|
||||
|
|
|
@ -107,7 +107,7 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
navBarTitleText: {
|
||||
color: cssVar('fbui-bluegray-60'),
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
marginVertical: 9,
|
||||
},
|
||||
navBarButtonText: {
|
||||
|
|
|
@ -176,7 +176,7 @@ var styles = StyleSheet.create({
|
|||
fontSize: 18,
|
||||
color: '#666666',
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
lineHeight: 32,
|
||||
},
|
||||
filterText: {
|
||||
|
|
|
@ -47,7 +47,7 @@ var styles = StyleSheet.create({
|
|||
text: {
|
||||
fontSize: 14,
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
margin: 10,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@ var Entity = React.createClass({
|
|||
|
||||
var AttributeToggler = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {fontWeight: 'bold', fontSize: 15};
|
||||
return {fontWeight: '500', fontSize: 15};
|
||||
},
|
||||
increaseSize: function() {
|
||||
this.setState({
|
||||
|
@ -129,9 +129,37 @@ exports.examples = [
|
|||
title: 'Font Weight',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{fontWeight: '100'}}>
|
||||
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)'
|
||||
},
|
||||
entity: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
color: '#527fe4',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -187,7 +187,7 @@ var styles = StyleSheet.create({
|
|||
backgroundColor: '#f9f9f9',
|
||||
},
|
||||
textBlock: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
color: 'blue',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "RCTDevelopmentViewController.h"
|
||||
#import "RCTRootView.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
@ -42,7 +41,7 @@
|
|||
rootView.moduleName = @"UIExplorerApp";
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
UIViewController *rootViewController = [[RCTDevelopmentViewController alloc] init];
|
||||
UIViewController *rootViewController = [[UIViewController alloc] init];
|
||||
rootViewController.view = rootView;
|
||||
self.window.rootViewController = rootViewController;
|
||||
[self.window makeKeyAndVisible];
|
||||
|
|
|
@ -76,7 +76,7 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
titleText: {
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
descriptionText: {
|
||||
fontSize: 14,
|
||||
|
|
|
@ -204,7 +204,7 @@ var styles = StyleSheet.create({
|
|||
backgroundColor: 'white',
|
||||
},
|
||||
sectionHeaderTitle: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
fontSize: 11,
|
||||
},
|
||||
row: {
|
||||
|
@ -220,7 +220,7 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
rowTitleText: {
|
||||
fontSize: 17,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
rowDetailText: {
|
||||
fontSize: 15,
|
||||
|
|
|
@ -42,7 +42,7 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
text: {
|
||||
fontSize: 19,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
errorTextTitle: {
|
||||
fontSize: 15,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
marginBottom: 10,
|
||||
},
|
||||
errorText: {
|
||||
|
|
|
@ -81,7 +81,7 @@ var styles = StyleSheet.create({
|
|||
padding: 10,
|
||||
},
|
||||
testName: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: '500',
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
|
|
|
@ -21,28 +21,92 @@ var DEVICE_APPSTATE_EVENT = 'appStateDidChange';
|
|||
|
||||
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(
|
||||
DEVICE_APPSTATE_EVENT,
|
||||
(appStateData) => {
|
||||
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]) {
|
||||
return;
|
||||
}
|
||||
_appStateHandlers[handler].remove();
|
||||
_appStateHandlers[handler] = null;
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
currentState: (null : ?String),
|
||||
|
||||
AppStateIOS.currentState = null;
|
||||
};
|
||||
|
||||
RCTDeviceEventEmitter.addListener(
|
||||
DEVICE_APPSTATE_EVENT,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule View
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
@ -40,18 +39,8 @@ var stylePropType = StyleSheetPropType(ViewStylePropTypes);
|
|||
* </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
|
||||
* performance, although inline styles are also supported. It is common for
|
||||
* `StyleSheet`s to be combined dynamically. See `StyleSheet.js` for more info.
|
||||
* performance, although inline styles are also supported.
|
||||
*/
|
||||
var View = React.createClass({
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
@ -67,10 +56,18 @@ var View = React.createClass({
|
|||
|
||||
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,
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -78,16 +75,16 @@ var View = React.createClass({
|
|||
|
||||
/**
|
||||
* For most touch interactions, you'll simply want to wrap your component in
|
||||
* `TouchableHighlight.js`. Check out `Touchable.js` and
|
||||
* `ScrollResponder.js` for more discussion.
|
||||
* `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`,
|
||||
* `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion.
|
||||
*/
|
||||
onMoveShouldSetResponder: PropTypes.func,
|
||||
onResponderGrant: PropTypes.func,
|
||||
onResponderReject: PropTypes.func,
|
||||
onResponderMove: PropTypes.func,
|
||||
onResponderReject: PropTypes.func,
|
||||
onResponderRelease: PropTypes.func,
|
||||
onResponderTerminate: PropTypes.func,
|
||||
onResponderTerminationRequest: PropTypes.func,
|
||||
onMoveShouldSetResponder: PropTypes.func,
|
||||
onStartShouldSetResponder: 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`
|
||||
* value. `box-none` is as if you had applied the `CSS` class:
|
||||
*
|
||||
* .cantTouchThis * {
|
||||
* pointer-events: auto;
|
||||
* }
|
||||
* .cantTouchThis {
|
||||
* ```
|
||||
* .box-none {
|
||||
* 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
|
||||
* already deviating from the spec by adding additional modes, we opt to not
|
||||
|
@ -114,11 +124,6 @@ var View = React.createClass({
|
|||
'box-only',
|
||||
'auto',
|
||||
]),
|
||||
|
||||
/**
|
||||
* Used to style and layout the `View`. See `StyleSheet.js` and
|
||||
* `ViewStylePropTypes.js` for more info.
|
||||
*/
|
||||
style: stylePropType,
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,18 +21,25 @@ type ChangeEventName = $Enum<{
|
|||
change: string;
|
||||
}>;
|
||||
|
||||
type ReachabilityStateIOS = $Enum<{
|
||||
cell: string;
|
||||
none: string;
|
||||
unknown: string;
|
||||
wifi: string;
|
||||
}>;
|
||||
|
||||
|
||||
/**
|
||||
* NetInfo exposes info about online/offline status
|
||||
*
|
||||
* == iOS Reachability
|
||||
* ### reachabilityIOS
|
||||
*
|
||||
* Asyncronously determine if the device is online and on a cellular network.
|
||||
*
|
||||
* - "none" - device is offline
|
||||
* - "wifi" - device is online and connected via wifi, or is the iOS simulator
|
||||
* - "cell" - device is connected via Edge, 3G, WiMax, or LTE
|
||||
* - "unknown" - error case and the network status is unknown
|
||||
* - `none` - device is offline
|
||||
* - `wifi` - device is online and connected via wifi, or is the iOS simulator
|
||||
* - `cell` - device is connected via Edge, 3G, WiMax, or LTE
|
||||
* - `unknown` - error case and the network status is unknown
|
||||
*
|
||||
* ```
|
||||
* NetInfo.reachabilityIOS.fetch().done((reach) => {
|
||||
|
@ -50,11 +57,37 @@ type ChangeEventName = $Enum<{
|
|||
* 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 = {};
|
||||
|
||||
if (RCTReachability) {
|
||||
|
||||
// RCTReachability is exposed, so this is an iOS-like environment and we will
|
||||
// expose reachabilityIOS
|
||||
|
||||
var _reachabilitySubscriptions = {};
|
||||
|
||||
NetInfo.reachabilityIOS = {
|
||||
|
@ -84,7 +117,7 @@ if (RCTReachability) {
|
|||
fetch: function(): Promise {
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTReachability.getCurrentReachability(
|
||||
(resp) => {
|
||||
function(resp) {
|
||||
resolve(resp.network_reachability);
|
||||
},
|
||||
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 _iosReachabilityIsConnected = function(
|
||||
reachability: ReachabilityStateIOS
|
||||
): bool {
|
||||
return reachability !== 'none' &&
|
||||
reachability !== 'unknown';
|
||||
};
|
||||
|
||||
NetInfo.isConnected = {
|
||||
addEventListener: function (
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
_isConnectedSubscriptions[handler] = (reachability) => {
|
||||
handler(reachability !== 'none');
|
||||
handler(_iosReachabilityIsConnected(reachability));
|
||||
};
|
||||
NetInfo.reachabilityIOS.addEventListener(eventName, _isConnectedSubscriptions[handler]);
|
||||
NetInfo.reachabilityIOS.addEventListener(
|
||||
eventName,
|
||||
_isConnectedSubscriptions[handler]
|
||||
);
|
||||
},
|
||||
|
||||
removeEventListener: function(
|
||||
eventName: ChangeEventName,
|
||||
handler: Function
|
||||
): void {
|
||||
NetInfo.reachabilityIOS.removeEventListener(eventName, _isConnectedSubscriptions[handler]);
|
||||
NetInfo.reachabilityIOS.removeEventListener(
|
||||
eventName,
|
||||
_isConnectedSubscriptions[handler]
|
||||
);
|
||||
},
|
||||
|
||||
fetch: function(): Promise {
|
||||
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.
|
||||
*
|
||||
* @providesModule IOSDefaultEventPluginOrder
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule IOSNativeBridgeEventPlugin
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
@ -51,10 +52,11 @@ var IOSNativeBridgeEventPlugin = {
|
|||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
topLevelType: string,
|
||||
topLevelTarget: EventTarget,
|
||||
topLevelTargetID: string,
|
||||
nativeEvent: Event
|
||||
): ?Object {
|
||||
var bubbleDispatchConfig = customBubblingEventTypes[topLevelType];
|
||||
var directDispatchConfig = customDirectEventTypes[topLevelType];
|
||||
var event = SyntheticEvent.getPooled(
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule NativeMethodsMixin
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeModules = require('NativeModules');
|
||||
var NativeModules = require('NativeModules');
|
||||
var RCTPOPAnimationManager = NativeModules.POPAnimationManager;
|
||||
var RCTUIManager = NativeModules.UIManager;
|
||||
|
@ -20,7 +20,26 @@ var flattenStyle = require('flattenStyle');
|
|||
var invariant = require('invariant');
|
||||
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(
|
||||
anim,
|
||||
funcName + ' must be called with a valid animation ID returned from' +
|
||||
|
@ -29,21 +48,25 @@ var animationIDInvariant = function(funcName, anim) {
|
|||
};
|
||||
|
||||
var NativeMethodsMixin = {
|
||||
addAnimation: function(anim, callback) {
|
||||
addAnimation: function(anim: number, callback?: (finished: bool) => void) {
|
||||
animationIDInvariant('addAnimation', anim);
|
||||
RCTPOPAnimationManager.addAnimation(this.getNodeHandle(), anim, callback);
|
||||
},
|
||||
|
||||
removeAnimation: function(anim) {
|
||||
removeAnimation: function(anim: number) {
|
||||
animationIDInvariant('removeAnimation', anim);
|
||||
RCTPOPAnimationManager.removeAnimation(this.getNodeHandle(), anim);
|
||||
},
|
||||
|
||||
measure: function(callback) {
|
||||
measure: function(callback: MeasureOnSuccessCallback) {
|
||||
RCTUIManager.measure(this.getNodeHandle(), callback);
|
||||
},
|
||||
|
||||
measureLayout: function(relativeToNativeNode, onSuccess, onFail) {
|
||||
measureLayout: function(
|
||||
relativeToNativeNode: number,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail: () => void /* currently unused */
|
||||
) {
|
||||
RCTUIManager.measureLayout(
|
||||
this.getNodeHandle(),
|
||||
relativeToNativeNode,
|
||||
|
@ -57,7 +80,7 @@ var NativeMethodsMixin = {
|
|||
* in future diff process, this means that if you do not include them in the
|
||||
* next render, they will remain active.
|
||||
*/
|
||||
setNativeProps: function(nativeProps) {
|
||||
setNativeProps: function(nativeProps: Object) {
|
||||
// nativeProps contains a style attribute that's going to be flattened
|
||||
// and all the attributes expanded in place. In order to make this
|
||||
// process do as few allocations and copies as possible, we return
|
||||
|
@ -111,15 +134,19 @@ function throwOnStylesProp(component, props) {
|
|||
}
|
||||
}
|
||||
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(
|
||||
!NativeMethodsMixin.componentWillMount &&
|
||||
!NativeMethodsMixin.componentWillReceiveProps,
|
||||
!NativeMethodsMixin_DEV.componentWillMount &&
|
||||
!NativeMethodsMixin_DEV.componentWillReceiveProps,
|
||||
'Do not override existing functions.'
|
||||
);
|
||||
NativeMethodsMixin.componentWillMount = function () {
|
||||
NativeMethodsMixin_DEV.componentWillMount = function () {
|
||||
throwOnStylesProp(this, this.props);
|
||||
};
|
||||
NativeMethodsMixin.componentWillReceiveProps = function (newProps) {
|
||||
NativeMethodsMixin_DEV.componentWillReceiveProps = function (newProps) {
|
||||
throwOnStylesProp(this, newProps);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule React
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactIOS
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var ReactChildren = require('ReactChildren');
|
||||
|
@ -51,7 +51,7 @@ var resolveDefaultProps = function(element) {
|
|||
};
|
||||
|
||||
// Experimental optimized element creation
|
||||
var augmentElement = function(element) {
|
||||
var augmentElement = function(element: ReactElement) {
|
||||
if (__DEV__) {
|
||||
invariant(
|
||||
false,
|
||||
|
@ -67,7 +67,7 @@ var augmentElement = function(element) {
|
|||
return element;
|
||||
};
|
||||
|
||||
var render = function(component, mountInto) {
|
||||
var render = function(component: ReactComponent, mountInto: number) {
|
||||
ReactIOSMount.renderComponent(component, mountInto);
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactIOSComponentEnvironment
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactIOSComponentMixin
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactIOSDOMIDOperations
|
||||
* @typechecks static-only
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactIOSDefaultInjection
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule createReactIOSNativeComponentClass
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
@ -14,11 +15,19 @@
|
|||
var ReactElement = require('ReactElement');
|
||||
var ReactIOSNativeComponent = require('ReactIOSNativeComponent');
|
||||
|
||||
// See also ReactIOSNativeComponent
|
||||
type ReactIOSNativeComponentViewConfig = {
|
||||
validAttributes: Object;
|
||||
uiViewClassName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} config iOS View configuration.
|
||||
* @private
|
||||
*/
|
||||
var createReactIOSNativeComponentClass = function(viewConfig) {
|
||||
var createReactIOSNativeComponentClass = function(
|
||||
viewConfig: ReactIOSNativeComponentViewConfig
|
||||
): Function { // returning Function is lossy :/
|
||||
var Constructor = function(element) {
|
||||
this._currentElement = element;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule diffRawProperties
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
|
@ -21,13 +22,19 @@
|
|||
* previous. These properties are as supplied to component construction.
|
||||
* @return {?object}
|
||||
*/
|
||||
function diffRawProperties(updatePayload, prevProps, nextProps, validAttributes) {
|
||||
function diffRawProperties(
|
||||
updatePayload: ?Object,
|
||||
prevProps: ?Object,
|
||||
nextProps: ?Object,
|
||||
validAttributes: Object
|
||||
): ?Object {
|
||||
var validAttributeConfig;
|
||||
var nextProp;
|
||||
var prevProp;
|
||||
var isScalar;
|
||||
var shouldUpdate;
|
||||
|
||||
if (nextProps) {
|
||||
for (var propKey in nextProps) {
|
||||
validAttributeConfig = validAttributes[propKey];
|
||||
if (!validAttributeConfig) {
|
||||
|
@ -52,10 +59,12 @@ function diffRawProperties(updatePayload, prevProps, nextProps, validAttributes)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// default.
|
||||
if (prevProps) {
|
||||
for (var propKey in prevProps) {
|
||||
validAttributeConfig = validAttributes[propKey];
|
||||
if (!validAttributeConfig) {
|
||||
|
@ -84,6 +93,7 @@ function diffRawProperties(updatePayload, prevProps, nextProps, validAttributes)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return updatePayload;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ extern NSString *const RCTReactTagAttributeName;
|
|||
@property (nonatomic, copy) NSString *fontFamily;
|
||||
@property (nonatomic, assign) CGFloat fontSize;
|
||||
@property (nonatomic, copy) NSString *fontWeight;
|
||||
@property (nonatomic, copy) NSString *fontStyle;
|
||||
@property (nonatomic, assign) BOOL isHighlighted;
|
||||
@property (nonatomic, assign) CGFloat lineHeight;
|
||||
@property (nonatomic, assign) NSInteger maxNumberOfLines;
|
||||
|
|
|
@ -50,12 +50,14 @@ static css_dim_t RCTMeasure(void *context, float width)
|
|||
{
|
||||
return [self _attributedStringWithFontFamily:nil
|
||||
fontSize:0
|
||||
fontWeight:nil];
|
||||
fontWeight:nil
|
||||
fontStyle:nil];
|
||||
}
|
||||
|
||||
- (NSAttributedString *)_attributedStringWithFontFamily:(NSString *)fontFamily
|
||||
fontSize:(CGFloat)fontSize
|
||||
fontWeight:(NSString *)fontWeight
|
||||
fontStyle:(NSString *)fontStyle
|
||||
{
|
||||
if (![self isTextDirty] && _cachedAttributedString) {
|
||||
return _cachedAttributedString;
|
||||
|
@ -67,6 +69,9 @@ static css_dim_t RCTMeasure(void *context, float width)
|
|||
if (_fontWeight) {
|
||||
fontWeight = _fontWeight;
|
||||
}
|
||||
if (_fontStyle) {
|
||||
fontStyle = _fontStyle;
|
||||
}
|
||||
if (_fontFamily) {
|
||||
fontFamily = _fontFamily;
|
||||
}
|
||||
|
@ -75,7 +80,7 @@ static css_dim_t RCTMeasure(void *context, float width)
|
|||
for (RCTShadowView *child in [self reactSubviews]) {
|
||||
if ([child isKindOfClass:[RCTShadowText class]]) {
|
||||
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]]) {
|
||||
RCTShadowRawText *shadowRawText = (RCTShadowRawText *)child;
|
||||
[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];
|
||||
}
|
||||
|
||||
_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:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString];
|
||||
[self _setParagraphStyleOnAttributedString:attributedString];
|
||||
|
@ -110,7 +115,7 @@ static css_dim_t RCTMeasure(void *context, float width)
|
|||
|
||||
- (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
|
||||
|
|
|
@ -12,3 +12,7 @@
|
|||
// see also react-native.js
|
||||
|
||||
declare var __DEV__: boolean;
|
||||
|
||||
declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: any; /*?{
|
||||
inject: ?((stuff: Object) => void)
|
||||
};*/
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#import "Layout.h"
|
||||
#import "RCTAnimationType.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTPointerEvents.h"
|
||||
|
||||
/**
|
||||
|
@ -69,8 +70,13 @@
|
|||
|
||||
+ (UIFont *)UIFont:(UIFont *)font withSize:(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 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 *)NSURLArray:(id)json;
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#import <objc/message.h>
|
||||
|
||||
#import "RCTLog.h"
|
||||
|
||||
@implementation RCTConvert
|
||||
|
||||
RCT_CONVERTER(BOOL, BOOL, boolValue)
|
||||
|
@ -135,7 +133,9 @@ RCT_CGSTRUCT_CONVERTER(CATransform3D, (@[
|
|||
@"m41", @"m42", @"m43", @"m44"
|
||||
]), 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
|
||||
{
|
||||
|
@ -364,7 +364,8 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty
|
|||
|
||||
} 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
|
||||
|
@ -418,100 +419,163 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty
|
|||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
NSString *const RCTDefaultFontName = @"HelveticaNeue";
|
||||
NSString *const RCTDefaultFontWeight = @"normal";
|
||||
NSString *const RCTBoldFontWeight = @"bold";
|
||||
// Defaults
|
||||
NSString *const RCTDefaultFontFamily = @"Helvetica Neue";
|
||||
const RCTFontWeight RCTDefaultFontWeight = UIFontWeightRegular;
|
||||
const CGFloat RCTDefaultFontSize = 14;
|
||||
|
||||
// Create descriptor
|
||||
UIFontDescriptor *fontDescriptor = font.fontDescriptor ?: [UIFontDescriptor fontDescriptorWithName:RCTDefaultFontName size:RCTDefaultFontSize];
|
||||
// Get existing properties
|
||||
BOOL isItalic = NO;
|
||||
BOOL isCondensed = NO;
|
||||
RCTFontWeight fontWeight = RCTDefaultFontWeight;
|
||||
if (font) {
|
||||
family = font.familyName;
|
||||
fontWeight = RCTWeightOfFont(font);
|
||||
isItalic = RCTFontIsItalic(font);
|
||||
isCondensed = RCTFontIsCondensed(font);
|
||||
}
|
||||
|
||||
// Get font weight
|
||||
if (weight) {
|
||||
fontWeight = [self RCTFontWeight:weight];
|
||||
}
|
||||
|
||||
// Get font style
|
||||
if (style) {
|
||||
isItalic = [self RCTFontStyle:style];
|
||||
}
|
||||
|
||||
// Get font size
|
||||
CGFloat fontSize = [self CGFloat:size];
|
||||
if (fontSize && !isnan(fontSize)) {
|
||||
fontDescriptor = [fontDescriptor fontDescriptorWithSize:fontSize];
|
||||
}
|
||||
CGFloat fontSize = [self CGFloat:size] ?: RCTDefaultFontSize;
|
||||
|
||||
// Get font family
|
||||
NSString *familyName = [self NSString:family];
|
||||
if (familyName) {
|
||||
NSString *familyName = [self NSString:family] ?: RCTDefaultFontFamily;
|
||||
if ([UIFont fontNamesForFamilyName:familyName].count == 0) {
|
||||
font = [UIFont fontWithName:familyName size:fontDescriptor.pointSize];
|
||||
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;
|
||||
fontDescriptor = font.fontDescriptor;
|
||||
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||
fontWeight = [traits[UIFontWeightTrait] doubleValue];
|
||||
} else {
|
||||
// Not a valid font or family
|
||||
RCTLogError(@"Unrecognized font family '%@'", familyName);
|
||||
familyName = [UIFont fontWithDescriptor:fontDescriptor size:0].familyName;
|
||||
familyName = RCTDefaultFontFamily;
|
||||
}
|
||||
} else {
|
||||
// Set font family
|
||||
fontDescriptor = [fontDescriptor fontDescriptorWithFamily:familyName];
|
||||
}
|
||||
} else {
|
||||
familyName = [UIFont fontWithDescriptor:fontDescriptor size:0].familyName;
|
||||
}
|
||||
|
||||
// Get font weight
|
||||
NSString *fontWeight = [self NSString:weight];
|
||||
if (fontWeight) {
|
||||
|
||||
static NSSet *values;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
values = [NSSet setWithObjects:RCTDefaultFontWeight, RCTBoldFontWeight, nil];
|
||||
});
|
||||
|
||||
if (fontWeight && ![values containsObject:fontWeight]) {
|
||||
RCTLogError(@"Unrecognized font weight '%@', must be one of %@", fontWeight, values);
|
||||
fontWeight = RCTDefaultFontWeight;
|
||||
}
|
||||
|
||||
// this is hacky. we are appending the string -Medium because most fonts we currently use
|
||||
// just need to have -Medium appended to get the bold we want. we're going to revamp this
|
||||
// to make it easier to know which options are available in JS. t4996115
|
||||
if ([fontWeight isEqualToString:RCTBoldFontWeight]) {
|
||||
font = nil;
|
||||
for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) {
|
||||
if ([fontName hasSuffix:@"-Medium"]) {
|
||||
font = [UIFont fontWithName:fontName size:fontDescriptor.pointSize];
|
||||
break;
|
||||
}
|
||||
if ([fontName hasSuffix:@"-Bold"]) {
|
||||
font = [UIFont fontWithName:fontName size:fontDescriptor.pointSize];
|
||||
// But keep searching in case there's a medium option
|
||||
}
|
||||
}
|
||||
if (font) {
|
||||
fontDescriptor = font.fontDescriptor;
|
||||
// Get closest match
|
||||
UIFont *bestMatch = font;
|
||||
CGFloat closestWeight = font ? RCTWeightOfFont(font) : INFINITY;
|
||||
for (NSString *name in [UIFont fontNamesForFamilyName:familyName]) {
|
||||
UIFont *match = [UIFont fontWithName:name size:fontSize];
|
||||
if (isItalic == RCTFontIsItalic(match) &&
|
||||
isCondensed == RCTFontIsCondensed(match)) {
|
||||
CGFloat testWeight = RCTWeightOfFont(match);
|
||||
if (ABS(testWeight - fontWeight) < ABS(closestWeight - fontWeight)) {
|
||||
bestMatch = match;
|
||||
closestWeight = testWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 [UIFont fontWithDescriptor:fontDescriptor size:0];
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
RCT_ARRAY_CONVERTER(NSString)
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RCTDevelopmentViewController : UIViewController
|
||||
@class RCTRootView;
|
||||
|
||||
@interface RCTDevMenu : NSObject
|
||||
|
||||
- (instancetype)initWithRootView:(RCTRootView *)rootView;
|
||||
- (void)show;
|
||||
|
||||
@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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTContextExecutor.h"
|
||||
#import "RCTDevMenu.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTKeyCommands.h"
|
||||
#import "RCTLog.h"
|
||||
|
@ -26,6 +27,7 @@ NSString *const RCTReloadNotification = @"RCTReloadNotification";
|
|||
|
||||
@implementation RCTRootView
|
||||
{
|
||||
RCTDevMenu *_devMenu;
|
||||
RCTBridge *_bridge;
|
||||
RCTTouchHandler *_touchHandler;
|
||||
id<RCTJavaScriptExecutor> _executor;
|
||||
|
@ -84,6 +86,9 @@ static Class _globalExecutorClass;
|
|||
// Numbering of these tags goes from 1, 11, 21, 31, etc
|
||||
static NSInteger rootViewTag = 1;
|
||||
self.reactTag = @(rootViewTag);
|
||||
#ifdef DEBUG
|
||||
self.enableDevMenu = YES;
|
||||
#endif
|
||||
rootViewTag += 10;
|
||||
|
||||
// Add reload observer
|
||||
|
@ -93,6 +98,21 @@ static Class _globalExecutorClass;
|
|||
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
|
||||
{
|
||||
return @[
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
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 */; };
|
||||
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
|
||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; };
|
||||
|
@ -77,8 +77,8 @@
|
|||
/* Begin PBXFileReference section */
|
||||
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>"; };
|
||||
00C1A2B11AC0B7E000E89A1C /* RCTDevelopmentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevelopmentViewController.h; sourceTree = "<group>"; };
|
||||
00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevelopmentViewController.m; sourceTree = "<group>"; };
|
||||
00C1A2B11AC0B7E000E89A1C /* RCTDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevMenu.h; 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>"; };
|
||||
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>"; };
|
||||
|
@ -368,8 +368,8 @@
|
|||
83CBBA591A601E9000E9B192 /* RCTRedBox.m */,
|
||||
830A229C1A66C68A008503DA /* RCTRootView.h */,
|
||||
830A229D1A66C68A008503DA /* RCTRootView.m */,
|
||||
00C1A2B11AC0B7E000E89A1C /* RCTDevelopmentViewController.h */,
|
||||
00C1A2B21AC0B7E000E89A1C /* RCTDevelopmentViewController.m */,
|
||||
00C1A2B11AC0B7E000E89A1C /* RCTDevMenu.h */,
|
||||
00C1A2B21AC0B7E000E89A1C /* RCTDevMenu.m */,
|
||||
83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */,
|
||||
83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */,
|
||||
83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
|
||||
|
@ -499,7 +499,7 @@
|
|||
13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
|
||||
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */,
|
||||
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
|
||||
00C1A2B31AC0B7E000E89A1C /* RCTDevelopmentViewController.m in Sources */,
|
||||
00C1A2B31AC0B7E000E89A1C /* RCTDevMenu.m in Sources */,
|
||||
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
|
||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */,
|
||||
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
|
||||
|
|
|
@ -22,19 +22,25 @@
|
|||
- (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
|
||||
* 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
|
||||
* efficiently since it will have already been computed by the off-main-thread
|
||||
* layout system.
|
||||
*/
|
||||
@property (nonatomic, readonly) UIScrollView *scrollView;
|
||||
@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;
|
||||
|
||||
/**
|
||||
* The underlying scrollView (TODO: can we remove this?)
|
||||
*/
|
||||
@property (nonatomic, readonly) UIScrollView *scrollView;
|
||||
|
||||
@property (nonatomic, assign) UIEdgeInsets contentInset;
|
||||
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
|
||||
@property (nonatomic, assign) NSUInteger throttleScrollCallbackMS;
|
||||
|
|
|
@ -253,7 +253,6 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
@implementation RCTScrollView
|
||||
{
|
||||
RCTEventDispatcher *_eventDispatcher;
|
||||
BOOL _contentSizeManuallySet;
|
||||
RCTCustomScrollView *_scrollView;
|
||||
UIView *_contentView;
|
||||
NSTimeInterval _lastScrollDispatchTime;
|
||||
|
@ -273,6 +272,7 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
_scrollView.delaysContentTouches = NO;
|
||||
_automaticallyAdjustContentInsets = YES;
|
||||
_contentInset = UIEdgeInsetsZero;
|
||||
_contentSize = CGSizeZero;
|
||||
|
||||
_throttleScrollCallbackMS = 0;
|
||||
_lastScrollDispatchTime = CACurrentMediaTime();
|
||||
|
@ -319,16 +319,6 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
|
|||
_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
|
||||
{
|
||||
_scrollView.delegate = nil;
|
||||
|
@ -556,30 +546,41 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, RCTScrollEventTypeMove)
|
|||
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) {
|
||||
_scrollView.contentSize = _contentSize;
|
||||
if (!CGSizeEqualToSize(_contentSize, CGSizeZero)) {
|
||||
return _contentSize;
|
||||
} else if (!_contentView) {
|
||||
_scrollView.contentSize = CGSizeZero;
|
||||
return CGSizeZero;
|
||||
} else {
|
||||
CGSize singleSubviewSize = _contentView.frame.size;
|
||||
CGPoint singleSubviewPosition = _contentView.frame.origin;
|
||||
CGSize fittedSize = {
|
||||
return (CGSize){
|
||||
singleSubviewSize.width + singleSubviewPosition.x,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
- (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
|
||||
// resetting its contentOffset to {0, 0}. To prevent this, we generate
|
||||
|
|
|
@ -41,7 +41,11 @@ RCT_CUSTOM_VIEW_PROPERTY(fontSize, 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)
|
||||
{
|
||||
|
|
|
@ -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