Merge pull request #1264 from vjeux/Update_Wed_13_May

Update wed 13 may
This commit is contained in:
Christopher Chedeau 2015-05-13 14:47:49 -07:00
commit fec81947bd
103 changed files with 1855 additions and 732 deletions

View File

@ -150,7 +150,7 @@ class Game2048 extends React.Component {
startX: number;
startY: number;
constructor(props) {
constructor(props: {}) {
super(props);
this.state = {
board: new GameBoard(),

View File

@ -95,9 +95,98 @@ exports.examples = [{
</TouchableHighlight>
</View>
);
}
},
{
title: 'Prompt',
render(): React.Component {
return <PromptExample />
}
}];
class PromptExample extends React.Component {
constructor(props) {
super(props);
this.promptResponse = this.promptResponse.bind(this);
this.state = {
promptValue: undefined,
};
this.title = 'Type a value';
this.defaultValue = 'Default value';
this.buttons = [{
text: 'Custom cancel',
}, {
text: 'Custom OK',
onPress: this.promptResponse
}];
}
render() {
return (
<View>
<Text style={{marginBottom: 10}}>
<Text style={{fontWeight: 'bold'}}>Prompt value:</Text> {this.state.promptValue}
</Text>
<TouchableHighlight
style={styles.wrapper}
onPress={this.prompt.bind(this, this.title, this.promptResponse)}>
<View style={styles.button}>
<Text>
prompt with title & callback
</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
onPress={this.prompt.bind(this, this.title, this.buttons)}>
<View style={styles.button}>
<Text>
prompt with title & custom buttons
</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
onPress={this.prompt.bind(this, this.title, this.defaultValue, this.promptResponse)}>
<View style={styles.button}>
<Text>
prompt with title, default value & callback
</Text>
</View>
</TouchableHighlight>
<TouchableHighlight
style={styles.wrapper}
onPress={this.prompt.bind(this, this.title, this.defaultValue, this.buttons)}>
<View style={styles.button}>
<Text>
prompt with title, default value & custom buttons
</Text>
</View>
</TouchableHighlight>
</View>
);
}
prompt() {
// Flow's apply support is broken: #7035621
((AlertIOS.prompt: any).apply: any)(AlertIOS, arguments);
}
promptResponse(promptValue) {
this.setState({ promptValue });
}
}
var styles = StyleSheet.create({
wrapper: {
borderRadius: 5,

View File

@ -68,6 +68,18 @@ var styles = StyleSheet.create({
borderLeftWidth: 40,
borderLeftColor: 'blue',
},
border6: {
borderTopWidth: 10,
borderTopColor: 'red',
borderRightWidth: 20,
borderRightColor: 'yellow',
borderBottomWidth: 30,
borderBottomColor: 'green',
borderLeftWidth: 40,
borderLeftColor: 'blue',
borderTopLeftRadius: 100,
},
});
exports.title = 'Border';
@ -115,4 +127,11 @@ exports.examples = [
return <View style={[styles.box, styles.border5]} />;
}
},
{
title: 'Custom Borders',
description: 'border*Width & border*Color',
render() {
return <View style={[styles.box, styles.border6]} />;
}
},
];

View File

@ -0,0 +1,30 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @providesModule ExampleTypes
* @flow
*/
export type Example = {
title: string,
render: () => ?ReactElement<any, any, any>,
description?: string,
};
export type ExampleModule = {
title: string;
description: string;
examples: Array<Example>;
external?: bool;
};

View File

@ -168,7 +168,7 @@ var MapViewExample = React.createClass({
/>
<MapRegionInput
onChange={this._onRegionInputChanged}
region={this.state.mapRegionInput}
region={this.state.mapRegionInput || undefined}
/>
</View>
);

View File

@ -181,7 +181,13 @@ var BoxOnlyExample = React.createClass({
}
});
var exampleClasses = [
type ExampleClass = {
Component: ReactClass<any, any, any>,
title: string,
description: string,
};
var exampleClasses: Array<ExampleClass> = [
{
Component: NoneExample,
title: '`none`',

View File

@ -218,6 +218,26 @@ exports.examples = [
</View>
);
},
}, {
title: 'Letter Spacing',
render: function() {
return (
<View>
<Text style={{letterSpacing: 0}}>
letterSpacing = 0
</Text>
<Text style={{letterSpacing: 2, marginTop: 5}}>
letterSpacing = 2
</Text>
<Text style={{letterSpacing: 9, marginTop: 5}}>
letterSpacing = 9
</Text>
<Text style={{letterSpacing: -1, marginTop: 5}}>
letterSpacing = -1
</Text>
</View>
);
},
}, {
title: 'Spaces',
render: function() {

View File

@ -69,9 +69,10 @@ var styles = StyleSheet.create({
overflow: 'hidden',
},
titleContainer: {
borderWidth: 0.5,
borderRadius: 2.5,
borderColor: '#d6d7da',
borderBottomWidth: 0.5,
borderTopLeftRadius: 3,
borderTopRightRadius: 2.5,
borderBottomColor: '#d6d7da',
backgroundColor: '#f6f7f8',
paddingHorizontal: 10,
paddingVertical: 5,

View File

@ -30,6 +30,8 @@ var {
var { TestModule } = React.addons;
var Settings = require('Settings');
import type { Example, ExampleModule } from 'ExampleTypes';
var createExamplePage = require('./createExamplePage');
var COMPONENTS = [
@ -107,9 +109,17 @@ COMPONENTS.concat(APIS).forEach((Example) => {
}
});
class UIExplorerList extends React.Component {
type Props = {
navigator: Array<{title: string, component: ReactClass<any,any,any>}>,
onExternalExampleRequested: Function,
};
constructor(props) {
class UIExplorerList extends React.Component {
props: Props;
constructor(props: Props) {
super(props);
this.state = {
dataSource: ds.cloneWithRowsAndSections({
@ -149,7 +159,7 @@ class UIExplorerList extends React.Component {
);
}
_renderSectionHeader(data, section) {
_renderSectionHeader(data: any, section: string) {
return (
<View style={styles.sectionHeader}>
<Text style={styles.sectionHeaderTitle}>
@ -159,7 +169,7 @@ class UIExplorerList extends React.Component {
);
}
_renderRow(example, i) {
_renderRow(example: ExampleModule, i: number) {
return (
<View key={i}>
<TouchableHighlight onPress={() => this._onPressRow(example)}>
@ -177,7 +187,7 @@ class UIExplorerList extends React.Component {
);
}
_search(text) {
_search(text: mixed) {
var regex = new RegExp(text, 'i');
var filter = (component) => regex.test(component.title);
@ -191,7 +201,7 @@ class UIExplorerList extends React.Component {
Settings.set({searchText: text});
}
_onPressRow(example) {
_onPressRow(example: ExampleModule) {
if (example.external) {
this.props.onExternalExampleRequested(example);
return;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 273 KiB

View File

@ -88,35 +88,19 @@
XCTAssertTrue(foundElement, @"Cound't find element with '<View>' text in %d seconds", TIMEOUT_SECONDS);
}
- (void)testViewExampleSnapshot
{
[_runner runTest:_cmd module:@"ViewExample"];
#define RCT_SNAPSHOT_TEST(name, reRecord) \
- (void)test##name##Snapshot \
{ \
_runner.recordMode |= reRecord; \
[_runner runTest:_cmd module:@#name]; \
}
- (void)testLayoutExampleSnapshot
{
[_runner runTest:_cmd module:@"LayoutExample"];
}
- (void)testTextExampleSnapshot
{
[_runner runTest:_cmd module:@"TextExample"];
}
- (void)testSwitchExampleSnapshot
{
[_runner runTest:_cmd module:@"SwitchExample"];
}
- (void)testSliderExampleSnapshot
{
[_runner runTest:_cmd module:@"SliderExample"];
}
- (void)testTabBarExampleSnapshot
{
[_runner runTest:_cmd module:@"TabBarExample"];
}
RCT_SNAPSHOT_TEST(ViewExample, NO)
RCT_SNAPSHOT_TEST(LayoutExample, NO)
RCT_SNAPSHOT_TEST(TextExample, NO)
RCT_SNAPSHOT_TEST(SwitchExample, NO)
RCT_SNAPSHOT_TEST(SliderExample, NO)
RCT_SNAPSHOT_TEST(TabBarExample, NO)
// Make sure this test runs last
- (void)testZZZ_NotInRecordMode

View File

@ -17,22 +17,13 @@
'use strict';
var React = require('react-native');
var ReactIOS = require('ReactIOS');
var ReactNative = require('ReactNative');
var UIExplorerBlock = require('./UIExplorerBlock');
var UIExplorerPage = require('./UIExplorerPage');
var invariant = require('invariant');
class Example extends React.Component {
title: string;
description: string;
}
type ExampleModule = {
title: string;
description: string;
examples: Array<Example>;
};
import type { Example, ExampleModule } from 'ExampleTypes';
var createExamplePage = function(title: ?string, exampleModule: ExampleModule)
: ReactClass<any, any, any> {
@ -44,20 +35,20 @@ var createExamplePage = function(title: ?string, exampleModule: ExampleModule)
description: exampleModule.description,
},
getBlock: function(example, i) {
getBlock: function(example: Example, i) {
// Hack warning: This is a hack because the www UI explorer requires
// renderComponent to be called.
var originalRender = React.render;
var originalRenderComponent = React.renderComponent;
var originalIOSRender = ReactIOS.render;
var originalIOSRenderComponent = ReactIOS.renderComponent;
var originalIOSRender = ReactNative.render;
var originalIOSRenderComponent = ReactNative.renderComponent;
var renderedComponent;
// TODO remove typecasts when Flow bug #6560135 is fixed
// and workaround is removed from react-native.js
(React: Object).render =
(React: Object).renderComponent =
(ReactIOS: Object).render =
(ReactIOS: Object).renderComponent =
(ReactNative: Object).render =
(ReactNative: Object).renderComponent =
function(element, container) {
renderedComponent = element;
};
@ -67,8 +58,8 @@ var createExamplePage = function(title: ?string, exampleModule: ExampleModule)
}
(React: Object).render = originalRender;
(React: Object).renderComponent = originalRenderComponent;
(ReactIOS: Object).render = originalIOSRender;
(ReactIOS: Object).renderComponent = originalIOSRenderComponent;
(ReactNative: Object).render = originalIOSRender;
(ReactNative: Object).renderComponent = originalIOSRenderComponent;
return (
<UIExplorerBlock
key={i}

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSART
* @providesModule ReactNativeART
*/
"use strict";
@ -16,9 +16,9 @@ var Path = require('ARTSerializablePath');
var Transform = require('art/core/transform');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var merge = require('merge');
// Diff Helpers
@ -64,7 +64,7 @@ function fontAndLinesDiffer(a, b) {
// Native Attributes
var SurfaceViewAttributes = merge(ReactIOSViewAttributes.UIView, {
var SurfaceViewAttributes = merge(ReactNativeViewAttributes.UIView, {
// This should contain pixel information such as width, height and
// resolution to know what kind of buffer needs to be allocated.
// Currently we rely on UIViews and style to figure that out.
@ -100,22 +100,22 @@ var TextAttributes = merge(RenderableAttributes, {
// Native Components
var NativeSurfaceView = createReactIOSNativeComponentClass({
var NativeSurfaceView = createReactNativeComponentClass({
validAttributes: SurfaceViewAttributes,
uiViewClassName: 'ARTSurfaceView',
});
var NativeGroup = createReactIOSNativeComponentClass({
var NativeGroup = createReactNativeComponentClass({
validAttributes: GroupAttributes,
uiViewClassName: 'ARTGroup',
});
var NativeShape = createReactIOSNativeComponentClass({
var NativeShape = createReactNativeComponentClass({
validAttributes: ShapeAttributes,
uiViewClassName: 'ARTShape',
});
var NativeText = createReactIOSNativeComponentClass({
var NativeText = createReactNativeComponentClass({
validAttributes: TextAttributes,
uiViewClassName: 'ARTText',
});

View File

@ -12,6 +12,7 @@
'use strict';
var RCTAnimationManager = require('NativeModules').AnimationExperimentalManager;
var React = require('React');
var AnimationUtils = require('AnimationUtils');
type EasingFunction = (t: number) => number;
@ -47,7 +48,7 @@ var AnimationExperimental = {
},
callback?: ?(finished: bool) => void
): number {
var nodeHandle = anim.node.getNodeHandle();
var nodeHandle = React.findNodeHandle(anim.node);
var easingSample = AnimationUtils.evaluateEasingFunction(
anim.duration,
anim.easing

View File

@ -12,6 +12,7 @@
'use strict';
var POPAnimationOrNull = require('POPAnimation');
var React = require('React');
if (!POPAnimationOrNull) {
// POP animation isn't available in the OSS fork - this is a temporary
@ -83,7 +84,7 @@ var POPAnimationMixin = {
'Invalid refKey ' + refKey + ' for anim:\n' + JSON.stringify(anim) +
'\nvalid refs: ' + JSON.stringify(Object.keys(this.refs))
);
var refNodeHandle = this.refs[refKey].getNodeHandle();
var refNodeHandle = React.findNodeHandle(this.refs[refKey]);
this.startAnimationWithNodeHandle(refNodeHandle, animID, doneCallback);
},
@ -192,7 +193,7 @@ var POPAnimationMixin = {
*/
stopAnimations: function(refKey: string) {
invariant(this.refs[refKey], 'invalid ref');
this.stopNodeHandleAnimations(this.refs[refKey].getNodeHandle());
this.stopNodeHandleAnimations(React.findNodeHandle(this.refs[refKey]));
},
/**

View File

@ -15,7 +15,9 @@ var RCTPOPAnimationManager = require('NativeModules').POPAnimationManager;
if (!RCTPOPAnimationManager) {
// POP animation isn't available in the OSS fork - this is a temporary
// workaround to enable its availability to be determined at runtime.
module.exports = (null: ?Object);
// For Flow let's pretend like we always export POPAnimation
// so all our users don't need to do null checks
module.exports = ((null: any): typeof POPAnimation);
} else {
var ReactPropTypes = require('ReactPropTypes');

View File

@ -11,7 +11,7 @@
*/
'use strict';
var ReactIOSEventEmitter = require('ReactIOSEventEmitter');
var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
// Completely locally implemented - no native hooks.
module.exports = ReactIOSEventEmitter;
module.exports = ReactNativeEventEmitter;

View File

@ -92,6 +92,8 @@ var getPhotosReturnChecker = createStrictShapeTypeChecker({
});
class CameraRoll {
static GroupTypesOptions: Array<string>;
/**
* Saves the image with tag `tag` to the camera roll.
*

View File

@ -15,10 +15,10 @@ var EdgeInsetsPropType = require('EdgeInsetsPropType');
var NativeMethodsMixin = require('NativeMethodsMixin');
var Platform = require('Platform');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var View = require('View');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var deepDiffer = require('deepDiffer');
var insetsDiffer = require('insetsDiffer');
var merge = require('merge');
@ -163,9 +163,9 @@ var MapView = React.createClass({
});
if (Platform.OS === 'android') {
var RCTMap = createReactIOSNativeComponentClass({
var RCTMap = createReactNativeComponentClass({
validAttributes: merge(
ReactIOSViewAttributes.UIView, {
ReactNativeViewAttributes.UIView, {
showsUserLocation: true,
zoomEnabled: true,
rotateEnabled: true,

View File

@ -14,14 +14,14 @@
var EventEmitter = require('EventEmitter');
var Image = require('Image');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var RCTNavigatorManager = require('NativeModules').NavigatorManager;
var StyleSheet = require('StyleSheet');
var StaticContainer = require('StaticContainer.react');
var View = require('View');
var createReactIOSNativeComponentClass =
require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass =
require('createReactNativeComponentClass');
var invariant = require('invariant');
var logError = require('logError');
var merge = require('merge');
@ -35,14 +35,14 @@ function getuid() {
return __uid++;
}
var RCTNavigator = createReactIOSNativeComponentClass({
validAttributes: merge(ReactIOSViewAttributes.UIView, {
var RCTNavigator = createReactNativeComponentClass({
validAttributes: merge(ReactNativeViewAttributes.UIView, {
requestedTopOfStack: true
}),
uiViewClassName: 'RCTNavigator',
});
var RCTNavigatorItem = createReactIOSNativeComponentClass({
var RCTNavigatorItem = createReactNativeComponentClass({
validAttributes: {
// TODO: Remove or fix the attributes that are not fully functional.
// NavigatorIOS does not use them all, because some are problematic
@ -67,7 +67,7 @@ var RCTNavigatorItem = createReactIOSNativeComponentClass({
var NavigatorTransitionerIOS = React.createClass({
requestSchedulingNavigation: function(cb) {
RCTNavigatorManager.requestSchedulingJavaScriptNavigation(
(this: any).getNodeHandle(),
React.findNodeHandle(this),
logError,
cb
);

View File

@ -13,6 +13,7 @@
var NativeModules = require('NativeModules');
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var React = require('React');
var Subscribable = require('Subscribable');
var TextInputState = require('TextInputState');
@ -350,7 +351,7 @@ var ScrollResponderMixin = {
* can also be used to quickly scroll to any element we want to focus
*/
scrollResponderScrollTo: function(offsetX: number, offsetY: number) {
RCTUIManagerDeprecated.scrollTo(this.getNodeHandle(), offsetX, offsetY);
RCTUIManagerDeprecated.scrollTo(React.findNodeHandle(this), offsetX, offsetY);
},
/**
@ -358,7 +359,7 @@ var ScrollResponderMixin = {
* @param {object} rect Should have shape {x, y, width, height}
*/
scrollResponderZoomTo: function(rect: { x: number; y: number; width: number; height: number; }) {
RCTUIManagerDeprecated.zoomToRect(this.getNodeHandle(), rect);
RCTUIManagerDeprecated.zoomToRect(React.findNodeHandle(this), rect);
},
/**
@ -376,7 +377,7 @@ var ScrollResponderMixin = {
this.preventNegativeScrollOffset = !!preventNegativeScrollOffset;
RCTUIManager.measureLayout(
nodeHandle,
this.getNodeHandle(),
React.findNodeHandle(this),
this.scrollResponderTextInputFocusError,
this.scrollResponderInputMeasureAndScrollToKeyboard
);

View File

@ -17,7 +17,7 @@ var PointPropType = require('PointPropType');
var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
var RCTScrollViewConsts = RCTScrollView.Constants;
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var RCTUIManager = require('NativeModules').UIManager;
var ScrollResponder = require('ScrollResponder');
var StyleSheet = require('StyleSheet');
@ -25,7 +25,7 @@ var StyleSheetPropType = require('StyleSheetPropType');
var View = require('View');
var ViewStylePropTypes = require('ViewStylePropTypes');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var deepDiffer = require('deepDiffer');
var flattenStyle = require('flattenStyle');
var insetsDiffer = require('insetsDiffer');
@ -207,19 +207,19 @@ var ScrollView = React.createClass({
},
getInnerViewNode: function(): any {
return this.refs[INNERVIEW].getNodeHandle();
return React.findNodeHandle(this.refs[INNERVIEW]);
},
scrollTo: function(destY?: number, destX?: number) {
if (Platform.OS === 'android') {
RCTUIManager.dispatchViewManagerCommand(
this.getNodeHandle(),
React.findNodeHandle(this),
RCTUIManager.RCTScrollView.Commands.scrollTo,
[destX || 0, destY || 0]
);
} else {
RCTUIManager.scrollTo(
this.getNodeHandle(),
React.findNodeHandle(this),
destX || 0,
destY || 0
);
@ -228,7 +228,7 @@ var ScrollView = React.createClass({
scrollWithoutAnimationTo: function(destY?: number, destX?: number) {
RCTUIManager.scrollWithoutAnimationTo(
this.getNodeHandle(),
React.findNodeHandle(this),
destX || 0,
destY || 0
);
@ -343,7 +343,7 @@ var styles = StyleSheet.create({
});
var validAttributes = {
...ReactIOSViewAttributes.UIView,
...ReactNativeViewAttributes.UIView,
alwaysBounceHorizontal: true,
alwaysBounceVertical: true,
automaticallyAdjustContentInsets: true,
@ -370,11 +370,11 @@ var validAttributes = {
};
if (Platform.OS === 'android') {
var AndroidScrollView = createReactIOSNativeComponentClass({
var AndroidScrollView = createReactNativeComponentClass({
validAttributes: validAttributes,
uiViewClassName: 'RCTScrollView',
});
var AndroidHorizontalScrollView = createReactIOSNativeComponentClass({
var AndroidHorizontalScrollView = createReactNativeComponentClass({
validAttributes: validAttributes,
uiViewClassName: 'AndroidHorizontalScrollView',
});

View File

@ -19,14 +19,14 @@ var Platform = require('Platform');
var PropTypes = require('ReactPropTypes');
var React = require('React');
var ReactChildren = require('ReactChildren');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var Text = require('Text');
var TextInputState = require('TextInputState');
var TimerMixin = require('react-timer-mixin');
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var emptyFunction = require('emptyFunction');
var invariant = require('invariant');
var merge = require('merge');
@ -35,7 +35,7 @@ var autoCapitalizeConsts = RCTUIManager.UIText.AutocapitalizationType;
var keyboardTypeConsts = RCTUIManager.UIKeyboardType;
var returnKeyTypeConsts = RCTUIManager.UIReturnKeyType;
var RCTTextViewAttributes = merge(ReactIOSViewAttributes.UIView, {
var RCTTextViewAttributes = merge(ReactNativeViewAttributes.UIView, {
autoCorrect: true,
autoCapitalize: true,
clearTextOnFocus: true,
@ -305,7 +305,7 @@ var TextInput = React.createClass({
isFocused: function(): boolean {
return TextInputState.currentlyFocusedField() ===
this.refs.input.getNativeNode();
React.findNodeHandle(this.refs.input);
},
getDefaultProps: function(): DefaultProps {
@ -592,17 +592,17 @@ var styles = StyleSheet.create({
},
});
var RCTTextView = createReactIOSNativeComponentClass({
var RCTTextView = createReactNativeComponentClass({
validAttributes: RCTTextViewAttributes,
uiViewClassName: 'RCTTextView',
});
var RCTTextField = createReactIOSNativeComponentClass({
var RCTTextField = createReactNativeComponentClass({
validAttributes: RCTTextFieldAttributes,
uiViewClassName: 'RCTTextField',
});
var AndroidTextInput = createReactIOSNativeComponentClass({
var AndroidTextInput = createReactNativeComponentClass({
validAttributes: AndroidTextInputAttributes,
uiViewClassName: 'AndroidTextInput',
});

View File

@ -21,22 +21,22 @@ var TextInputState = {
/**
* Internal state
*/
_currentlyFocusedID: (null: ?string),
_currentlyFocusedID: (null: ?number),
/**
* Returns the ID of the currently focused text field, if one exists
* If no text field is focused it returns null
*/
currentlyFocusedField: function(): ?string {
currentlyFocusedField: function(): ?number {
return this._currentlyFocusedID;
},
/**
* @param {string} TextInputID id of the text field to focus
* @param {number} TextInputID id of the text field to focus
* Focuses the specified text field
* noop if the text field was already focused
*/
focusTextInput: function(textFieldID: string) {
focusTextInput: function(textFieldID: ?number) {
if (this._currentlyFocusedID !== textFieldID && textFieldID !== null) {
this._currentlyFocusedID = textFieldID;
RCTUIManager.focus(textFieldID);
@ -44,11 +44,11 @@ var TextInputState = {
},
/**
* @param {string} textFieldID id of the text field to focus
* @param {number} textFieldID id of the text field to focus
* Unfocuses the specified text field
* noop if it wasn't focused
*/
blurTextInput: function(textFieldID: string) {
blurTextInput: function(textFieldID: ?number) {
if (this._currentlyFocusedID === textFieldID && textFieldID !== null) {
this._currentlyFocusedID = null;
RCTUIManager.blur(textFieldID);

View File

@ -14,7 +14,7 @@
var NativeMethodsMixin = require('NativeMethodsMixin');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var TimerMixin = require('react-timer-mixin');
var Touchable = require('Touchable');
@ -120,7 +120,7 @@ var TouchableHighlight = React.createClass({
viewConfig: {
uiViewClassName: 'RCTView',
validAttributes: ReactIOSViewAttributes.RCTView
validAttributes: ReactNativeViewAttributes.RCTView
},
/**

View File

@ -15,12 +15,12 @@ var NativeMethodsMixin = require('NativeMethodsMixin');
var PropTypes = require('ReactPropTypes');
var RCTUIManager = require('NativeModules').UIManager;
var React = require('React');
var ReactIOSStyleAttributes = require('ReactIOSStyleAttributes');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheetPropType = require('StyleSheetPropType');
var ViewStylePropTypes = require('ViewStylePropTypes');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var stylePropType = StyleSheetPropType(ViewStylePropTypes);
@ -53,7 +53,7 @@ var View = React.createClass({
*/
viewConfig: {
uiViewClassName: 'RCTView',
validAttributes: ReactIOSViewAttributes.RCTView
validAttributes: ReactNativeViewAttributes.RCTView
},
propTypes: {
@ -163,8 +163,8 @@ var View = React.createClass({
},
});
var RCTView = createReactIOSNativeComponentClass({
validAttributes: ReactIOSViewAttributes.RCTView,
var RCTView = createReactNativeComponentClass({
validAttributes: ReactNativeViewAttributes.RCTView,
uiViewClassName: 'RCTView',
});
RCTView.propTypes = View.propTypes;
@ -172,7 +172,7 @@ if (__DEV__) {
var viewConfig = RCTUIManager.viewConfigs && RCTUIManager.viewConfigs.RCTView || {};
for (var prop in viewConfig.nativeProps) {
var viewAny: any = View; // Appease flow
if (!viewAny.propTypes[prop] && !ReactIOSStyleAttributes[prop]) {
if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) {
throw new Error(
'View is missing propType for native prop `' + prop + '`'
);

View File

@ -28,6 +28,10 @@ var ViewStylePropTypes = {
borderBottomColor: ReactPropTypes.string,
borderLeftColor: ReactPropTypes.string,
borderRadius: ReactPropTypes.number,
borderTopLeftRadius: ReactPropTypes.number,
borderTopRightRadius: ReactPropTypes.number,
borderBottomLeftRadius: ReactPropTypes.number,
borderBottomRightRadius: ReactPropTypes.number,
opacity: ReactPropTypes.number,
overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
shadowColor: ReactPropTypes.string,

View File

@ -12,11 +12,11 @@
var EdgeInsetsPropType = require('EdgeInsetsPropType');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var View = require('View');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var keyMirror = require('keyMirror');
var merge = require('merge');
@ -143,7 +143,7 @@ var WebView = React.createClass({
},
getWebWiewHandle: function() {
return this.refs[RCT_WEBVIEW_REF].getNodeHandle();
return React.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
},
onLoadingStart: function(event) {
@ -168,8 +168,8 @@ var WebView = React.createClass({
},
});
var RCTWebView = createReactIOSNativeComponentClass({
validAttributes: merge(ReactIOSViewAttributes.UIView, {
var RCTWebView = createReactNativeComponentClass({
validAttributes: merge(ReactNativeViewAttributes.UIView, {
url: true,
javaScriptEnabledAndroid: true,
}),

View File

@ -14,7 +14,7 @@
var ActivityIndicatorIOS = require('ActivityIndicatorIOS');
var EdgeInsetsPropType = require('EdgeInsetsPropType');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var Text = require('Text');
var View = require('View');
@ -189,7 +189,7 @@ var WebView = React.createClass({
},
getWebWiewHandle: function(): any {
return this.refs[RCT_WEBVIEW_REF].getNodeHandle();
return React.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
},
onLoadingStart: function(event: Event) {

View File

@ -346,12 +346,12 @@ var ListView = React.createClass({
_measureAndUpdateScrollProps: function() {
RCTUIManager.measureLayout(
this.refs[SCROLLVIEW_REF].getInnerViewNode(),
this.refs[SCROLLVIEW_REF].getNodeHandle(),
React.findNodeHandle(this.refs[SCROLLVIEW_REF]),
logError,
this._setScrollContentHeight
);
RCTUIManager.measureLayoutRelativeToParent(
this.refs[SCROLLVIEW_REF].getNodeHandle(),
React.findNodeHandle(this.refs[SCROLLVIEW_REF]),
logError,
this._setScrollVisibleHeight
);

View File

@ -253,7 +253,7 @@ var Navigator = React.createClass({
onDidFocus: PropTypes.func,
/**
* Will be called with (ref, indexInStack) when the scene ref changes
* Will be called with (ref, indexInStack, route) when the scene ref changes
*/
onItemRef: PropTypes.func,
@ -582,7 +582,7 @@ var Navigator = React.createClass({
* This happens at the end of a transition started by transitionTo, and when the spring catches up to a pending gesture
*/
_completeTransition: function() {
if (this.spring.getCurrentValue() !== 1) {
if (this.spring.getCurrentValue() !== 1 && this.spring.getCurrentValue() !== 0) {
// The spring has finished catching up to a gesture in progress. Remove the pending progress
// and we will be in a normal activeGesture state
if (this.state.pendingGestureProgress) {
@ -659,11 +659,17 @@ var Navigator = React.createClass({
},
/**
* Hides scenes that we are not currently on or transitioning from
* Hides all scenes that we are not currently on, gesturing to, or transitioning from
*/
_hideScenes: function() {
var gesturingToIndex = null;
if (this.state.activeGesture) {
gesturingToIndex = this.state.presentedIndex + this._deltaForGestureAction(this.state.activeGesture);
}
for (var i = 0; i < this.state.routeStack.length; i++) {
if (i === this.state.presentedIndex || i === this.state.transitionFromIndex) {
if (i === this.state.presentedIndex ||
i === this.state.transitionFromIndex ||
i === gesturingToIndex) {
continue;
}
this._disableScene(i);
@ -734,10 +740,14 @@ var Navigator = React.createClass({
viewAtIndex.setNativeProps({renderToHardwareTextureAndroid: shouldRenderToHardwareTexture});
},
_handleTouchStart: function() {
this._eligibleGestures = GESTURE_ACTIONS;
},
_handleMoveShouldSetPanResponder: function(e, gestureState) {
var currentRoute = this.state.routeStack[this.state.presentedIndex];
var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
this._expectingGestureGrant = this._matchGestureAction(sceneConfig.gestures, gestureState);
this._expectingGestureGrant = this._matchGestureAction(this._eligibleGestures, sceneConfig.gestures, gestureState);
return !! this._expectingGestureGrant;
},
@ -855,7 +865,7 @@ var Navigator = React.createClass({
var gesture = sceneConfig.gestures[this.state.activeGesture];
return this._moveAttachedGesture(gesture, gestureState);
}
var matchedGesture = this._matchGestureAction(sceneConfig.gestures, gestureState);
var matchedGesture = this._matchGestureAction(GESTURE_ACTIONS, sceneConfig.gestures, gestureState);
if (matchedGesture) {
this._attachGesture(matchedGesture);
}
@ -870,9 +880,14 @@ var Navigator = React.createClass({
var nextProgress = (distance - gestureDetectMovement) /
(gesture.fullDistance - gestureDetectMovement);
if (nextProgress < 0 && gesture.isDetachable) {
var gesturingToIndex = this.state.presentedIndex + this._deltaForGestureAction(this.state.activeGesture);
this._transitionBetween(this.state.presentedIndex, gesturingToIndex, 0);
this._detachGesture();
if (this.state.pendingGestureProgress != null) {
this.spring.setCurrentValue(0);
}
return;
}
if (this._doesGestureOverswipe(this.state.activeGesture)) {
var frictionConstant = gesture.overswipe.frictionConstant;
var frictionByDistance = gesture.overswipe.frictionByDistance;
@ -889,12 +904,12 @@ var Navigator = React.createClass({
}
},
_matchGestureAction: function(gestures, gestureState) {
_matchGestureAction: function(eligibleGestures, gestures, gestureState) {
if (!gestures) {
return null;
}
var matchedGesture = null;
GESTURE_ACTIONS.some((gestureName) => {
eligibleGestures.some((gestureName, gestureIndex) => {
var gesture = gestures[gestureName];
if (!gesture) {
return;
@ -920,12 +935,19 @@ var Navigator = React.createClass({
}
var moveStartedInRegion = gesture.edgeHitWidth == null ||
currentLoc < edgeHitWidth;
var moveTravelledFarEnough =
travelDist >= gesture.gestureDetectMovement &&
travelDist > oppositeAxisTravelDist * gesture.directionRatio;
if (moveStartedInRegion && moveTravelledFarEnough) {
if (!moveStartedInRegion) {
return false;
}
var moveTravelledFarEnough = travelDist >= gesture.gestureDetectMovement;
if (!moveTravelledFarEnough) {
return false;
}
var directionIsCorrect = Math.abs(travelDist) > Math.abs(oppositeAxisTravelDist) * gesture.directionRatio;
if (directionIsCorrect) {
matchedGesture = gestureName;
return true;
} else {
this._eligibleGestures = this._eligibleGestures.slice().splice(gestureIndex, 1);
}
});
return matchedGesture;
@ -1159,13 +1181,13 @@ var Navigator = React.createClass({
return this.state.routeStack;
},
_handleItemRef: function(itemId, ref) {
_handleItemRef: function(itemId, route, ref) {
this._itemRefs[itemId] = ref;
var itemIndex = this.state.idStack.indexOf(itemId);
if (itemIndex === -1) {
return;
}
this.props.onItemRef && this.props.onItemRef(ref, itemIndex);
this.props.onItemRef && this.props.onItemRef(ref, itemIndex, route);
},
_cleanScenesPastIndex: function(index) {
@ -1202,6 +1224,7 @@ var Navigator = React.createClass({
<View
style={styles.transitioner}
{...this.panGesture.panHandlers}
onTouchStart={this._handleTouchStart}
onResponderTerminationRequest={
this._handleResponderTerminationRequest
}>
@ -1273,7 +1296,7 @@ var Navigator = React.createClass({
}}
style={[styles.baseScene, this.props.sceneStyle, disabledSceneStyle]}>
{React.cloneElement(child, {
ref: this._handleItemRef.bind(null, this.state.idStack[i]),
ref: this._handleItemRef.bind(null, this.state.idStack[i], route),
})}
</View>
);

View File

@ -101,6 +101,18 @@ var FadeToTheLeft = {
},
};
var FadeToTheRight = {
...FadeToTheLeft,
transformTranslate: {
from: {x: 0, y: 0, z: 0},
to: {x: Math.round(SCREEN_WIDTH * 0.3), y: 0, z: 0},
},
translateX: {
from: 0,
to: Math.round(SCREEN_WIDTH * 0.3),
}
};
var FadeIn = {
opacity: {
from: 0,
@ -187,6 +199,27 @@ var FromTheRight = {
},
};
var FromTheLeft = {
...FromTheRight,
transformTranslate: {
from: {x: -SCREEN_WIDTH, y: 0, z: 0},
to: {x: 0, y: 0, z: 0},
min: 0,
max: 1,
type: 'linear',
extrapolate: true,
round: PixelRatio.get(),
},
translateX: {
from: -SCREEN_WIDTH,
to: 0,
min: 0,
max: 1,
type: 'linear',
extrapolate: true,
round: PixelRatio.get(),
},
};
var ToTheBack = {
// Rotate *requires* you to break out each individual component of
@ -374,6 +407,13 @@ var NavigatorSceneConfigs = {
...BaseConfig,
// We will want to customize this soon
},
FloatFromLeft: {
...BaseConfig,
animationInterpolators: {
into: buildStyleInterpolator(FromTheLeft),
out: buildStyleInterpolator(FadeToTheRight),
},
},
FloatFromBottom: {
...BaseConfig,
gestures: {

View File

@ -18,7 +18,7 @@ var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModules = require('NativeModules');
var PropTypes = require('ReactPropTypes');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var StyleSheetPropType = require('StyleSheetPropType');
@ -113,7 +113,7 @@ var Image = React.createClass({
*/
viewConfig: {
uiViewClassName: 'UIView',
validAttributes: ReactIOSViewAttributes.UIView
validAttributes: ReactNativeViewAttributes.UIView
},
render: function() {

View File

@ -15,6 +15,12 @@
@interface RCTImageLoader : NSObject
+ (ALAssetsLibrary *)assetsLibrary;
+ (void)loadImageWithTag:(NSString *)tag callback:(void (^)(NSError *error, UIImage *image))callback;
/**
* Can be called from any thread.
* Will always call callback on main thread.
*/
+ (void)loadImageWithTag:(NSString *)tag
callback:(void (^)(NSError *error, id /* UIImage or CAAnimation */ image))callback;
@end

View File

@ -16,6 +16,7 @@
#import <UIKit/UIKit.h>
#import "RCTConvert.h"
#import "RCTGIFImage.h"
#import "RCTImageDownloader.h"
#import "RCTLog.h"
@ -32,13 +33,24 @@ static dispatch_queue_t RCTImageLoaderQueue(void)
return queue;
}
NSError *errorWithMessage(NSString *message)
static NSError *RCTErrorWithMessage(NSString *message)
{
NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: message};
NSError *error = [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
return error;
}
static void RCTDispatchCallbackOnMainQueue(void (^callback)(NSError *, id), NSError *error, UIImage *image)
{
if ([NSThread isMainThread]) {
callback(error, image);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
callback(error, image);
});
}
}
@implementation RCTImageLoader
+ (ALAssetsLibrary *)assetsLibrary
@ -51,7 +63,11 @@ NSError *errorWithMessage(NSString *message)
return assetsLibrary;
}
+ (void)loadImageWithTag:(NSString *)imageTag callback:(void (^)(NSError *error, UIImage *image))callback
/**
* Can be called from any thread.
* Will always call callback on main thread.
*/
+ (void)loadImageWithTag:(NSString *)imageTag callback:(void (^)(NSError *error, id image))callback
{
if ([imageTag hasPrefix:@"assets-library"]) {
[[RCTImageLoader assetsLibrary] assetForURL:[NSURL URLWithString:imageTag] resultBlock:^(ALAsset *asset) {
@ -67,18 +83,18 @@ NSError *errorWithMessage(NSString *message)
ALAssetRepresentation *representation = [asset defaultRepresentation];
ALAssetOrientation orientation = [representation orientation];
UIImage *image = [UIImage imageWithCGImage:[representation fullResolutionImage] scale:1.0f orientation:(UIImageOrientation)orientation];
callback(nil, image);
RCTDispatchCallbackOnMainQueue(callback, nil, image);
}
});
} else {
NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@ with no error message.", imageTag];
NSError *error = errorWithMessage(errorText);
callback(error, nil);
NSError *error = RCTErrorWithMessage(errorText);
RCTDispatchCallbackOnMainQueue(callback, error, nil);
}
} failureBlock:^(NSError *loadError) {
NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@.\niOS Error: %@", imageTag, loadError];
NSError *error = errorWithMessage(errorText);
callback(error, nil);
NSError *error = RCTErrorWithMessage(errorText);
RCTDispatchCallbackOnMainQueue(callback, error, nil);
}];
} else if ([imageTag hasPrefix:@"ph://"]) {
// Using PhotoKit for iOS 8+
@ -89,19 +105,19 @@ NSError *errorWithMessage(NSString *message)
PHFetchResult *results = [PHAsset fetchAssetsWithLocalIdentifiers:@[phAssetID] options:nil];
if (results.count == 0) {
NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", phAssetID];
NSError *error = errorWithMessage(errorText);
callback(error, nil);
NSError *error = RCTErrorWithMessage(errorText);
RCTDispatchCallbackOnMainQueue(callback, error, nil);
return;
}
PHAsset *asset = [results firstObject];
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage *result, NSDictionary *info) {
if (result) {
callback(nil, result);
RCTDispatchCallbackOnMainQueue(callback, nil, result);
} else {
NSString *errorText = [NSString stringWithFormat:@"Failed to load PHAsset with local identifier %@ with no error message.", phAssetID];
NSError *error = errorWithMessage(errorText);
callback(error, nil);
NSError *error = RCTErrorWithMessage(errorText);
RCTDispatchCallbackOnMainQueue(callback, error, nil);
return;
}
}];
@ -109,20 +125,34 @@ NSError *errorWithMessage(NSString *message)
NSURL *url = [NSURL URLWithString:imageTag];
if (!url) {
NSString *errorMessage = [NSString stringWithFormat:@"Invalid URL: %@", imageTag];
callback(errorWithMessage(errorMessage), nil);
RCTDispatchCallbackOnMainQueue(callback, RCTErrorWithMessage(errorMessage), nil);
return;
}
[[RCTImageDownloader sharedInstance] downloadDataForURL:url block:^(NSData *data, NSError *error) {
if (error) {
callback(error, nil);
RCTDispatchCallbackOnMainQueue(callback, error, nil);
} else {
callback(nil, [UIImage imageWithData:data]);
RCTDispatchCallbackOnMainQueue(callback, nil, [UIImage imageWithData:data]);
}
}];
} else if ([[imageTag lowercaseString] hasSuffix:@".gif"]) {
id image = RCTGIFImageWithFileURL([RCTConvert NSURL:imageTag]);
if (image) {
RCTDispatchCallbackOnMainQueue(callback, nil, image);
} else {
NSString *errorMessage = [NSString stringWithFormat:@"Unable to load GIF image: %@", imageTag];
NSError *error = RCTErrorWithMessage(errorMessage);
RCTDispatchCallbackOnMainQueue(callback, error, nil);
}
} else {
UIImage *image = [RCTConvert UIImage:imageTag];
if (image) {
RCTDispatchCallbackOnMainQueue(callback, nil, image);
} else {
NSString *errorMessage = [NSString stringWithFormat:@"Unrecognized tag protocol: %@", imageTag];
NSError *error = errorWithMessage(errorMessage);
callback(error, nil);
NSError *error = RCTErrorWithMessage(errorMessage);
RCTDispatchCallbackOnMainQueue(callback, error, nil);
}
}
}

View File

@ -33,9 +33,11 @@ RCT_CUSTOM_VIEW_PROPERTY(src, NSURL, RCTStaticImage)
if ([[[json description] pathExtension] caseInsensitiveCompare:@"gif"] == NSOrderedSame) {
[view.layer addAnimation:RCTGIFImageWithFileURL([RCTConvert NSURL:json]) forKey:@"contents"];
} else {
[view.layer removeAnimationForKey:@"contents"];
view.image = [RCTConvert UIImage:json];
}
} else {
[view.layer removeAnimationForKey:@"contents"];
view.image = defaultView.image;
}
}
@ -52,13 +54,19 @@ RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTStaticImage)
RCT_CUSTOM_VIEW_PROPERTY(imageTag, NSString, RCTStaticImage)
{
if (json) {
[RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] callback:^(NSError *error, UIImage *image) {
[RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] callback:^(NSError *error, id image) {
if (error) {
RCTLogWarn(@"%@", error.localizedDescription);
}
if ([image isKindOfClass:[CAAnimation class]]) {
[view.layer addAnimation:image forKey:@"contents"];
} else {
[view.layer removeAnimationForKey:@"contents"];
view.image = image;
}
}];
} else {
[view.layer removeAnimationForKey:@"contents"];
view.image = defaultView.image;
}
}

View File

@ -12,9 +12,10 @@ jest
.dontMock('AssetRegistry')
.dontMock('../resolveAssetSource');
var resolveAssetSource;
var SourceCode;
var AssetRegistry;
var Platform;
var SourceCode;
var resolveAssetSource;
function expectResolvesAsset(input, expectedSource) {
var assetId = AssetRegistry.registerAsset(input);
@ -24,8 +25,9 @@ function expectResolvesAsset(input, expectedSource) {
describe('resolveAssetSource', () => {
beforeEach(() => {
jest.resetModuleRegistry();
SourceCode = require('NativeModules').SourceCode;
AssetRegistry = require('AssetRegistry');
Platform = require('Platform');
SourceCode = require('NativeModules').SourceCode;
resolveAssetSource = require('../resolveAssetSource');
});
@ -59,7 +61,7 @@ describe('resolveAssetSource', () => {
expect(resolveAssetSource('nonsense')).toBe(null);
});
describe('bundle was loaded from network', () => {
describe('bundle was loaded from network (DEV)', () => {
beforeEach(() => {
SourceCode.scriptURL = 'http://10.0.0.1:8081/main.bundle';
});
@ -104,9 +106,21 @@ describe('resolveAssetSource', () => {
});
describe('bundle was loaded from file', () => {
describe('bundle was loaded from file (PROD) on iOS', () => {
var originalDevMode;
var originalPlatform;
beforeEach(() => {
SourceCode.scriptURL = 'file:///Path/To/Simulator/main.bundle';
originalDevMode = __DEV__;
originalPlatform = Platform.OS;
__DEV__ = false;
Platform.OS = 'ios';
});
afterEach(() => {
__DEV__ = originalDevMode;
Platform.OS = originalPlatform;
});
it('uses pre-packed image', () => {
@ -129,6 +143,43 @@ describe('resolveAssetSource', () => {
});
});
describe('bundle was loaded from file (PROD) on Android', () => {
var originalDevMode;
var originalPlatform;
beforeEach(() => {
SourceCode.scriptURL = 'file:///Path/To/Simulator/main.bundle';
originalDevMode = __DEV__;
originalPlatform = Platform.OS;
__DEV__ = false;
Platform.OS = 'android';
});
afterEach(() => {
__DEV__ = originalDevMode;
Platform.OS = originalPlatform;
});
it('uses pre-packed image', () => {
expectResolvesAsset({
__packager_asset: true,
fileSystemLocation: '/root/app/module/a',
httpServerLocation: '/assets/AwesomeModule/Subdir',
width: 100,
height: 200,
scales: [1],
hash: '5b6f00f',
name: '!@Logo#1_€', // Invalid chars shouldn't get passed to native
type: 'png',
}, {
isStatic: true,
width: 100,
height: 200,
uri: 'assets_awesomemodule_subdir_logo1_',
});
});
});
});
describe('resolveAssetSource.pickScale', () => {

View File

@ -7,22 +7,31 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule resolveAssetSource
*
* Resolves an asset into a `source` for `Image`.
*/
'use strict';
var AssetRegistry = require('AssetRegistry');
var PixelRatio = require('PixelRatio');
var Platform = require('Platform');
var SourceCode = require('NativeModules').SourceCode;
var _serverURL;
function getServerURL() {
function getDevServerURL() {
if (!__DEV__) {
// In prod we want assets to be loaded from the archive
return null;
}
if (_serverURL === undefined) {
var scriptURL = SourceCode.scriptURL;
var match = scriptURL && scriptURL.match(/^https?:\/\/.*?\//);
if (match) {
// Bundle was loaded from network
_serverURL = match[0];
} else {
// Bundle was loaded from file
_serverURL = null;
}
}
@ -30,6 +39,55 @@ function getServerURL() {
return _serverURL;
}
/**
* Returns the path at which the asset can be found in the archive
*/
function getPathInArchive(asset) {
if (Platform.OS === 'android') {
var assetDir = getBasePath(asset);
// E.g. 'assets_awesomemodule_icon'
// The Android resource system picks the correct scale.
return (assetDir + '/' + asset.name)
.toLowerCase()
.replace(/\//g, '_') // Encode folder structure in file name
.replace(/([^a-z0-9_])/g, ''); // Remove illegal chars
} else {
// E.g. 'assets/AwesomeModule/icon@2x.png'
return getScaledAssetPath(asset);
}
}
/**
* Returns an absolute URL which can be used to fetch the asset
* from the devserver
*/
function getPathOnDevserver(devServerUrl, asset) {
return devServerUrl + getScaledAssetPath(asset) + '?hash=' + asset.hash;
}
/**
* Returns a path like 'assets/AwesomeModule'
*/
function getBasePath(asset) {
// TODO(frantic): currently httpServerLocation is used both as
// path in http URL and path within IPA. Should we have zipArchiveLocation?
var path = asset.httpServerLocation;
if (path[0] === '/') {
path = path.substr(1);
}
return path;
}
/**
* Returns a path like 'assets/AwesomeModule/icon@2x.png'
*/
function getScaledAssetPath(asset) {
var scale = pickScale(asset.scales, PixelRatio.get());
var scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
var assetDir = getBasePath(asset);
return assetDir + '/' + asset.name + scaleSuffix + '.' + asset.type;
}
function pickScale(scales, deviceScale) {
// Packager guarantees that `scales` array is sorted
for (var i = 0; i < scales.length; i++) {
@ -58,31 +116,19 @@ function resolveAssetSource(source) {
}
function assetToImageSource(asset) {
// TODO(frantic): currently httpServerLocation is used both as
// path in http URL and path within IPA. Should we have zipArchiveLocation?
var path = asset.httpServerLocation;
if (path[0] === '/') {
path = path.substr(1);
}
var scale = pickScale(asset.scales, PixelRatio.get());
var scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
var fileName = asset.name + scaleSuffix + '.' + asset.type;
var serverURL = getServerURL();
if (serverURL) {
var devServerURL = getDevServerURL();
if (devServerURL) {
return {
width: asset.width,
height: asset.height,
uri: serverURL + path + '/' + fileName +
'?hash=' + asset.hash,
uri: getPathOnDevserver(devServerURL, asset),
isStatic: false,
};
} else {
return {
width: asset.width,
height: asset.height,
uri: path + '/' + fileName,
uri: getPathInArchive(asset),
isStatic: true,
};
}

View File

@ -25,12 +25,23 @@ type Exception = {
message: string;
}
function reportException(e: Exception, stack?: any) {
function reportException(e: Exception, isFatal: bool, stack?: any) {
if (RCTExceptionsManager) {
if (!stack) {
stack = parseErrorStack(e);
}
if (!RCTExceptionsManager.reportFatalException ||
!RCTExceptionsManager.reportSoftException) {
// Backwards compatibility - no differentiation
// TODO(#7049989): deprecate reportUnhandledException on Android
RCTExceptionsManager.reportUnhandledException(e.message, stack);
} else {
if (isFatal) {
RCTExceptionsManager.reportFatalException(e.message, stack);
} else {
RCTExceptionsManager.reportSoftException(e.message, stack);
}
}
if (__DEV__) {
(sourceMapPromise = sourceMapPromise || loadSourceMap())
.then(map => {
@ -44,7 +55,7 @@ function reportException(e: Exception, stack?: any) {
}
}
function handleException(e: Exception) {
function handleException(e: Exception, isFatal: boolean) {
var stack = parseErrorStack(e);
var msg =
'Error: ' + e.message +
@ -57,7 +68,7 @@ function handleException(e: Exception) {
} else {
console.error(msg);
}
reportException(e, stack);
reportException(e, isFatal, stack);
}
/**
@ -78,7 +89,7 @@ function installConsoleErrorReporter() {
var str = Array.prototype.map.call(arguments, stringifySafe).join(', ');
var error: any = new Error('console.error: ' + str);
error.framesToPop = 1;
reportException(error);
reportException(error, /* isFatal */ false);
};
if (console.reportErrorsAsExceptions === undefined) {
console.reportErrorsAsExceptions = true; // Individual apps can disable this

View File

@ -66,9 +66,9 @@ function setupDocumentShim() {
GLOBAL.MutationObserver = undefined;
}
function handleErrorWithRedBox(e) {
function handleErrorWithRedBox(e, isFatal) {
try {
require('ExceptionsManager').handleException(e);
require('ExceptionsManager').handleException(e, isFatal);
} catch(ee) {
console.log('Failed to print error: ', ee.message);
}

View File

@ -15,13 +15,13 @@
var NativeMethodsMixin = require('NativeMethodsMixin');
var React = require('React');
var ReactChildren = require('ReactChildren');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var RCTPickerIOSConsts = require('NativeModules').UIManager.RCTPicker.Constants;
var StyleSheet = require('StyleSheet');
var View = require('View');
var createReactIOSNativeComponentClass =
require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass =
require('createReactNativeComponentClass');
var merge = require('merge');
var PICKER = 'picker';
@ -112,12 +112,12 @@ var styles = StyleSheet.create({
},
});
var rkPickerIOSAttributes = merge(ReactIOSViewAttributes.UIView, {
var rkPickerIOSAttributes = merge(ReactNativeViewAttributes.UIView, {
items: true,
selectedIndex: true,
});
var RCTPickerIOS = createReactIOSNativeComponentClass({
var RCTPickerIOS = createReactNativeComponentClass({
validAttributes: rkPickerIOSAttributes,
uiViewClassName: 'RCTPicker',
});

View File

@ -11,7 +11,7 @@
*/
'use strict';
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var RCTUIManager = require('NativeModules').UIManager;
type OnSuccessCallback = (
@ -52,7 +52,7 @@ var queryLayoutByID = function(
): void {
// Native bridge doesn't *yet* surface errors.
RCTUIManager.measure(
ReactIOSTagHandles.rootNodeIDToTag[rootNodeID],
ReactNativeTagHandles.rootNodeIDToTag[rootNodeID],
onSuccess
);
};

View File

@ -16,6 +16,7 @@ var RCTPOPAnimationManager = NativeModules.POPAnimationManager;
var RCTUIManager = NativeModules.UIManager;
var TextInputState = require('TextInputState');
var findNodeHandle = require('findNodeHandle');
var flattenStyle = require('flattenStyle');
var invariant = require('invariant');
var mergeFast = require('mergeFast');
@ -51,16 +52,16 @@ var animationIDInvariant = function(
var NativeMethodsMixin = {
addAnimation: function(anim: number, callback?: (finished: bool) => void) {
animationIDInvariant('addAnimation', anim);
RCTPOPAnimationManager.addAnimation(this.getNodeHandle(), anim, callback);
RCTPOPAnimationManager.addAnimation(findNodeHandle(this), anim, callback);
},
removeAnimation: function(anim: number) {
animationIDInvariant('removeAnimation', anim);
RCTPOPAnimationManager.removeAnimation(this.getNodeHandle(), anim);
RCTPOPAnimationManager.removeAnimation(findNodeHandle(this), anim);
},
measure: function(callback: MeasureOnSuccessCallback) {
RCTUIManager.measure(this.getNodeHandle(), callback);
RCTUIManager.measure(findNodeHandle(this), callback);
},
measureLayout: function(
@ -69,7 +70,7 @@ var NativeMethodsMixin = {
onFail: () => void /* currently unused */
) {
RCTUIManager.measureLayout(
this.getNodeHandle(),
findNodeHandle(this),
relativeToNativeNode,
onFail,
onSuccess
@ -106,18 +107,18 @@ var NativeMethodsMixin = {
}
RCTUIManager.updateView(
this.getNodeHandle(),
findNodeHandle(this),
this.viewConfig.uiViewClassName,
props
);
},
focus: function() {
TextInputState.focusTextInput(this.getNodeHandle());
TextInputState.focusTextInput(findNodeHandle(this));
},
blur: function() {
TextInputState.blurTextInput(this.getNodeHandle());
TextInputState.blurTextInput(findNodeHandle(this));
}
};

View File

@ -1,79 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSComponentMixin
* @flow
*/
'use strict';
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactInstanceMap = require('ReactInstanceMap');
/**
* ReactNative vs ReactWeb
* -----------------------
* React treats some pieces of data opaquely. This means that the information
* is first class (it can be passed around), but cannot be inspected. This
* allows us to build infrastructure that reasons about resources, without
* making assumptions about the nature of those resources, and this allows that
* infra to be shared across multiple platforms, where the resources are very
* different. General infra (such as `ReactMultiChild`) reasons opaquely about
* the data, but platform specific code (such as `ReactIOSNativeComponent`) can
* make assumptions about the data.
*
*
* `rootNodeID`, uniquely identifies a position in the generated native view
* tree. Many layers of composite components (created with `React.createClass`)
* can all share the same `rootNodeID`.
*
* `nodeHandle`: A sufficiently unambiguous way to refer to a lower level
* resource (dom node, native view etc). The `rootNodeID` is sufficient for web
* `nodeHandle`s, because the position in a tree is always enough to uniquely
* identify a DOM node (we never have nodes in some bank outside of the
* document). The same would be true for `ReactNative`, but we must maintain a
* mapping that we can send efficiently serializable
* strings across native boundaries.
*
* Opaque name TodaysWebReact FutureWebWorkerReact ReactNative
* ----------------------------------------------------------------------------
* nodeHandle N/A rootNodeID tag
*
*
* `mountImage`: A way to represent the potential to create lower level
* resources whos `nodeHandle` can be discovered immediately by knowing the
* `rootNodeID`. Today's web React represents this with `innerHTML` annotated
* with DOM ids that match the `rootNodeID`.
*
* Opaque name TodaysWebReact FutureWebWorkerReact ReactNative
* ----------------------------------------------------------------------------
* mountImage innerHTML innerHTML {rootNodeID, tag}
*
*/
var ReactIOSComponentMixin = {
/**
* This has no particular meaning in ReactIOS. If this were in the DOM, this
* would return the DOM node. There should be nothing that invokes this
* method. Any current callers of this are mistaken - they should be invoking
* `getNodeHandle`.
*/
getNativeNode: function() {
// TODO (balpert): Wrap iOS native components in a composite wrapper, then
// ReactInstanceMap.get here will always succeed
return ReactIOSTagHandles.rootNodeIDToTag[
(ReactInstanceMap.get(this) || this)._rootNodeID
];
},
getNodeHandle: function() {
return ReactIOSTagHandles.rootNodeIDToTag[
(ReactInstanceMap.get(this) || this)._rootNodeID
];
}
};
module.exports = ReactIOSComponentMixin;

View File

@ -14,7 +14,7 @@
var RCTUIManager = require('NativeModules').UIManager;
var UnimplementedView = require('UnimplementedView');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var deepDiffer = require('deepDiffer');
var insetsDiffer = require('insetsDiffer');
var pointsDiffer = require('pointsDiffer');
@ -59,7 +59,7 @@ function requireNativeComponent(
if (__DEV__) {
wrapperComponent && verifyPropTypes(wrapperComponent, viewConfig);
}
return createReactIOSNativeComponentClass(viewConfig);
return createReactNativeComponentClass(viewConfig);
}
var TypeToDifferMap = {

View File

@ -11,7 +11,7 @@
*/
'use strict';
var ReactIOSStyleAttributes = require('ReactIOSStyleAttributes');
var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
var View = require('View');
function verifyPropTypes(
@ -26,7 +26,7 @@ function verifyPropTypes(
for (var prop in nativeProps) {
if (!component.propTypes[prop] &&
!View.propTypes[prop] &&
!ReactIOSStyleAttributes[prop] &&
!ReactNativeStyleAttributes[prop] &&
(!nativePropsToIgnore || !nativePropsToIgnore[prop])) {
throw new Error(
'`' + component.displayName + '` has no propType for native prop `' +

View File

@ -12,4 +12,4 @@
"use strict";
module.exports = require('ReactIOS');
module.exports = require('ReactNative');

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOS
* @providesModule ReactNative
* @flow
*/
"use strict";
@ -19,15 +19,16 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
var ReactElement = require('ReactElement');
var ReactElementValidator = require('ReactElementValidator');
var ReactInstanceHandles = require('ReactInstanceHandles');
var ReactIOSDefaultInjection = require('ReactIOSDefaultInjection');
var ReactIOSMount = require('ReactIOSMount');
var ReactNativeDefaultInjection = require('ReactNativeDefaultInjection');
var ReactNativeMount = require('ReactNativeMount');
var ReactPropTypes = require('ReactPropTypes');
var deprecated = require('deprecated');
var findNodeHandle = require('findNodeHandle');
var invariant = require('invariant');
var onlyChild = require('onlyChild');
ReactIOSDefaultInjection.inject();
ReactNativeDefaultInjection.inject();
var createElement = ReactElement.createElement;
var createFactory = ReactElement.createFactory;
@ -72,11 +73,11 @@ var render = function(
mountInto: number,
callback?: ?(() => void)
): ?ReactComponent {
return ReactIOSMount.renderComponent(element, mountInto, callback);
return ReactNativeMount.renderComponent(element, mountInto, callback);
};
var ReactIOS = {
hasReactIOSInitialized: false,
var ReactNative = {
hasReactNativeInitialized: false,
Children: {
map: ReactChildren.map,
forEach: ReactChildren.forEach,
@ -90,13 +91,14 @@ var ReactIOS = {
createFactory: createFactory,
cloneElement: cloneElement,
_augmentElement: augmentElement,
findNodeHandle: findNodeHandle,
render: render,
unmountComponentAtNode: ReactIOSMount.unmountComponentAtNode,
unmountComponentAtNode: ReactNativeMount.unmountComponentAtNode,
// Hook for JSX spread, don't use this for anything else.
__spread: Object.assign,
unmountComponentAtNodeAndRemoveContainer: ReactIOSMount.unmountComponentAtNodeAndRemoveContainer,
unmountComponentAtNodeAndRemoveContainer: ReactNativeMount.unmountComponentAtNodeAndRemoveContainer,
isValidClass: ReactElement.isValidFactory,
isValidElement: ReactElement.isValidElement,
@ -126,10 +128,10 @@ if (
__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
CurrentOwner: ReactCurrentOwner,
InstanceHandles: ReactInstanceHandles,
Mount: ReactIOSMount,
Mount: ReactNativeMount,
Reconciler: require('ReactReconciler'),
TextComponent: require('ReactIOSTextComponent'),
TextComponent: require('ReactNativeTextComponent'),
});
}
module.exports = ReactIOS;
module.exports = ReactNative;

View File

@ -6,16 +6,16 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSNativeComponent
* @providesModule ReactNativeBaseComponent
* @flow
*/
'use strict';
var NativeMethodsMixin = require('NativeMethodsMixin');
var ReactIOSComponentMixin = require('ReactIOSComponentMixin');
var ReactIOSEventEmitter = require('ReactIOSEventEmitter');
var ReactIOSStyleAttributes = require('ReactIOSStyleAttributes');
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeComponentMixin = require('ReactNativeComponentMixin');
var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var ReactMultiChild = require('ReactMultiChild');
var RCTUIManager = require('NativeModules').UIManager;
@ -26,23 +26,23 @@ var flattenStyle = require('flattenStyle');
var precomputeStyle = require('precomputeStyle');
var warning = require('warning');
var registrationNames = ReactIOSEventEmitter.registrationNames;
var putListener = ReactIOSEventEmitter.putListener;
var deleteAllListeners = ReactIOSEventEmitter.deleteAllListeners;
var registrationNames = ReactNativeEventEmitter.registrationNames;
var putListener = ReactNativeEventEmitter.putListener;
var deleteAllListeners = ReactNativeEventEmitter.deleteAllListeners;
type ReactIOSNativeComponentViewConfig = {
type ReactNativeBaseComponentViewConfig = {
validAttributes: Object;
uiViewClassName: string;
}
/**
* @constructor ReactIOSNativeComponent
* @constructor ReactNativeBaseComponent
* @extends ReactComponent
* @extends ReactMultiChild
* @param {!object} UIKit View Configuration.
*/
var ReactIOSNativeComponent = function(
viewConfig: ReactIOSNativeComponentViewConfig
var ReactNativeBaseComponent = function(
viewConfig: ReactNativeBaseComponentViewConfig
) {
this.viewConfig = viewConfig;
};
@ -75,7 +75,7 @@ cachedIndexArray._cache = {};
* Mixin for containers that contain UIViews. NOTE: markup is rendered markup
* which is a `viewID` ... see the return value for `mountComponent` !
*/
ReactIOSNativeComponent.Mixin = {
ReactNativeBaseComponent.Mixin = {
getPublicInstance: function() {
// TODO: This should probably use a composite wrapper
return this;
@ -97,7 +97,7 @@ ReactIOSNativeComponent.Mixin = {
* recording the fact that its own `rootNodeID` is associated with a
* `nodeHandle`. Only the code that actually adds its `nodeHandle` (`tag`) as
* a child of a container can confidently record that in
* `ReactIOSTagHandles`.
* `ReactNativeTagHandles`.
*/
initializeChildren: function(children, containerTag, transaction, context) {
var mountImages = this.mountChildren(children, transaction, context);
@ -117,7 +117,7 @@ ReactIOSNativeComponent.Mixin = {
mountImage && mountImage.rootNodeID && mountImage.tag,
'Mount image returned does not have required data'
);
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
childID,
childTag
);
@ -166,7 +166,7 @@ ReactIOSNativeComponent.Mixin = {
updatePayload,
this.previousFlattenedStyle,
nextFlattenedStyle,
ReactIOSStyleAttributes
ReactNativeStyleAttributes
);
this.previousFlattenedStyle = nextFlattenedStyle;
}
@ -195,7 +195,7 @@ ReactIOSNativeComponent.Mixin = {
if (updatePayload) {
RCTUIManager.updateView(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(this._rootNodeID),
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(this._rootNodeID),
this.viewConfig.uiViewClassName,
updatePayload
);
@ -243,7 +243,7 @@ ReactIOSNativeComponent.Mixin = {
mountComponent: function(rootID, transaction, context) {
this._rootNodeID = rootID;
var tag = ReactIOSTagHandles.allocateTag();
var tag = ReactNativeTagHandles.allocateTag();
this.previousFlattenedStyle = {};
var updatePayload = this.computeUpdatedProperties(
@ -268,15 +268,15 @@ ReactIOSNativeComponent.Mixin = {
};
/**
* Order of mixins is important. ReactIOSNativeComponent overrides methods in
* Order of mixins is important. ReactNativeBaseComponent overrides methods in
* ReactMultiChild.
*/
Object.assign(
ReactIOSNativeComponent.prototype,
ReactNativeBaseComponent.prototype,
ReactMultiChild.Mixin,
ReactIOSNativeComponent.Mixin,
ReactNativeBaseComponent.Mixin,
NativeMethodsMixin,
ReactIOSComponentMixin
ReactNativeComponentMixin
);
module.exports = ReactIOSNativeComponent;
module.exports = ReactNativeBaseComponent;

View File

@ -6,19 +6,19 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSComponentEnvironment
* @providesModule ReactNativeComponentEnvironment
* @flow
*/
'use strict';
var ReactIOSDOMIDOperations = require('ReactIOSDOMIDOperations');
var ReactIOSReconcileTransaction = require('ReactIOSReconcileTransaction');
var ReactNativeDOMIDOperations = require('ReactNativeDOMIDOperations');
var ReactNativeReconcileTransaction = require('ReactNativeReconcileTransaction');
var ReactIOSComponentEnvironment = {
var ReactNativeComponentEnvironment = {
processChildrenUpdates: ReactIOSDOMIDOperations.dangerouslyProcessChildrenUpdates,
processChildrenUpdates: ReactNativeDOMIDOperations.dangerouslyProcessChildrenUpdates,
replaceNodeWithMarkupByID: ReactIOSDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
replaceNodeWithMarkupByID: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
/**
* Nothing to do for UIKit bridge.
@ -36,7 +36,7 @@ var ReactIOSComponentEnvironment = {
},
ReactReconcileTransaction: ReactIOSReconcileTransaction,
ReactReconcileTransaction: ReactNativeReconcileTransaction,
};
module.exports = ReactIOSComponentEnvironment;
module.exports = ReactNativeComponentEnvironment;

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactNativeComponentMixin
* @flow
*/
'use strict';
var findNodeHandle = require('findNodeHandle');
var ReactNativeComponentMixin = {
/**
* This method is deprecated; use `React.findNodeHandle` instead.
*/
getNativeNode: function() {
return findNodeHandle(this);
},
/**
* This method is deprecated; use `React.findNodeHandle` instead.
*/
getNodeHandle: function() {
return findNodeHandle(this);
}
};
module.exports = ReactNativeComponentMixin;

View File

@ -6,13 +6,13 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSDOMIDOperations
* @providesModule ReactNativeDOMIDOperations
* @flow
*/
"use strict";
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
var RCTUIManager = require('NativeModules').UIManager;
var ReactPerf = require('ReactPerf');
@ -38,7 +38,7 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
// containerID.
for (var i = 0; i < childrenUpdates.length; i++) {
var update = childrenUpdates[i];
var containerTag = ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(update.parentID);
var containerTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(update.parentID);
var updates = byContainerTag[containerTag] || (byContainerTag[containerTag] = {});
if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING) {
(updates.moveFromIndices || (updates.moveFromIndices = [])).push(update.fromIndex);
@ -49,7 +49,7 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
var mountImage = markupList[update.markupIndex];
var tag = mountImage.tag;
var rootNodeID = mountImage.rootNodeID;
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(rootNodeID, tag);
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(rootNodeID, tag);
(updates.addAtIndices || (updates.addAtIndices = [])).push(update.toIndex);
(updates.addChildTags || (updates.addChildTags = [])).push(tag);
}
@ -75,7 +75,7 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
* Operations used to process updates to DOM nodes. This is made injectable via
* `ReactComponent.DOMIDOperations`.
*/
var ReactIOSDOMIDOperations = {
var ReactNativeDOMIDOperations = {
dangerouslyProcessChildrenUpdates: ReactPerf.measure(
// FIXME(frantic): #4441289 Hack to avoid modifying react-tools
'ReactDOMIDOperations',
@ -93,11 +93,11 @@ var ReactIOSDOMIDOperations = {
'ReactDOMIDOperations',
'dangerouslyReplaceNodeWithMarkupByID',
function(id, mountImage) {
var oldTag = ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(id);
var oldTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(id);
RCTUIManager.replaceExistingNonRootView(oldTag, mountImage.tag);
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(id, mountImage.tag);
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(id, mountImage.tag);
}
),
};
module.exports = ReactIOSDOMIDOperations;
module.exports = ReactNativeDOMIDOperations;

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSDefaultInjection
* @providesModule ReactNativeDefaultInjection
* @flow
*/
@ -26,18 +26,18 @@ var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
var ReactEmptyComponent = require('ReactEmptyComponent');
var ReactInstanceHandles = require('ReactInstanceHandles');
var ReactIOSComponentEnvironment = require('ReactIOSComponentEnvironment');
var ReactIOSComponentMixin = require('ReactIOSComponentMixin');
var ReactIOSGlobalInteractionHandler = require('ReactIOSGlobalInteractionHandler');
var ReactIOSGlobalResponderHandler = require('ReactIOSGlobalResponderHandler');
var ReactIOSMount = require('ReactIOSMount');
var ReactIOSTextComponent = require('ReactIOSTextComponent');
var ReactNativeComponentEnvironment = require('ReactNativeComponentEnvironment');
var ReactNativeComponentMixin = require('ReactNativeComponentMixin');
var ReactNativeGlobalInteractionHandler = require('ReactNativeGlobalInteractionHandler');
var ReactNativeGlobalResponderHandler = require('ReactNativeGlobalResponderHandler');
var ReactNativeMount = require('ReactNativeMount');
var ReactNativeTextComponent = require('ReactNativeTextComponent');
var ReactNativeComponent = require('ReactNativeComponent');
var ReactUpdates = require('ReactUpdates');
var ResponderEventPlugin = require('ResponderEventPlugin');
var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var invariant = require('invariant');
// Just to ensure this gets packaged, since its only caller is from Native.
@ -53,11 +53,11 @@ function inject() {
EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles);
ResponderEventPlugin.injection.injectGlobalResponderHandler(
ReactIOSGlobalResponderHandler
ReactNativeGlobalResponderHandler
);
ResponderEventPlugin.injection.injectGlobalInteractionHandler(
ReactIOSGlobalInteractionHandler
ReactNativeGlobalInteractionHandler
);
/**
@ -70,7 +70,7 @@ function inject() {
});
ReactUpdates.injection.injectReconcileTransaction(
ReactIOSComponentEnvironment.ReactReconcileTransaction
ReactNativeComponentEnvironment.ReactReconcileTransaction
);
ReactUpdates.injection.injectBatchingStrategy(
@ -78,22 +78,22 @@ function inject() {
);
ReactComponentEnvironment.injection.injectEnvironment(
ReactIOSComponentEnvironment
ReactNativeComponentEnvironment
);
// Can't import View here because it depends on React to make its composite
var RCTView = createReactIOSNativeComponentClass({
var RCTView = createReactNativeComponentClass({
validAttributes: {},
uiViewClassName: 'RCTView',
});
ReactEmptyComponent.injection.injectEmptyComponent(RCTView);
EventPluginUtils.injection.injectMount(ReactIOSMount);
EventPluginUtils.injection.injectMount(ReactNativeMount);
ReactClass.injection.injectMixin(ReactIOSComponentMixin);
ReactClass.injection.injectMixin(ReactNativeComponentMixin);
ReactNativeComponent.injection.injectTextComponentClass(
ReactIOSTextComponent
ReactNativeTextComponent
);
ReactNativeComponent.injection.injectAutoWrapper(function(tag) {
// Show a nicer error message for non-function tags

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSEventEmitter
* @providesModule ReactNativeEventEmitter
* @flow
*/
@ -14,7 +14,7 @@
var EventPluginHub = require('EventPluginHub');
var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var NodeHandle = require('NodeHandle');
var EventConstants = require('EventConstants');
@ -82,15 +82,15 @@ var removeTouchesAtIndices = function(
};
/**
* `ReactIOSEventEmitter` is used to attach top-level event listeners. For example:
* `ReactNativeEventEmitter` is used to attach top-level event listeners. For example:
*
* ReactIOSEventEmitter.putListener('myID', 'onClick', myFunction);
* ReactNativeEventEmitter.putListener('myID', 'onClick', myFunction);
*
* This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
*
* @internal
*/
var ReactIOSEventEmitter = merge(ReactEventEmitterMixin, {
var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
registrationNames: EventPluginHub.registrationNameModules,
@ -118,7 +118,7 @@ var ReactIOSEventEmitter = merge(ReactEventEmitterMixin, {
nativeEventParam: Object
) {
var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
ReactIOSEventEmitter.handleTopLevel(
ReactNativeEventEmitter.handleTopLevel(
topLevelType,
rootNodeID,
rootNodeID,
@ -138,8 +138,8 @@ var ReactIOSEventEmitter = merge(ReactEventEmitterMixin, {
topLevelType: string,
nativeEventParam: Object
) {
var rootNodeID = ReactIOSTagHandles.tagToRootNodeID[tag];
ReactIOSEventEmitter._receiveRootNodeIDEvent(
var rootNodeID = ReactNativeTagHandles.tagToRootNodeID[tag];
ReactNativeEventEmitter._receiveRootNodeIDEvent(
rootNodeID,
topLevelType,
nativeEventParam
@ -191,7 +191,7 @@ var ReactIOSEventEmitter = merge(ReactEventEmitterMixin, {
var rootNodeID = null;
var target = nativeEvent.target;
if (target !== null && target !== undefined) {
if (target < ReactIOSTagHandles.tagsStartAt) {
if (target < ReactNativeTagHandles.tagsStartAt) {
if (__DEV__) {
warning(
false,
@ -202,7 +202,7 @@ var ReactIOSEventEmitter = merge(ReactEventEmitterMixin, {
rootNodeID = NodeHandle.getRootNodeID(target);
}
}
ReactIOSEventEmitter._receiveRootNodeIDEvent(
ReactNativeEventEmitter._receiveRootNodeIDEvent(
rootNodeID,
eventTopLevelType,
nativeEvent
@ -211,4 +211,4 @@ var ReactIOSEventEmitter = merge(ReactEventEmitterMixin, {
}
});
module.exports = ReactIOSEventEmitter;
module.exports = ReactNativeEventEmitter;

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSGlobalInteractionHandler
* @providesModule ReactNativeGlobalInteractionHandler
* @flow
*/
'use strict';
@ -17,7 +17,7 @@ var InteractionManager = require('InteractionManager');
// released/terminated.
var interactionHandle = null;
var ReactIOSGlobalInteractionHandler = {
var ReactNativeGlobalInteractionHandler = {
onChange: function(numberActiveTouches: number) {
if (numberActiveTouches === 0) {
if (interactionHandle) {
@ -30,4 +30,4 @@ var ReactIOSGlobalInteractionHandler = {
}
};
module.exports = ReactIOSGlobalInteractionHandler;
module.exports = ReactNativeGlobalInteractionHandler;

View File

@ -6,19 +6,19 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSGlobalResponderHandler
* @providesModule ReactNativeGlobalResponderHandler
* @flow
*/
'use strict';
var RCTUIManager = require('NativeModules').UIManager;
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var ReactIOSGlobalResponderHandler = {
var ReactNativeGlobalResponderHandler = {
onChange: function(from: string, to: string) {
if (to !== null) {
RCTUIManager.setJSResponder(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(to)
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(to)
);
} else {
RCTUIManager.clearJSResponder();
@ -26,4 +26,4 @@ var ReactIOSGlobalResponderHandler = {
}
};
module.exports = ReactIOSGlobalResponderHandler;
module.exports = ReactNativeGlobalResponderHandler;

View File

@ -6,14 +6,14 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSMount
* @providesModule ReactNativeMount
* @flow
*/
'use strict';
var RCTUIManager = require('NativeModules').UIManager;
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var ReactPerf = require('ReactPerf');
var ReactReconciler = require('ReactReconciler');
var ReactUpdateQueue = require('ReactUpdateQueue');
@ -45,7 +45,7 @@ function mountComponentIntoNode(
componentInstance, rootID, transaction, emptyObject
);
componentInstance._isTopLevel = true;
ReactIOSMount._mountImageIntoNode(markup, container);
ReactNativeMount._mountImageIntoNode(markup, container);
}
/**
@ -75,7 +75,7 @@ function batchedMountComponentIntoNode(
* As soon as `ReactMount` is refactored to not rely on the DOM, we can share
* code between the two. For now, we'll hard code the ID logic.
*/
var ReactIOSMount = {
var ReactNativeMount = {
instanceCount: 0,
_instancesByContainerID: {},
@ -89,9 +89,9 @@ var ReactIOSMount = {
containerTag: number,
callback?: ?(() => void)
): ?ReactComponent {
var topRootNodeID = ReactIOSTagHandles.tagToRootNodeID[containerTag];
var topRootNodeID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
if (topRootNodeID) {
var prevComponent = ReactIOSMount._instancesByContainerID[topRootNodeID];
var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
if (prevComponent) {
var prevElement = prevComponent._currentElement;
if (shouldUpdateReactComponent(prevElement, nextElement)) {
@ -101,28 +101,28 @@ var ReactIOSMount = {
}
return prevComponent;
} else {
ReactIOSMount.unmountComponentAtNode(containerTag);
ReactNativeMount.unmountComponentAtNode(containerTag);
}
}
}
if (!ReactIOSTagHandles.reactTagIsNativeTopRootID(containerTag)) {
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
console.error('You cannot render into anything but a top root');
return;
}
var topRootNodeID = ReactIOSTagHandles.allocateRootNodeIDForTag(containerTag);
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
var topRootNodeID = ReactNativeTagHandles.allocateRootNodeIDForTag(containerTag);
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
topRootNodeID,
containerTag
);
var instance = instantiateReactComponent(nextElement);
ReactIOSMount._instancesByContainerID[topRootNodeID] = instance;
ReactNativeMount._instancesByContainerID[topRootNodeID] = instance;
var childRootNodeID = instanceNumberToChildRootID(
topRootNodeID,
ReactIOSMount.instanceCount++
ReactNativeMount.instanceCount++
);
// The initial render is synchronous but any updates that happen during
@ -153,14 +153,14 @@ var ReactIOSMount = {
function(mountImage, containerID) {
// Since we now know that the `mountImage` has been mounted, we can
// mark it as such.
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
mountImage.rootNodeID,
mountImage.tag
);
var addChildTags = [mountImage.tag];
var addAtIndices = [0];
RCTUIManager.manageChildren(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
null, // moveFromIndices
null, // moveToIndices
addChildTags,
@ -181,7 +181,7 @@ var ReactIOSMount = {
unmountComponentAtNodeAndRemoveContainer: function(
containerTag: number
) {
ReactIOSMount.unmountComponentAtNode(containerTag);
ReactNativeMount.unmountComponentAtNode(containerTag);
// call back into native to remove all of the subviews from this container
RCTUIManager.removeRootView(containerTag);
},
@ -192,18 +192,18 @@ var ReactIOSMount = {
* component at this time.
*/
unmountComponentAtNode: function(containerTag: number): boolean {
if (!ReactIOSTagHandles.reactTagIsNativeTopRootID(containerTag)) {
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
console.error('You cannot render into anything but a top root');
return false;
}
var containerID = ReactIOSTagHandles.tagToRootNodeID[containerTag];
var instance = ReactIOSMount._instancesByContainerID[containerID];
var containerID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
var instance = ReactNativeMount._instancesByContainerID[containerID];
if (!instance) {
return false;
}
ReactIOSMount.unmountComponentFromNode(instance, containerID);
delete ReactIOSMount._instancesByContainerID[containerID];
ReactNativeMount.unmountComponentFromNode(instance, containerID);
delete ReactNativeMount._instancesByContainerID[containerID];
return true;
},
@ -214,7 +214,7 @@ var ReactIOSMount = {
* @param {string} containerID ID of container we're removing from.
* @final
* @internal
* @see {ReactIOSMount.unmountComponentAtNode}
* @see {ReactNativeMount.unmountComponentAtNode}
*/
unmountComponentFromNode: function(
instance: ReactComponent,
@ -223,7 +223,7 @@ var ReactIOSMount = {
// Call back into native to remove all of the subviews from this container
ReactReconciler.unmountComponent(instance);
var containerTag =
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
RCTUIManager.removeSubviewsFromContainerWithID(containerTag);
},
@ -232,10 +232,10 @@ var ReactIOSMount = {
}
};
ReactIOSMount.renderComponent = ReactPerf.measure(
ReactNativeMount.renderComponent = ReactPerf.measure(
'ReactMount',
'_renderNewRootComponent',
ReactIOSMount.renderComponent
ReactNativeMount.renderComponent
);
module.exports = ReactIOSMount;
module.exports = ReactNativeMount;

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSReconcileTransaction
* @providesModule ReactNativeReconcileTransaction
* @flow
*/
@ -55,9 +55,9 @@ var TRANSACTION_WRAPPERS = [ON_DOM_READY_QUEUEING];
* - Implement/integrate with customized constraint based layout system and keep
* track of which dimensions must be remeasured.
*
* @class ReactIOSReconcileTransaction
* @class ReactNativeReconcileTransaction
*/
function ReactIOSReconcileTransaction() {
function ReactNativeReconcileTransaction() {
this.reinitializeTransaction();
this.reactMountReady = CallbackQueue.getPooled(null);
}
@ -93,12 +93,12 @@ var Mixin = {
};
Object.assign(
ReactIOSReconcileTransaction.prototype,
ReactNativeReconcileTransaction.prototype,
Transaction.Mixin,
ReactIOSReconcileTransaction,
ReactNativeReconcileTransaction,
Mixin
);
PooledClass.addPoolingTo(ReactIOSReconcileTransaction);
PooledClass.addPoolingTo(ReactNativeReconcileTransaction);
module.exports = ReactIOSReconcileTransaction;
module.exports = ReactNativeReconcileTransaction;

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSStyleAttributes
* @providesModule ReactNativeStyleAttributes
* @flow
*/
@ -20,13 +20,13 @@ var keyMirror = require('keyMirror');
var matricesDiffer = require('matricesDiffer');
var sizesDiffer = require('sizesDiffer');
var ReactIOSStyleAttributes = {
var ReactNativeStyleAttributes = {
...keyMirror(ViewStylePropTypes),
...keyMirror(TextStylePropTypes),
...keyMirror(ImageStylePropTypes),
};
ReactIOSStyleAttributes.transformMatrix = { diff: matricesDiffer };
ReactIOSStyleAttributes.shadowOffset = { diff: sizesDiffer };
ReactNativeStyleAttributes.transformMatrix = { diff: matricesDiffer };
ReactNativeStyleAttributes.shadowOffset = { diff: sizesDiffer };
module.exports = ReactIOSStyleAttributes;
module.exports = ReactNativeStyleAttributes;

View File

@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSTagHandles
* @providesModule ReactNativeTagHandles
* @flow
*/
'use strict';
@ -28,17 +28,17 @@ var warning = require('warning');
* unmount a component with a `rootNodeID`, then mount a new one in its place,
*/
var INITIAL_TAG_COUNT = 1;
var ReactIOSTagHandles = {
var ReactNativeTagHandles = {
tagsStartAt: INITIAL_TAG_COUNT,
tagCount: INITIAL_TAG_COUNT,
allocateTag: function(): number {
// Skip over root IDs as those are reserved for native
while (this.reactTagIsNativeTopRootID(ReactIOSTagHandles.tagCount)) {
ReactIOSTagHandles.tagCount++;
while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) {
ReactNativeTagHandles.tagCount++;
}
var tag = ReactIOSTagHandles.tagCount;
ReactIOSTagHandles.tagCount++;
var tag = ReactNativeTagHandles.tagCount;
ReactNativeTagHandles.tagCount++;
return tag;
},
@ -57,8 +57,8 @@ var ReactIOSTagHandles = {
) {
warning(rootNodeID && tag, 'Root node or tag is null when associating');
if (rootNodeID && tag) {
ReactIOSTagHandles.tagToRootNodeID[tag] = rootNodeID;
ReactIOSTagHandles.rootNodeIDToTag[rootNodeID] = tag;
ReactNativeTagHandles.tagToRootNodeID[tag] = rootNodeID;
ReactNativeTagHandles.rootNodeIDToTag[rootNodeID] = tag;
}
},
@ -90,7 +90,7 @@ var ReactIOSTagHandles = {
mostRecentMountedNodeHandleForRootNodeID: function(
rootNodeID: string
): number {
return ReactIOSTagHandles.rootNodeIDToTag[rootNodeID];
return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
},
tagToRootNodeID: ([] : Array<string>),
@ -98,4 +98,4 @@ var ReactIOSTagHandles = {
rootNodeIDToTag: ({} : {[key: string]: number})
};
module.exports = ReactIOSTagHandles;
module.exports = ReactNativeTagHandles;

View File

@ -6,21 +6,21 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSTextComponent
* @providesModule ReactNativeTextComponent
*/
'use strict';
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var RCTUIManager = require('NativeModules').UIManager;
var assign = require('Object.assign');
var ReactIOSTextComponent = function(props) {
var ReactNativeTextComponent = function(props) {
// This constructor and its argument is currently used by mocks.
};
assign(ReactIOSTextComponent.prototype, {
assign(ReactNativeTextComponent.prototype, {
construct: function(text) {
// This is really a ReactText (ReactNode), not a ReactElement
@ -31,7 +31,7 @@ assign(ReactIOSTextComponent.prototype, {
mountComponent: function(rootID, transaction, context) {
this._rootNodeID = rootID;
var tag = ReactIOSTagHandles.allocateTag();
var tag = ReactNativeTagHandles.allocateTag();
RCTUIManager.createView(tag, 'RCTRawText', {text: this._stringText});
return {
rootNodeID: rootID,
@ -46,7 +46,7 @@ assign(ReactIOSTextComponent.prototype, {
if (nextStringText !== this._stringText) {
this._stringText = nextStringText;
RCTUIManager.updateView(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(
this._rootNodeID
),
'RCTRawText',
@ -64,4 +64,4 @@ assign(ReactIOSTextComponent.prototype, {
});
module.exports = ReactIOSTextComponent;
module.exports = ReactNativeTextComponent;

View File

@ -6,16 +6,16 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactIOSViewAttributes
* @providesModule ReactNativeViewAttributes
* @flow
*/
'use strict';
var merge = require('merge');
var ReactIOSViewAttributes = {};
var ReactNativeViewAttributes = {};
ReactIOSViewAttributes.UIView = {
ReactNativeViewAttributes.UIView = {
pointerEvents: true,
accessible: true,
accessibilityLabel: true,
@ -23,8 +23,8 @@ ReactIOSViewAttributes.UIView = {
onLayout: true,
};
ReactIOSViewAttributes.RCTView = merge(
ReactIOSViewAttributes.UIView, {
ReactNativeViewAttributes.RCTView = merge(
ReactNativeViewAttributes.UIView, {
// This is a special performance property exposed by RCTView and useful for
// scrolling content when there are many subviews, most of which are offscreen.
@ -34,4 +34,4 @@ ReactIOSViewAttributes.RCTView = merge(
removeClippedSubviews: true,
});
module.exports = ReactIOSViewAttributes;
module.exports = ReactNativeViewAttributes;

View File

@ -6,17 +6,17 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule createReactIOSNativeComponentClass
* @providesModule createReactNativeComponentClass
* @flow
*/
"use strict";
var ReactElement = require('ReactElement');
var ReactIOSNativeComponent = require('ReactIOSNativeComponent');
var ReactNativeBaseComponent = require('ReactNativeBaseComponent');
// See also ReactIOSNativeComponent
type ReactIOSNativeComponentViewConfig = {
// See also ReactNativeBaseComponent
type ReactNativeBaseComponentViewConfig = {
validAttributes: Object;
uiViewClassName: string;
}
@ -25,8 +25,8 @@ type ReactIOSNativeComponentViewConfig = {
* @param {string} config iOS View configuration.
* @private
*/
var createReactIOSNativeComponentClass = function(
viewConfig: ReactIOSNativeComponentViewConfig
var createReactNativeComponentClass = function(
viewConfig: ReactNativeBaseComponentViewConfig
): Function { // returning Function is lossy :/
var Constructor = function(element) {
this._currentElement = element;
@ -36,9 +36,9 @@ var createReactIOSNativeComponentClass = function(
this.previousFlattenedStyle = null;
};
Constructor.displayName = viewConfig.uiViewClassName;
Constructor.prototype = new ReactIOSNativeComponent(viewConfig);
Constructor.prototype = new ReactNativeBaseComponent(viewConfig);
return Constructor;
};
module.exports = createReactIOSNativeComponentClass;
module.exports = createReactNativeComponentClass;

View File

@ -0,0 +1,112 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule findNodeHandle
* @flow
*/
'use strict';
var ReactCurrentOwner = require('ReactCurrentOwner');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var invariant = require('invariant');
var warning = require('warning');
/**
* ReactNative vs ReactWeb
* -----------------------
* React treats some pieces of data opaquely. This means that the information
* is first class (it can be passed around), but cannot be inspected. This
* allows us to build infrastructure that reasons about resources, without
* making assumptions about the nature of those resources, and this allows that
* infra to be shared across multiple platforms, where the resources are very
* different. General infra (such as `ReactMultiChild`) reasons opaquely about
* the data, but platform specific code (such as `ReactNativeBaseComponent`) can
* make assumptions about the data.
*
*
* `rootNodeID`, uniquely identifies a position in the generated native view
* tree. Many layers of composite components (created with `React.createClass`)
* can all share the same `rootNodeID`.
*
* `nodeHandle`: A sufficiently unambiguous way to refer to a lower level
* resource (dom node, native view etc). The `rootNodeID` is sufficient for web
* `nodeHandle`s, because the position in a tree is always enough to uniquely
* identify a DOM node (we never have nodes in some bank outside of the
* document). The same would be true for `ReactNative`, but we must maintain a
* mapping that we can send efficiently serializable
* strings across native boundaries.
*
* Opaque name TodaysWebReact FutureWebWorkerReact ReactNative
* ----------------------------------------------------------------------------
* nodeHandle N/A rootNodeID tag
*/
function findNodeHandle(componentOrHandle: any): ?number {
if (__DEV__) {
var owner = ReactCurrentOwner.current;
if (owner !== null) {
warning(
owner._warnedAboutRefsInRender,
'%s is accessing findNodeHandle inside its render(). ' +
'render() should be a pure function of props and state. It should ' +
'never access something that requires stale data from the previous ' +
'render, such as refs. Move this logic to componentDidMount and ' +
'componentDidUpdate instead.',
owner.getName() || 'A component'
);
owner._warnedAboutRefsInRender = true;
}
}
if (componentOrHandle == null) {
return null;
}
if (typeof componentOrHandle === 'number') {
// Already a node handle
return componentOrHandle;
}
var component = componentOrHandle;
// TODO (balpert): Wrap iOS native components in a composite wrapper, then
// ReactInstanceMap.get here will always succeed for mounted components
var internalInstance = ReactInstanceMap.get(component);
if (internalInstance) {
return ReactNativeTagHandles.rootNodeIDToTag[internalInstance._rootNodeID];
} else {
var rootNodeID = component._rootNodeID;
if (rootNodeID) {
return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
} else {
invariant(
(
// Native
typeof component === 'object' &&
'_rootNodeID' in component
) || (
// Composite
component.render != null &&
typeof component.render === 'function'
),
'findNodeHandle(...): Argument is not a component ' +
'(type: %s, keys: %s)',
typeof component,
Object.keys(component)
);
invariant(
false,
'findNodeHandle(...): Unable to find node handle for unmounted ' +
'component.'
);
}
}
}
module.exports = findNodeHandle;

View File

@ -12,6 +12,7 @@
'use strict';
var MatrixMath = require('MatrixMath');
var Platform = require('Platform');
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
var invariant = require('invariant');
@ -36,8 +37,9 @@ function precomputeStyle(style: ?Object): ?Object {
* Generate a transform matrix based on the provided transforms, and use that
* within the style object instead.
*
* This allows us to provide an API that is similar to CSS and to have a
* universal, singular interface to native code.
* This allows us to provide an API that is similar to CSS, where transforms may
* be applied in an arbitrary order, and yet have a universal, singular
* interface to native code.
*/
function _precomputeTransforms(style: Object): Object {
var {transform} = style;
@ -80,6 +82,17 @@ function _precomputeTransforms(style: Object): Object {
}
});
// Android does not support the direct application of a transform matrix to
// a view, so we need to decompose the result matrix into transforms that can
// get applied in the specific order of (1) translate (2) scale (3) rotate.
// Once we can directly apply a matrix, we can remove this decomposition.
if (Platform.OS === 'android') {
return {
...style,
transformMatrix: result,
decomposedMatrix: MatrixMath.decomposeMatrix(result),
};
}
return {
...style,
transformMatrix: result,

View File

@ -22,6 +22,7 @@ extern NSString *const RCTReactTagAttributeName;
@property (nonatomic, copy) NSString *fontWeight;
@property (nonatomic, copy) NSString *fontStyle;
@property (nonatomic, assign) BOOL isHighlighted;
@property (nonatomic, assign) CGFloat letterSpacing;
@property (nonatomic, assign) CGFloat lineHeight;
@property (nonatomic, assign) NSUInteger maximumNumberOfLines;
@property (nonatomic, assign) CGSize shadowOffset;
@ -30,6 +31,7 @@ extern NSString *const RCTReactTagAttributeName;
// Not exposed to JS
@property (nonatomic, strong) UIFont *font;
@property (nonatomic, assign) NSLineBreakMode truncationMode;
@property (nonatomic, assign) CGFloat effectiveLetterSpacing;
@property (nonatomic, copy, readonly) NSAttributedString *attributedString;
@property (nonatomic, strong, readonly) NSLayoutManager *layoutManager;

View File

@ -40,11 +40,15 @@ static css_dim_t RCTMeasure(void *context, float width)
css_dim_t result;
result.dimensions[CSS_WIDTH] = RCTCeilPixelValue(computedSize.width);
if (shadowText.effectiveLetterSpacing < 0) {
result.dimensions[CSS_WIDTH] -= shadowText.effectiveLetterSpacing;
}
result.dimensions[CSS_HEIGHT] = RCTCeilPixelValue(computedSize.height);
return result;
}
@implementation RCTShadowText {
@implementation RCTShadowText
{
NSLayoutManager *_layoutManager;
NSTextContainer *_textContainer;
NSAttributedString *_cachedAttributedString;
@ -55,6 +59,7 @@ static css_dim_t RCTMeasure(void *context, float width)
{
if ((self = [super init])) {
_fontSize = NAN;
_letterSpacing = NAN;
_isHighlighted = NO;
_textContainer = [[NSTextContainer alloc] init];
@ -71,22 +76,24 @@ static css_dim_t RCTMeasure(void *context, float width)
- (NSAttributedString *)attributedString
{
return [self _attributedStringWithFontFamily:nil
fontSize:0
fontSize:nil
fontWeight:nil
fontStyle:nil];
fontStyle:nil
letterSpacing:nil];
}
- (NSAttributedString *)_attributedStringWithFontFamily:(NSString *)fontFamily
fontSize:(CGFloat)fontSize
fontSize:(NSNumber *)fontSize
fontWeight:(NSString *)fontWeight
fontStyle:(NSString *)fontStyle
letterSpacing:(NSNumber *)letterSpacing
{
if (![self isTextDirty] && _cachedAttributedString) {
return _cachedAttributedString;
}
if (_fontSize && !isnan(_fontSize)) {
fontSize = _fontSize;
fontSize = @(_fontSize);
}
if (_fontWeight) {
fontWeight = _fontWeight;
@ -97,12 +104,17 @@ static css_dim_t RCTMeasure(void *context, float width)
if (_fontFamily) {
fontFamily = _fontFamily;
}
if (!isnan(_letterSpacing)) {
letterSpacing = @(_letterSpacing);
}
_effectiveLetterSpacing = letterSpacing.doubleValue;
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
for (RCTShadowView *child in [self reactSubviews]) {
if ([child isKindOfClass:[RCTShadowText class]]) {
RCTShadowText *shadowText = (RCTShadowText *)child;
[attributedString appendAttributedString:[shadowText _attributedStringWithFontFamily:fontFamily fontSize:fontSize fontWeight:fontWeight fontStyle:fontStyle]];
[attributedString appendAttributedString:[shadowText _attributedStringWithFontFamily:fontFamily fontSize:fontSize fontWeight:fontWeight fontStyle:fontStyle letterSpacing:letterSpacing]];
} else if ([child isKindOfClass:[RCTShadowRawText class]]) {
RCTShadowRawText *shadowRawText = (RCTShadowRawText *)child;
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:[shadowRawText text] ?: @""]];
@ -123,8 +135,9 @@ 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 style:fontStyle];
_font = [RCTConvert UIFont:nil withFamily:fontFamily size:fontSize weight:fontWeight style:fontStyle];
[self _addAttribute:NSFontAttributeName withValue:_font toAttributedString:attributedString];
[self _addAttribute:NSKernAttributeName withValue:letterSpacing toAttributedString:attributedString];
[self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString];
[self _setParagraphStyleOnAttributedString:attributedString];
@ -143,7 +156,7 @@ static css_dim_t RCTMeasure(void *context, float width)
- (void)_addAttribute:(NSString *)attribute withValue:(id)attributeValue toAttributedString:(NSMutableAttributedString *)attributedString
{
[attributedString enumerateAttribute:attribute inRange:NSMakeRange(0, [attributedString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (!value) {
if (!value && attributeValue) {
[attributedString addAttribute:attribute value:attributeValue range:range];
}
}];
@ -223,6 +236,7 @@ RCT_TEXT_PROPERTY(Color, _color, UIColor *);
RCT_TEXT_PROPERTY(FontFamily, _fontFamily, NSString *);
RCT_TEXT_PROPERTY(FontSize, _fontSize, CGFloat);
RCT_TEXT_PROPERTY(FontWeight, _fontWeight, NSString *);
RCT_TEXT_PROPERTY(LetterSpacing, _letterSpacing, CGFloat);
RCT_TEXT_PROPERTY(LineHeight, _lineHeight, CGFloat);
RCT_TEXT_PROPERTY(ShadowOffset, _shadowOffset, CGSize);
RCT_TEXT_PROPERTY(TextAlign, _textAlign, NSTextAlignment);

View File

@ -14,7 +14,6 @@
@property (nonatomic, strong) NSLayoutManager *layoutManager;
@property (nonatomic, strong) NSTextContainer *textContainer;
@property (nonatomic, copy) NSAttributedString *attributedText;
@property (nonatomic, assign) UIEdgeInsets contentInset;
@end

View File

@ -45,6 +45,7 @@ RCT_EXPORT_SHADOW_PROPERTY(fontSize, CGFloat)
RCT_EXPORT_SHADOW_PROPERTY(fontWeight, NSString)
RCT_EXPORT_SHADOW_PROPERTY(fontStyle, NSString)
RCT_EXPORT_SHADOW_PROPERTY(isHighlighted, BOOL)
RCT_EXPORT_SHADOW_PROPERTY(letterSpacing, CGFloat)
RCT_EXPORT_SHADOW_PROPERTY(lineHeight, CGFloat)
RCT_EXPORT_SHADOW_PROPERTY(maximumNumberOfLines, NSInteger)
RCT_EXPORT_SHADOW_PROPERTY(shadowOffset, CGSize)

View File

@ -13,19 +13,19 @@
var NativeMethodsMixin = require('NativeMethodsMixin');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheetPropType = require('StyleSheetPropType');
var TextStylePropTypes = require('TextStylePropTypes');
var Touchable = require('Touchable');
var createReactIOSNativeComponentClass =
require('createReactIOSNativeComponentClass');
var createReactNativeComponentClass =
require('createReactNativeComponentClass');
var merge = require('merge');
var stylePropType = StyleSheetPropType(TextStylePropTypes);
var viewConfig = {
validAttributes: merge(ReactIOSViewAttributes.UIView, {
validAttributes: merge(ReactNativeViewAttributes.UIView, {
isHighlighted: true,
numberOfLines: true,
}),
@ -176,7 +176,6 @@ var Text = React.createClass({
for (var key in this.props) {
props[key] = this.props[key];
}
props.ref = this.getNodeHandle();
// Text is accessible by default
if (props.accessible !== false) {
props.accessible = true;
@ -202,6 +201,6 @@ type RectOffset = {
var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
var RCTText = createReactIOSNativeComponentClass(viewConfig);
var RCTText = createReactNativeComponentClass(viewConfig);
module.exports = Text;

View File

@ -32,6 +32,7 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
writingDirection: ReactPropTypes.oneOf(
['auto' /*default*/, 'ltr', 'rtl']
),
letterSpacing: ReactPropTypes.number,
});
// Text doesn't support padding correctly (#4841912)

View File

@ -12,6 +12,7 @@
'use strict';
var RCTAlertManager = require('NativeModules').AlertManager;
var invariant = require('invariant');
var DEFAULT_BUTTON_TEXT = 'OK';
var DEFAULT_BUTTON = {
@ -47,14 +48,17 @@ class AlertIOS {
message?: ?string,
buttons?: Array<{
text: ?string;
onPress: ?Function;
}>
onPress?: ?Function;
}>,
type?: ?string
): void {
var callbacks = [];
var buttonsSpec = [];
title = title || '';
message = message || '';
buttons = buttons || [DEFAULT_BUTTON];
type = type || '';
buttons.forEach((btn, index) => {
callbacks[index] = btn.onPress;
var btnDef = {};
@ -65,12 +69,50 @@ class AlertIOS {
title,
message,
buttons: buttonsSpec,
}, (id) => {
type,
}, (id, value) => {
var cb = callbacks[id];
cb && cb();
cb && cb(value);
});
}
static prompt(
title: string,
value?: string,
buttons?: Array<{
text: ?string;
onPress?: ?Function;
}>,
callback?: ?Function
): void {
if (arguments.length === 2) {
if (typeof value === 'object') {
buttons = value;
value = undefined;
} else if (typeof value === 'function') {
callback = value;
value = undefined;
}
} else if (arguments.length === 3 && typeof buttons === 'function') {
callback = buttons;
buttons = undefined;
}
invariant(
!(callback && buttons) && (callback || buttons),
'Must provide either a button list or a callback, but not both'
);
if (!buttons) {
buttons = [{
text: 'Cancel',
}, {
text: 'OK',
onPress: callback
}];
}
this.alert(title, value, buttons, 'plain-text');
}
}
module.exports = AlertIOS;

View File

@ -5,6 +5,8 @@
*/
'use strict';
var invariant = require('invariant');
/**
* Memory conservative (mutative) matrix math utilities. Uses "command"
* matrices, which are reusable.
@ -74,17 +76,18 @@ var MatrixMath = {
matrixCommand[10] = factor;
},
reuseRotateYCommand: function(matrixCommand, amount) {
matrixCommand[0] = Math.cos(amount);
matrixCommand[2] = Math.sin(amount);
matrixCommand[8] = Math.sin(-amount);
matrixCommand[10] = Math.cos(amount);
reuseRotateXCommand: function(matrixCommand, radians) {
matrixCommand[5] = Math.cos(radians);
matrixCommand[6] = Math.sin(radians);
matrixCommand[9] = -Math.sin(radians);
matrixCommand[10] = Math.cos(radians);
},
createRotateZ: function(radians) {
var mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateZCommand(mat, radians);
return mat;
reuseRotateYCommand: function(matrixCommand, amount) {
matrixCommand[0] = Math.cos(amount);
matrixCommand[2] = -Math.sin(amount);
matrixCommand[8] = Math.sin(amount);
matrixCommand[10] = Math.cos(amount);
},
// http://www.w3.org/TR/css3-transforms/#recomposing-to-a-2d-matrix
@ -95,6 +98,12 @@ var MatrixMath = {
matrixCommand[5] = Math.cos(radians);
},
createRotateZ: function(radians) {
var mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateZCommand(mat, radians);
return mat;
},
multiplyInto: function(out, a, b) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
@ -124,7 +133,398 @@ var MatrixMath = {
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
},
determinant(matrix: Array<number>): number {
var [
m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33
] = matrix;
return (
m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 -
m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 +
m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 -
m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 +
m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 -
m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 +
m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 -
m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 +
m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 -
m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 +
m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 -
m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33
);
},
/**
* Inverse of a matrix. Multiplying by the inverse is used in matrix math
* instead of division.
*
* Formula from:
* http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
*/
inverse(matrix: Array<number>): Array<number> {
var det = MatrixMath.determinant(matrix);
if (!det) {
return matrix;
}
var [
m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33
] = matrix;
return [
(m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33) / det,
(m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33) / det,
(m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33) / det,
(m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23) / det,
(m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33) / det,
(m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33) / det,
(m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33) / det,
(m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23) / det,
(m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33) / det,
(m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33) / det,
(m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33) / det,
(m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23) / det,
(m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32) / det,
(m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32) / det,
(m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32) / det,
(m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22) / det
];
},
/**
* Turns columns into rows and rows into columns.
*/
transpose(m: Array<number>): Array<number> {
return [
m[0], m[4], m[8], m[12],
m[1], m[5], m[9], m[13],
m[2], m[6], m[10], m[14],
m[3], m[7], m[11], m[15]
];
},
/**
* Based on: http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c
*/
multiplyVectorByMatrix(
v: Array<number>,
m: Array<number>
): Array<number> {
var [vx, vy, vz, vw] = v;
return [
vx * m[0] + vy * m[4] + vz * m[8] + vw * m[12],
vx * m[1] + vy * m[5] + vz * m[9] + vw * m[13],
vx * m[2] + vy * m[6] + vz * m[10] + vw * m[14],
vx * m[3] + vy * m[7] + vz * m[11] + vw * m[15]
];
},
/**
* From: https://code.google.com/p/webgl-mjs/source/browse/mjs.js
*/
v3Length(a: Array<number>): number {
return Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
},
/**
* Based on: https://code.google.com/p/webgl-mjs/source/browse/mjs.js
*/
v3Normalize(
vector: Array<number>,
v3Length: number
): Array<number> {
var im = 1 / (v3Length || MatrixMath.v3Length(vector));
return [
vector[0] * im,
vector[1] * im,
vector[2] * im
];
},
/**
* The dot product of a and b, two 3-element vectors.
* From: https://code.google.com/p/webgl-mjs/source/browse/mjs.js
*/
v3Dot(a, b) {
return a[0] * b[0] +
a[1] * b[1] +
a[2] * b[2];
},
/**
* From:
* http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp
*/
v3Combine(
a: Array<number>,
b: Array<number>,
aScale: number,
bScale: number
): Array<number> {
return [
aScale * a[0] + bScale * b[0],
aScale * a[1] + bScale * b[1],
aScale * a[2] + bScale * b[2]
];
},
/**
* From:
* http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp
*/
v3Cross(a: Array<number>, b: Array<number>): Array<number> {
return [
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0]
];
},
/**
* Based on:
* http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
* and:
* http://quat.zachbennett.com/
*
* Note that this rounds degrees to the thousandth of a degree, due to
* floating point errors in the creation of the quaternion.
*
* Also note that this expects the qw value to be last, not first.
*
* Also, when researching this, remember that:
* yaw === heading === z-axis
* pitch === elevation/attitude === y-axis
* roll === bank === x-axis
*/
quaternionToDegreesXYZ(q: Array<number>, matrix, row): Array<number> {
var [qx, qy, qz, qw] = q;
var qw2 = qw * qw;
var qx2 = qx * qx;
var qy2 = qy * qy;
var qz2 = qz * qz;
var test = qx * qy + qz * qw;
var unit = qw2 + qx2 + qy2 + qz2;
var conv = 180 / Math.PI;
if (test > 0.49999 * unit) {
return [0, 2 * Math.atan2(qx, qw) * conv, 90];
}
if (test < -0.49999 * unit) {
return [0, -2 * Math.atan2(qx, qw) * conv, -90];
}
return [
MatrixMath.roundTo3Places(
Math.atan2(2*qx*qw-2*qy*qz,1-2*qx2-2*qz2) * conv
),
MatrixMath.roundTo3Places(
Math.atan2(2*qy*qw-2*qx*qz,1-2*qy2-2*qz2) * conv
),
MatrixMath.roundTo3Places(
Math.asin(2*qx*qy+2*qz*qw) * conv
)
];
},
/**
* Based on:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
*/
roundTo3Places(n: number): number {
var arr = n.toString().split('e');
return Math.round(arr[0] + 'e' + (arr[1] ? (+arr[1] - 3) : 3)) * 0.001;
},
/**
* Decompose a matrix into separate transform values, for use on platforms
* where applying a precomposed matrix is not possible, and transforms are
* applied in an inflexible ordering (e.g. Android).
*
* Implementation based on
* http://www.w3.org/TR/css3-transforms/#decomposing-a-2d-matrix
* http://www.w3.org/TR/css3-transforms/#decomposing-a-3d-matrix
* which was based on
* http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c
*/
decomposeMatrix(transformMatrix: Array<number>): ?Object {
invariant(
transformMatrix.length === 16,
'Matrix decomposition needs a list of 3d matrix values, received %s',
transformMatrix
);
// output values
var perspective = [];
var quaternion = [];
var scale = [];
var skew = [];
var translation = [];
// create normalized, 2d array matrix
// and normalized 1d array perspectiveMatrix with redefined 4th column
if (!transformMatrix[15]) {
return;
}
var matrix = [];
var perspectiveMatrix = [];
for (var i = 0; i < 4; i++) {
matrix.push([]);
for (var j = 0; j < 4; j++) {
var value = transformMatrix[(i * 4) + j] / transformMatrix[15];
matrix[i].push(value);
perspectiveMatrix.push(j === 3 ? 0 : value);
}
}
perspectiveMatrix[15] = 1;
// test for singularity of upper 3x3 part of the perspective matrix
if (!MatrixMath.determinant(perspectiveMatrix)) {
return;
}
// isolate perspective
if (matrix[0][3] !== 0 || matrix[1][3] !== 0 || matrix[2][3] !== 0) {
// rightHandSide is the right hand side of the equation.
// rightHandSide is a vector, or point in 3d space relative to the origin.
var rightHandSide = [
matrix[0][3],
matrix[1][3],
matrix[2][3],
matrix[3][3]
];
// Solve the equation by inverting perspectiveMatrix and multiplying
// rightHandSide by the inverse.
var inversePerspectiveMatrix = MatrixMath.inverse3x3(
perspectiveMatrix
);
var transposedInversePerspectiveMatrix = MatrixMath.transpose4x4(
inversePerspectiveMatrix
);
var perspective = MatrixMath.multiplyVectorByMatrix(
rightHandSide,
transposedInversePerspectiveMatrix
);
} else {
// no perspective
perspective[0] = perspective[1] = perspective[2] = 0;
perspective[3] = 1;
}
// translation is simple
for (var i = 0; i < 3; i++) {
translation[i] = matrix[3][i];
}
// Now get scale and shear.
// 'row' is a 3 element array of 3 component vectors
var row = [];
for (i = 0; i < 3; i++) {
row[i] = [
matrix[i][0],
matrix[i][1],
matrix[i][2]
];
}
// Compute X scale factor and normalize first row.
scale[0] = MatrixMath.v3Length(row[0]);
row[0] = MatrixMath.v3Normalize(row[0], scale[0]);
// Compute XY shear factor and make 2nd row orthogonal to 1st.
skew[0] = MatrixMath.v3Dot(row[0], row[1]);
row[1] = MatrixMath.v3Combine(row[1], row[0], 1.0, -skew[0]);
// Compute XY shear factor and make 2nd row orthogonal to 1st.
skew[0] = MatrixMath.v3Dot(row[0], row[1]);
row[1] = MatrixMath.v3Combine(row[1], row[0], 1.0, -skew[0]);
// Now, compute Y scale and normalize 2nd row.
scale[1] = MatrixMath.v3Length(row[1]);
row[1] = MatrixMath.v3Normalize(row[1], scale[1]);
skew[0] /= scale[1];
// Compute XZ and YZ shears, orthogonalize 3rd row
skew[1] = MatrixMath.v3Dot(row[0], row[2]);
row[2] = MatrixMath.v3Combine(row[2], row[0], 1.0, -skew[1]);
skew[2] = MatrixMath.v3Dot(row[1], row[2]);
row[2] = MatrixMath.v3Combine(row[2], row[1], 1.0, -skew[2]);
// Next, get Z scale and normalize 3rd row.
scale[2] = MatrixMath.v3Length(row[2]);
row[2] = MatrixMath.v3Normalize(row[2], scale[2]);
skew[1] /= scale[2];
skew[2] /= scale[2];
// At this point, the matrix (in rows) is orthonormal.
// Check for a coordinate system flip. If the determinant
// is -1, then negate the matrix and the scaling factors.
var pdum3 = MatrixMath.v3Cross(row[1], row[2]);
if (MatrixMath.v3Dot(row[0], pdum3) < 0) {
for (i = 0; i < 3; i++) {
scale[i] *= -1;
row[i][0] *= -1;
row[i][1] *= -1;
row[i][2] *= -1;
}
}
// Now, get the rotations out
quaternion[0] =
0.5 * Math.sqrt(Math.max(1 + row[0][0] - row[1][1] - row[2][2], 0));
quaternion[1] =
0.5 * Math.sqrt(Math.max(1 - row[0][0] + row[1][1] - row[2][2], 0));
quaternion[2] =
0.5 * Math.sqrt(Math.max(1 - row[0][0] - row[1][1] + row[2][2], 0));
quaternion[3] =
0.5 * Math.sqrt(Math.max(1 + row[0][0] + row[1][1] + row[2][2], 0));
if (row[2][1] > row[1][2]) {
quaternion[0] = -quaternion[0];
}
if (row[0][2] > row[2][0]) {
quaternion[1] = -quaternion[1];
}
if (row[1][0] > row[0][1]) {
quaternion[2] = -quaternion[2];
}
// correct for occasional, weird Euler synonyms for 2d rotation
var rotationDegrees;
if (
quaternion[0] < 0.001 && quaternion[0] >= 0 &&
quaternion[1] < 0.001 && quaternion[1] >= 0
) {
// this is a 2d rotation on the z-axis
rotationDegrees = [0, 0, MatrixMath.roundTo3Places(
Math.atan2(row[0][1], row[0][0]) * 180 / Math.PI
)];
} else {
rotationDegrees = MatrixMath.quaternionToDegreesXYZ(quaternion, matrix, row);
}
// expose both base data and convenience names
return {
rotationDegrees,
perspective,
quaternion,
scale,
skew,
translation,
rotate: rotationDegrees[2],
scaleX: scale[0],
scaleY: scale[1],
translateX: translation[0],
translateY: translation[1],
};
},
};

View File

@ -81,6 +81,14 @@ var REQUEST_PARAMSS = 2;
var RESPONSE_CBIDS = 3;
var RESPONSE_RETURN_VALUES = 4;
var applyWithErrorReporter = function(fun: Function, context: ?any, args: ?any) {
try {
return fun.apply(context, args);
} catch (e) {
ErrorUtils.reportFatalError(e);
}
};
/**
* Utility to catch errors and prevent having to bind, or execute a bound
* function, while catching errors in a process and returning a resulting
@ -97,10 +105,10 @@ var RESPONSE_RETURN_VALUES = 4;
*/
var guardReturn = function(operation, operationArguments, getReturnValue, context) {
if (operation) {
ErrorUtils.applyWithGuard(operation, context, operationArguments);
applyWithErrorReporter(operation, context, operationArguments);
}
if (getReturnValue) {
return ErrorUtils.applyWithGuard(getReturnValue, context, null);
return applyWithErrorReporter(getReturnValue, context, null);
}
return null;
};

View File

@ -67,9 +67,9 @@ class PixelRatio {
static getPixelSizeForLayoutSize(layoutSize: number): number {
return Math.round(layoutSize * PixelRatio.get());
}
}
// No-op for iOS, but used on the web. Should not be documented.
PixelRatio.startDetecting = function() {};
static startDetecting() {}
}
module.exports = PixelRatio;

View File

@ -0,0 +1,140 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
jest.dontMock('MatrixMath');
jest.dontMock('invariant');
var MatrixMath = require('MatrixMath');
function degreesToRadians(degrees) {
return degrees * Math.PI / 180;
}
describe('MatrixMath', () => {
it('decomposes a 4x4 matrix to produce accurate Z-axis angles', () => {
expect(MatrixMath.decomposeMatrix([
1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
]).rotationDegrees).toEqual([0, 0, 0]);
[30, 45, 60, 75, 90, 100, 115, 120, 133, 167].forEach(angle => {
var mat = MatrixMath.createRotateZ(degreesToRadians(angle));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, 0, angle]);
mat = MatrixMath.createRotateZ(degreesToRadians(-angle));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, 0, -angle]);
});
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(180))
).rotationDegrees).toEqual([0, 0, 180]);
// all values are between 0 and 180;
// change of sign and direction in the third and fourth quadrant
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(222))
).rotationDegrees).toEqual([0, 0, -138]);
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(270))
).rotationDegrees).toEqual([0, 0, -90]);
// 360 is expressed as 0
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(360))
).rotationDegrees).toEqual([0, 0, 0]);
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(33.33333333))
).rotationDegrees).toEqual([0, 0, 33.333]);
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(86.75309))
).rotationDegrees).toEqual([0, 0, 86.753]);
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(42.00000000001))
).rotationDegrees).toEqual([0, 0, 42]);
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(42.99999999999))
).rotationDegrees).toEqual([0, 0, 43]);
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(42.49999999999))
).rotationDegrees).toEqual([0, 0, 42.5]);
expect(MatrixMath.decomposeMatrix(
MatrixMath.createRotateZ(degreesToRadians(42.55555555555))
).rotationDegrees).toEqual([0, 0, 42.556]);
});
it('decomposes a 4x4 matrix to produce accurate Y-axis angles', () => {
var mat;
[30, 45, 60, 75, 90, 100, 110, 120, 133, 167].forEach(angle => {
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateYCommand(mat, degreesToRadians(angle));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, angle, 0]);
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateYCommand(mat, degreesToRadians(-angle));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, -angle, 0]);
});
// all values are between 0 and 180;
// change of sign and direction in the third and fourth quadrant
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateYCommand(mat, degreesToRadians(222));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, -138, 0]);
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateYCommand(mat, degreesToRadians(270));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, -90, 0]);
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateYCommand(mat, degreesToRadians(360));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, 0, 0]);
});
it('decomposes a 4x4 matrix to produce accurate X-axis angles', () => {
var mat;
[30, 45, 60, 75, 90, 100, 110, 120, 133, 167].forEach(angle => {
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateXCommand(mat, degreesToRadians(angle));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([angle, 0, 0]);
});
// all values are between 0 and 180;
// change of sign and direction in the third and fourth quadrant
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateXCommand(mat, degreesToRadians(222));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([-138, 0, 0]);
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateXCommand(mat, degreesToRadians(270));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([-90, 0, 0]);
mat = MatrixMath.createIdentityMatrix();
MatrixMath.reuseRotateXCommand(mat, degreesToRadians(360));
expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
.toEqual([0, 0, 0]);
});
});

View File

@ -183,7 +183,7 @@ var PanResponder = {
* changes* in the centroid of recently moved touches.
*
* There is also some nuance with how we handle multiple moved touches in a
* single event. With the way `ReactIOSEventEmitter` dispatches touches as
* single event. With the way `ReactNativeEventEmitter` dispatches touches as
* individual events, multiple touches generate two 'move' events, each of
* them triggering `onResponderMove`. But with the way `PanResponder` works,
* all of the gesture inference is performed on the first dispatch, since it

View File

@ -2,7 +2,7 @@
* @providesModule UniversalWorkerNodeHandle
*/
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var invariant = require('invariant');
@ -12,7 +12,7 @@ var UniversalWorkerNodeHandle = {
nodeHandle !== undefined && nodeHandle !== null && nodeHandle !== 0,
'No node handle defined'
);
return ReactIOSTagHandles.tagToRootNodeID[nodeHandle];
return ReactNativeTagHandles.tagToRootNodeID[nodeHandle];
}
};

View File

@ -32,6 +32,12 @@ Pod::Spec.new do |s|
ss.frameworks = "JavaScriptCore"
end
s.subspec 'ART' do |ss|
ss.dependency 'React/Core'
ss.source_files = "Libraries/ART/**/*.{h,m}"
ss.preserve_paths = "Libraries/ART/**/*.js"
end
s.subspec 'RCTActionSheet' do |ss|
ss.dependency 'React/Core'
ss.source_files = "Libraries/ActionSheetIOS/*.{h,m}"

View File

@ -789,6 +789,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
* This runs only on the main thread, but crashes the subclass
* RCTAssertMainThread();
*/
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self invalidate];
}
@ -873,15 +874,19 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
return _eventDispatcher ?: _batchedBridge.eventDispatcher;
}
#define RCT_BRIDGE_WARN(...) \
#define RCT_INNER_BRIDGE_ONLY(...) \
- (void)__VA_ARGS__ \
{ \
RCTLogMustFix(@"Called method \"%@\" on top level bridge. This method should \
only be called from bridge instance in a bridge module", @(__func__)); \
}
RCT_BRIDGE_WARN(enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args)
RCT_BRIDGE_WARN(_invokeAndProcessModule:(NSString *)module method:(NSString *)method arguments:(NSArray *)args context:(NSNumber *)context)
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
{
[self.batchedBridge enqueueJSCall:moduleDotMethod args:args];
}
RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSString *)method arguments:(NSArray *)args context:(NSNumber *)context)
@end
@ -1084,7 +1089,16 @@ RCT_BRIDGE_WARN(_invokeAndProcessModule:(NSString *)module method:(NSString *)me
*/
_loading = NO;
} else if (bundleURL) { // Allow testing without a script
} else if (!bundleURL) {
// Allow testing without a script
dispatch_async(dispatch_get_main_queue(), ^{
_loading = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
object:_parentBridge
userInfo:@{ @"bridge": self }];
});
} else {
RCTJavaScriptLoader *loader = [[RCTJavaScriptLoader alloc] initWithBridge:self];
[loader loadBundleAtURL:bundleURL onComplete:^(NSError *error, NSString *script) {
@ -1108,9 +1122,9 @@ RCT_BRIDGE_WARN(_invokeAndProcessModule:(NSString *)module method:(NSString *)me
withDetails:[error localizedFailureReason]];
}
NSDictionary *userInfo = @{@"error": error};
NSDictionary *userInfo = @{@"bridge": self, @"error": error};
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidFailToLoadNotification
object:self
object:_parentBridge
userInfo:userInfo];
} else {
@ -1161,7 +1175,6 @@ RCT_BRIDGE_WARN(_invokeAndProcessModule:(NSString *)module method:(NSString *)me
void (^mainThreadInvalidate)(void) = ^{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_mainDisplayLink invalidate];
_mainDisplayLink = nil;
@ -1499,6 +1512,7 @@ RCT_BRIDGE_WARN(_invokeAndProcessModule:(NSString *)module method:(NSString *)me
@"module": method.moduleClassName,
@"method": method.JSMethodName,
@"selector": NSStringFromSelector(method.selector),
@"args": RCTJSONStringify(params ?: [NSNull null], NULL),
});
} forModule:@(moduleID)];

View File

@ -86,7 +86,7 @@ RCT_EXPORT_MODULE()
object:nil];
[notificationCenter addObserver:self
selector:@selector(jsLoaded)
selector:@selector(jsLoaded:)
name:RCTJavaScriptDidLoadNotification
object:nil];
@ -141,8 +141,12 @@ RCT_EXPORT_MODULE()
self.executorClass = NSClassFromString(_settings[@"executorClass"]);
}
- (void)jsLoaded
- (void)jsLoaded:(NSNotification *)notification
{
if (notification.userInfo[@"bridge"] != _bridge) {
return;
}
_jsLoaded = YES;
// Check if live reloading is available

View File

@ -11,6 +11,7 @@
#import <objc/runtime.h>
#import "RCTAssert.h"
#import "RCTBridge.h"
#import "RCTContextExecutor.h"
#import "RCTEventDispatcher.h"
@ -53,6 +54,7 @@
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
{
RCTAssertMainThread();
RCTAssert(bridge, @"A bridge instance is required to create an RCTRootView");
RCTAssert(moduleName, @"A moduleName is required to create an RCTRootView");
@ -96,7 +98,7 @@
}
RCT_IMPORT_METHOD(AppRegistry, runApplication)
RCT_IMPORT_METHOD(ReactIOS, unmountComponentAtNodeAndRemoveContainer)
RCT_IMPORT_METHOD(ReactNative, unmountComponentAtNodeAndRemoveContainer)
- (void)javaScriptDidLoad:(NSNotification *)notification
@ -150,7 +152,7 @@ RCT_IMPORT_METHOD(ReactIOS, unmountComponentAtNodeAndRemoveContainer)
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_contentView removeFromSuperview];
[_contentView invalidate];
}
@end
@ -212,13 +214,12 @@ RCT_IMPORT_METHOD(ReactIOS, unmountComponentAtNodeAndRemoveContainer)
- (void)invalidate
{
if (self.isValid) {
self.userInteractionEnabled = NO;
}
- (void)dealloc
{
[_bridge enqueueJSCall:@"ReactIOS.unmountComponentAtNodeAndRemoveContainer"
[self removeFromSuperview];
[_bridge enqueueJSCall:@"ReactNative.unmountComponentAtNodeAndRemoveContainer"
args:@[self.reactTag]];
}
}
@end

View File

@ -199,7 +199,7 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
#pragma mark - Gesture Recognizer Delegate Callbacks
static BOOL RCTAllTouchesAreCancelldOrEnded(NSSet *touches)
static BOOL RCTAllTouchesAreCancelledOrEnded(NSSet *touches)
{
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan ||
@ -254,7 +254,7 @@ static BOOL RCTAnyTouchesChanged(NSSet *touches)
[self _updateAndDispatchTouches:touches eventName:@"topTouchEnd" originatingTime:event.timestamp];
[self _recordRemovedTouches:touches];
if (RCTAllTouchesAreCancelldOrEnded(event.allTouches)) {
if (RCTAllTouchesAreCancelledOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateEnded;
} else if (RCTAnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
@ -267,7 +267,7 @@ static BOOL RCTAnyTouchesChanged(NSSet *touches)
[self _updateAndDispatchTouches:touches eventName:@"topTouchCancel" originatingTime:event.timestamp];
[self _recordRemovedTouches:touches];
if (RCTAllTouchesAreCancelldOrEnded(event.allTouches)) {
if (RCTAllTouchesAreCancelledOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateCancelled;
} else if (RCTAnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;

View File

@ -1,15 +1,20 @@
/**
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !! This file is a check-in from github! !!
* !! !!
* !! You should not modify this file directly. Instead: !!
* !! 1) Go to https://github.com/facebook/css-layout !!
* !! 2) Make a pull request and get it merged !!
* !! 3) Execute ./import.sh to pull in the latest version !!
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* Copyright (c) 2014, 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.
*
* WARNING: You should not modify this file directly. Instead:
* 1) Go to https://github.com/facebook/css-layout
* 2) Make a pull request and get it merged
* 3) Run import.sh to copy Layout.* to react-native-github
*/
#include <math.h>
@ -38,12 +43,6 @@ void init_css_node(css_node_t *node) {
node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
node->style.minDimensions[CSS_WIDTH] = CSS_UNDEFINED;
node->style.minDimensions[CSS_HEIGHT] = CSS_UNDEFINED;
node->style.maxDimensions[CSS_WIDTH] = CSS_UNDEFINED;
node->style.maxDimensions[CSS_HEIGHT] = CSS_UNDEFINED;
node->style.position[CSS_LEFT] = CSS_UNDEFINED;
node->style.position[CSS_TOP] = CSS_UNDEFINED;
node->style.position[CSS_RIGHT] = CSS_UNDEFINED;
@ -249,10 +248,6 @@ static float getPaddingAndBorder(css_node_t *node, int location) {
return getPadding(node, location) + getBorder(node, location);
}
static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) {
return getBorder(node, leading[axis]) + getBorder(node, trailing[axis]);
}
static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) {
return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]);
}
@ -302,8 +297,7 @@ static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) {
}
static bool isDimDefined(css_node_t *node, css_flex_direction_t axis) {
float value = node->style.dimensions[dim[axis]];
return !isUndefined(value) && value > 0.0;
return !isUndefined(node->style.dimensions[dim[axis]]);
}
static bool isPosDefined(css_node_t *node, css_position_t position) {
@ -322,30 +316,6 @@ static float getPosition(css_node_t *node, css_position_t position) {
return 0;
}
static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value) {
float min = CSS_UNDEFINED;
float max = CSS_UNDEFINED;
if (axis == CSS_FLEX_DIRECTION_COLUMN) {
min = node->style.minDimensions[CSS_HEIGHT];
max = node->style.maxDimensions[CSS_HEIGHT];
} else if (axis == CSS_FLEX_DIRECTION_ROW) {
min = node->style.minDimensions[CSS_WIDTH];
max = node->style.maxDimensions[CSS_WIDTH];
}
float boundValue = value;
if (!isUndefined(max) && max >= 0.0 && boundValue > max) {
boundValue = max;
}
if (!isUndefined(min) && min >= 0.0 && boundValue < min) {
boundValue = min;
}
return boundValue;
}
// When the user specifically sets a value for width or height
static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) {
// The parent already computed us a width or height. We just skip it
@ -359,7 +329,7 @@ static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) {
// The dimensions can never be smaller than the padding and border
node->layout.dimensions[dim[axis]] = fmaxf(
boundAxis(node, axis, node->style.dimensions[dim[axis]]),
node->style.dimensions[dim[axis]],
getPaddingAndBorderAxis(node, axis)
);
}
@ -376,7 +346,6 @@ static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) {
static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
/** START_GENERATED **/
css_flex_direction_t mainAxis = getFlexDirection(node);
css_flex_direction_t crossAxis = mainAxis == CSS_FLEX_DIRECTION_ROW ?
CSS_FLEX_DIRECTION_COLUMN :
@ -415,31 +384,25 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// Let's not measure the text if we already know both dimensions
if (isRowUndefined || isColumnUndefined) {
css_dim_t measureDim = node->measure(
css_dim_t measure_dim = node->measure(
node->context,
width
);
if (isRowUndefined) {
node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] +
node->layout.dimensions[CSS_WIDTH] = measure_dim.dimensions[CSS_WIDTH] +
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
}
if (isColumnUndefined) {
node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] +
node->layout.dimensions[CSS_HEIGHT] = measure_dim.dimensions[CSS_HEIGHT] +
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
}
}
return;
}
int i;
int ii;
css_node_t* child;
css_flex_direction_t axis;
// Pre-fill some dimensions straight from the parent
for (i = 0; i < node->children_count; ++i) {
child = node->get_child(node->context, i);
for (int i = 0; i < node->children_count; ++i) {
css_node_t* child = node->get_child(node->context, i);
// Pre-fill cross axis dimensions when the child is using stretch before
// we call the recursive layout pass
if (getAlignItem(node, child) == CSS_ALIGN_STRETCH &&
@ -447,27 +410,27 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
!isUndefined(node->layout.dimensions[dim[crossAxis]]) &&
!isDimDefined(child, crossAxis)) {
child->layout.dimensions[dim[crossAxis]] = fmaxf(
boundAxis(child, crossAxis, node->layout.dimensions[dim[crossAxis]] -
node->layout.dimensions[dim[crossAxis]] -
getPaddingAndBorderAxis(node, crossAxis) -
getMarginAxis(child, crossAxis)),
getMarginAxis(child, crossAxis),
// You never want to go smaller than padding
getPaddingAndBorderAxis(child, crossAxis)
);
} else if (getPositionType(child) == CSS_POSITION_ABSOLUTE) {
// Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both
// left and right or top and bottom).
for (ii = 0; ii < 2; ii++) {
axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
for (int ii = 0; ii < 2; ii++) {
css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
if (!isUndefined(node->layout.dimensions[dim[axis]]) &&
!isDimDefined(child, axis) &&
isPosDefined(child, leading[axis]) &&
isPosDefined(child, trailing[axis])) {
child->layout.dimensions[dim[axis]] = fmaxf(
boundAxis(child, axis, node->layout.dimensions[dim[axis]] -
node->layout.dimensions[dim[axis]] -
getPaddingAndBorderAxis(node, axis) -
getMarginAxis(child, axis) -
getPosition(child, leading[axis]) -
getPosition(child, trailing[axis])),
getPosition(child, trailing[axis]),
// You never want to go smaller than padding
getPaddingAndBorderAxis(child, axis)
);
@ -485,12 +448,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// We want to execute the next two loops one per line with flex-wrap
int startLine = 0;
int endLine = 0;
// int nextOffset = 0;
int alreadyComputedNextLayout = 0;
int nextLine = 0;
// We aggregate the total dimensions of the container in those two variables
float linesCrossDim = 0;
float linesMainDim = 0;
while (endLine < node->children_count) {
while (endLine != node->children_count) {
// <Loop A> Layout non flexible children and count children by type
// mainContentDim is accumulation of the dimensions and margin of all the
@ -504,10 +466,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
int flexibleChildrenCount = 0;
float totalFlexible = 0;
int nonFlexibleChildrenCount = 0;
float maxWidth;
for (i = startLine; i < node->children_count; ++i) {
child = node->get_child(node->context, i);
for (int i = startLine; i < node->children_count; ++i) {
css_node_t* child = node->get_child(node->context, i);
float nextContentDim = 0;
// It only makes sense to consider a child flexible if we have a computed
@ -517,27 +477,26 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
totalFlexible += getFlex(child);
// Even if we don't know its exact size yet, we already know the padding,
// border and margin. We'll use this partial information, which represents
// the smallest possible size for the child, to compute the remaining
// available space.
// border and margin. We'll use this partial information to compute the
// remaining space.
nextContentDim = getPaddingAndBorderAxis(child, mainAxis) +
getMarginAxis(child, mainAxis);
} else {
maxWidth = CSS_UNDEFINED;
if (mainAxis != CSS_FLEX_DIRECTION_ROW) {
float maxWidth = CSS_UNDEFINED;
if (mainAxis == CSS_FLEX_DIRECTION_ROW) {
// do nothing
} else if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
} else {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
}
}
// This is the main recursive call. We layout non flexible children.
if (alreadyComputedNextLayout == 0) {
if (nextLine == 0) {
layoutNode(child, maxWidth);
}
@ -553,14 +512,12 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// The element we are about to add would make us go to the next line
if (isFlexWrap(node) &&
!isUndefined(node->layout.dimensions[dim[mainAxis]]) &&
mainContentDim + nextContentDim > definedMainDim &&
// If there's only one element, then it's bigger than the content
// and needs its own line
i != startLine) {
alreadyComputedNextLayout = 1;
mainContentDim + nextContentDim > definedMainDim) {
nonFlexibleChildrenCount--;
nextLine = i + 1;
break;
}
alreadyComputedNextLayout = 0;
nextLine = 0;
mainContentDim += nextContentDim;
endLine = i + 1;
}
@ -585,26 +542,6 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// remaining space
if (flexibleChildrenCount != 0) {
float flexibleMainDim = remainingMainDim / totalFlexible;
float baseMainDim;
float boundMainDim;
// Iterate over every child in the axis. If the flex share of remaining
// space doesn't meet min/max bounds, remove this child from flex
// calculations.
for (i = startLine; i < endLine; ++i) {
child = node->get_child(node->context, i);
if (isFlex(child)) {
baseMainDim = flexibleMainDim * getFlex(child) +
getPaddingAndBorderAxis(child, mainAxis);
boundMainDim = boundAxis(child, mainAxis, baseMainDim);
if (baseMainDim != boundMainDim) {
remainingMainDim -= boundMainDim;
totalFlexible -= getFlex(child);
}
}
}
flexibleMainDim = remainingMainDim / totalFlexible;
// The non flexible children can overflow the container, in this case
// we should just assume that there is no space available.
@ -614,20 +551,21 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// We iterate over the full array and only apply the action on flexible
// children. This is faster than actually allocating a new array that
// contains only flexible children.
for (i = startLine; i < endLine; ++i) {
child = node->get_child(node->context, i);
for (int i = startLine; i < endLine; ++i) {
css_node_t* child = node->get_child(node->context, i);
if (isFlex(child)) {
// At this point we know the final size of the element in the main
// dimension
child->layout.dimensions[dim[mainAxis]] = boundAxis(child, mainAxis,
flexibleMainDim * getFlex(child) + getPaddingAndBorderAxis(child, mainAxis)
);
child->layout.dimensions[dim[mainAxis]] = flexibleMainDim * getFlex(child) +
getPaddingAndBorderAxis(child, mainAxis);
maxWidth = CSS_UNDEFINED;
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
float maxWidth = CSS_UNDEFINED;
if (mainAxis == CSS_FLEX_DIRECTION_ROW) {
// do nothing
} else if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
} else if (mainAxis != CSS_FLEX_DIRECTION_ROW) {
} else {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
@ -642,7 +580,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// space available
} else {
css_justify_t justifyContent = getJustifyContent(node);
if (justifyContent == CSS_JUSTIFY_CENTER) {
if (justifyContent == CSS_JUSTIFY_FLEX_START) {
// Do nothing
} else if (justifyContent == CSS_JUSTIFY_CENTER) {
leadingMainDim = remainingMainDim / 2;
} else if (justifyContent == CSS_JUSTIFY_FLEX_END) {
leadingMainDim = remainingMainDim;
@ -672,8 +612,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
float mainDim = leadingMainDim +
getPaddingAndBorder(node, leading[mainAxis]);
for (i = startLine; i < endLine; ++i) {
child = node->get_child(node->context, i);
for (int i = startLine; i < endLine; ++i) {
css_node_t* child = node->get_child(node->context, i);
if (getPositionType(child) == CSS_POSITION_ABSOLUTE &&
isPosDefined(child, leading[mainAxis])) {
@ -698,7 +638,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
// The cross dimension is the max of the elements dimension since there
// can only be one element in that cross dimension.
crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis)));
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
}
}
@ -708,15 +648,15 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// For the cross dim, we add both sides at the end because the value
// is aggregate via a max function. Intermediate negative values
// can mess this computation otherwise
boundAxis(node, crossAxis, crossDim + getPaddingAndBorderAxis(node, crossAxis)),
crossDim + getPaddingAndBorderAxis(node, crossAxis),
getPaddingAndBorderAxis(node, crossAxis)
);
}
// <Loop D> Position elements in the cross axis
for (i = startLine; i < endLine; ++i) {
child = node->get_child(node->context, i);
for (int i = startLine; i < endLine; ++i) {
css_node_t* child = node->get_child(node->context, i);
if (getPositionType(child) == CSS_POSITION_ABSOLUTE &&
isPosDefined(child, leading[crossAxis])) {
@ -734,19 +674,21 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// alignSelf (child) in order to determine the position in the cross axis
if (getPositionType(child) == CSS_POSITION_RELATIVE) {
css_align_t alignItem = getAlignItem(node, child);
if (alignItem == CSS_ALIGN_STRETCH) {
if (alignItem == CSS_ALIGN_FLEX_START) {
// Do nothing
} else if (alignItem == CSS_ALIGN_STRETCH) {
// You can only stretch if the dimension has not already been set
// previously.
if (!isDimDefined(child, crossAxis)) {
child->layout.dimensions[dim[crossAxis]] = fmaxf(
boundAxis(child, crossAxis, containerCrossAxis -
containerCrossAxis -
getPaddingAndBorderAxis(node, crossAxis) -
getMarginAxis(child, crossAxis)),
getMarginAxis(child, crossAxis),
// You never want to go smaller than padding
getPaddingAndBorderAxis(child, crossAxis)
);
}
} else if (alignItem != CSS_ALIGN_FLEX_START) {
} else {
// The remaining space between the parent dimensions+padding and child
// dimensions+margin.
float remainingCrossDim = containerCrossAxis -
@ -777,7 +719,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
node->layout.dimensions[dim[mainAxis]] = fmaxf(
// We're missing the last padding at this point to get the final
// dimension
boundAxis(node, mainAxis, linesMainDim + getPaddingAndBorder(node, trailing[mainAxis])),
linesMainDim + getPaddingAndBorder(node, trailing[mainAxis]),
// We can never assign a width smaller than the padding and borders
getPaddingAndBorderAxis(node, mainAxis)
);
@ -788,38 +730,37 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// For the cross dim, we add both sides at the end because the value
// is aggregate via a max function. Intermediate negative values
// can mess this computation otherwise
boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)),
linesCrossDim + getPaddingAndBorderAxis(node, crossAxis),
getPaddingAndBorderAxis(node, crossAxis)
);
}
// <Loop E> Calculate dimensions for absolutely positioned elements
for (i = 0; i < node->children_count; ++i) {
child = node->get_child(node->context, i);
for (int i = 0; i < node->children_count; ++i) {
css_node_t* child = node->get_child(node->context, i);
if (getPositionType(child) == CSS_POSITION_ABSOLUTE) {
// Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both
// left and right or top and bottom).
for (ii = 0; ii < 2; ii++) {
axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
for (int ii = 0; ii < 2; ii++) {
css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
if (!isUndefined(node->layout.dimensions[dim[axis]]) &&
!isDimDefined(child, axis) &&
isPosDefined(child, leading[axis]) &&
isPosDefined(child, trailing[axis])) {
child->layout.dimensions[dim[axis]] = fmaxf(
boundAxis(child, axis, node->layout.dimensions[dim[axis]] -
getBorderAxis(node, axis) -
node->layout.dimensions[dim[axis]] -
getPaddingAndBorderAxis(node, axis) -
getMarginAxis(child, axis) -
getPosition(child, leading[axis]) -
getPosition(child, trailing[axis])
),
getPosition(child, trailing[axis]),
// You never want to go smaller than padding
getPaddingAndBorderAxis(child, axis)
);
}
}
for (ii = 0; ii < 2; ii++) {
axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
for (int ii = 0; ii < 2; ii++) {
css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
if (isPosDefined(child, trailing[axis]) &&
!isPosDefined(child, leading[axis])) {
child->layout.position[leading[axis]] =

View File

@ -1,15 +1,21 @@
/**
* @generated SignedSource<<58298c7a8815a8675e970b0347dedfed>>
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !! This file is a check-in from github! !!
* !! !!
* !! You should not modify this file directly. Instead: !!
* !! 1) Go to https://github.com/facebook/css-layout !!
* !! 2) Make a pull request and get it merged !!
* !! 3) Execute ./import.sh to pull in the latest version !!
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* Copyright (c) 2014, 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.
*
* WARNING: You should not modify this file directly. Instead:
* 1) Go to https://github.com/facebook/css-layout
* 2) Make a pull request and get it merged
* 3) Run import.sh to copy Layout.* to react-native-github
*/
#ifndef __LAYOUT_H
@ -107,8 +113,6 @@ typedef struct {
float padding[4];
float border[4];
float dimensions[2];
float minDimensions[2];
float maxDimensions[2];
} css_style_t;
typedef struct css_node {

View File

@ -1,15 +0,0 @@
LAYOUT_C=`curl https://raw.githubusercontent.com/facebook/css-layout/master/src/Layout.c`
LAYOUT_H=`curl https://raw.githubusercontent.com/facebook/css-layout/master/src/Layout.h`
REPLACE_STRING="*
* WARNING: You should not modify this file directly. Instead:
* 1) Go to https://github.com/facebook/css-layout
* 2) Make a pull request and get it merged
* 3) Run import.sh to copy Layout.* to react-native-github
*/"
LAYOUT_C=${LAYOUT_C/\*\//$REPLACE_STRING}
LAYOUT_H=${LAYOUT_H/\*\//$REPLACE_STRING}
echo "$LAYOUT_C" > Layout.c
echo "$LAYOUT_H" > Layout.h

View File

@ -59,6 +59,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
{
NSString *title = args[@"title"];
NSString *message = args[@"message"];
NSString *type = args[@"type"];
NSArray *buttons = args[@"buttons"];
if (!title && !message) {
@ -70,13 +71,20 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
}
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:message
message:nil
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
NSMutableArray *buttonKeys = [[NSMutableArray alloc] initWithCapacity:buttons.count];
if ([type isEqualToString:@"plain-text"]) {
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
[alertView textFieldAtIndex:0].text = message;
} else {
alertView.message = message;
}
NSInteger index = 0;
for (NSDictionary *button in buttons) {
if (button.count != 1) {
@ -108,7 +116,15 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
RCTResponseSenderBlock callback = _alertCallbacks[index];
NSArray *buttonKeys = _alertButtonKeys[index];
callback(@[buttonKeys[buttonIndex]]);
NSArray *args;
if (alertView.alertViewStyle == UIAlertViewStylePlainTextInput) {
args = @[buttonKeys[buttonIndex], [alertView textFieldAtIndex:0].text];
} else {
args = @[buttonKeys[buttonIndex]];
}
callback(args);
[_alerts removeObjectAtIndex:index];
[_alertCallbacks removeObjectAtIndex:index];

View File

@ -13,7 +13,9 @@
@protocol RCTExceptionsManagerDelegate <NSObject>
- (void)unhandledJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack;
- (void)handleSoftJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack;
- (void)handleFatalJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack;
- (void)updateJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack;
@end

View File

@ -36,11 +36,23 @@ RCT_EXPORT_MODULE()
return [self initWithDelegate:nil];
}
RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message
RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
stack:(NSArray *)stack)
{
// TODO(#7070533): report a soft error to the server
if (_delegate) {
[_delegate handleSoftJSExceptionWithMessage:message stack:stack];
return;
}
[[RCTRedBox sharedInstance] showErrorMessage:message withStack:stack];
}
RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
stack:(NSArray *)stack)
{
if (_delegate) {
[_delegate unhandledJSExceptionWithMessage:message stack:stack];
[_delegate handleFatalJSExceptionWithMessage:message stack:stack];
return;
}
@ -78,11 +90,17 @@ RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message
stack:(NSArray *)stack)
{
if (_delegate) {
[_delegate unhandledJSExceptionWithMessage:message stack:stack];
[_delegate updateJSExceptionWithMessage:message stack:stack];
return;
}
[[RCTRedBox sharedInstance] updateErrorMessage:message withStack:stack];
}
// Deprecated. Use reportFatalException directly instead.
RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message
stack:(NSArray *)stack)
{
[self reportFatalException:message stack:stack];
}
@end

View File

@ -281,7 +281,7 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
dispatch_async(dispatch_get_main_queue(), ^{
for (NSNumber *rootViewTag in _rootViewTags) {
((UIView *)_viewRegistry[rootViewTag]).userInteractionEnabled = NO;
[_viewRegistry[rootViewTag] invalidate];
}
_rootViewTags = nil;

View File

@ -294,6 +294,12 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
_scrollView.stickyHeaderIndices = headerIndices;
}
- (void)setClipsToBounds:(BOOL)clipsToBounds
{
[super setClipsToBounds:clipsToBounds];
[_scrollView setClipsToBounds:clipsToBounds];
}
- (void)dealloc
{
_scrollView.delegate = nil;

View File

@ -48,6 +48,15 @@
*/
- (void)updateClippedSubviews;
/**
* Border radii.
*/
@property (nonatomic, assign) CGFloat borderRadius;
@property (nonatomic, assign) CGFloat borderTopLeftRadius;
@property (nonatomic, assign) CGFloat borderTopRightRadius;
@property (nonatomic, assign) CGFloat borderBottomLeftRadius;
@property (nonatomic, assign) CGFloat borderBottomRightRadius;
/**
* Border colors.
*/

View File

@ -15,8 +15,6 @@
#import "RCTUtils.h"
#import "UIView+React.h"
static void *RCTViewCornerRadiusKVOContext = &RCTViewCornerRadiusKVOContext;
static UIView *RCTViewHitTest(UIView *view, CGPoint point, UIEvent *event)
{
for (UIView *subview in [view.subviews reverseObjectEnumerator]) {
@ -123,30 +121,18 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
_borderRightWidth = -1;
_borderBottomWidth = -1;
_borderLeftWidth = -1;
_borderTopLeftRadius = -1;
_borderTopRightRadius = -1;
_borderBottomLeftRadius = -1;
_borderBottomRightRadius = -1;
_backgroundColor = [super backgroundColor];
[super setBackgroundColor:[UIColor clearColor]];
[self.layer addObserver:self forKeyPath:@"cornerRadius" options:0 context:RCTViewCornerRadiusKVOContext];
}
return self;
}
- (void)dealloc
{
[self.layer removeObserver:self forKeyPath:@"cornerRadius" context:RCTViewCornerRadiusKVOContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == RCTViewCornerRadiusKVOContext) {
[self.layer setNeedsDisplay];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (NSString *)accessibilityLabel
{
if (super.accessibilityLabel) {
@ -437,8 +423,12 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
- (UIImage *)generateBorderImage:(out CGRect *)contentsCenter
{
const CGFloat maxRadius = MIN(self.bounds.size.height, self.bounds.size.width) / 2.0;
const CGFloat radius = MAX(0, MIN(self.layer.cornerRadius, maxRadius));
const CGFloat maxRadius = MIN(self.bounds.size.height, self.bounds.size.width);
const CGFloat radius = MAX(0, _borderRadius);
const CGFloat topLeftRadius = MIN(_borderTopLeftRadius >= 0 ? _borderTopLeftRadius : radius, maxRadius);
const CGFloat topRightRadius = MIN(_borderTopRightRadius >= 0 ? _borderTopRightRadius : radius, maxRadius);
const CGFloat bottomLeftRadius = MIN(_borderBottomLeftRadius >= 0 ? _borderBottomLeftRadius : radius, maxRadius);
const CGFloat bottomRightRadius = MIN(_borderBottomRightRadius >= 0 ? _borderBottomRightRadius : radius, maxRadius);
const CGFloat borderWidth = MAX(0, _borderWidth);
const CGFloat topWidth = _borderTopWidth >= 0 ? _borderTopWidth : borderWidth;
@ -446,20 +436,26 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
const CGFloat bottomWidth = _borderBottomWidth >= 0 ? _borderBottomWidth : borderWidth;
const CGFloat leftWidth = _borderLeftWidth >= 0 ? _borderLeftWidth : borderWidth;
const CGFloat topRadius = MAX(0, radius - topWidth);
const CGFloat rightRadius = MAX(0, radius - rightWidth);
const CGFloat bottomRadius = MAX(0, radius - bottomWidth);
const CGFloat leftRadius = MAX(0, radius - leftWidth);
const CGFloat innerTopLeftRadiusX = MAX(0, topLeftRadius - leftWidth);
const CGFloat innerTopLeftRadiusY = MAX(0, topLeftRadius - topWidth);
const UIEdgeInsets edgeInsets = UIEdgeInsetsMake(topWidth + topRadius, leftWidth + leftRadius, bottomWidth + bottomRadius, rightWidth + rightRadius);
const CGFloat innerTopRightRadiusX = MAX(0, topRightRadius - rightWidth);
const CGFloat innerTopRightRadiusY = MAX(0, topRightRadius - topWidth);
const CGFloat innerBottomLeftRadiusX = MAX(0, bottomLeftRadius - leftWidth);
const CGFloat innerBottomLeftRadiusY = MAX(0, bottomLeftRadius - bottomWidth);
const CGFloat innerBottomRightRadiusX = MAX(0, bottomRightRadius - rightWidth);
const CGFloat innerBottomRightRadiusY = MAX(0, bottomRightRadius - bottomWidth);
const UIEdgeInsets edgeInsets = UIEdgeInsetsMake(topWidth + MAX(innerTopLeftRadiusY, innerTopRightRadiusY), leftWidth + MAX(innerTopLeftRadiusX, innerBottomLeftRadiusX), bottomWidth + MAX(innerBottomLeftRadiusY, innerBottomRightRadiusY), rightWidth + + MAX(innerBottomRightRadiusX, innerTopRightRadiusX));
const CGSize size = CGSizeMake(edgeInsets.left + 1 + edgeInsets.right, edgeInsets.top + 1 + edgeInsets.bottom);
UIScreen *screen = self.window.screen ?: [UIScreen mainScreen];
UIGraphicsBeginImageContextWithOptions(size, NO, screen.scale * 2);
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
const CGRect rect = {CGPointZero, size};
CGPathRef path = CGPathCreateWithRoundedRect(rect, radius, radius, NULL);
CGPathRef path = RCTPathCreateWithRoundedRect(rect, topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, bottomLeftRadius, bottomLeftRadius, bottomRightRadius, bottomRightRadius, NULL);
if (_backgroundColor) {
CGContextSaveGState(ctx);
@ -474,10 +470,11 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
CGContextAddPath(ctx, path);
CGPathRelease(path);
if (radius > 0 && topWidth > 0 && rightWidth > 0 && bottomWidth > 0 && leftWidth > 0) {
BOOL hasRadius = topLeftRadius > 0 || topRightRadius > 0 || bottomLeftRadius > 0 || bottomRightRadius > 0;
if (hasRadius && topWidth > 0 && rightWidth > 0 && bottomWidth > 0 && leftWidth > 0) {
const UIEdgeInsets insetEdgeInsets = UIEdgeInsetsMake(topWidth, leftWidth, bottomWidth, rightWidth);
const CGRect insetRect = UIEdgeInsetsInsetRect(rect, insetEdgeInsets);
CGPathRef insetPath = RCTPathCreateWithRoundedRect(insetRect, leftRadius, topRadius, rightRadius, topRadius, leftRadius, bottomRadius, rightRadius, bottomRadius, NULL);
CGPathRef insetPath = RCTPathCreateWithRoundedRect(insetRect, innerTopLeftRadiusX, innerTopLeftRadiusY, innerTopRightRadiusX, innerTopRightRadiusY, innerBottomLeftRadiusX, innerBottomLeftRadiusY, innerBottomRightRadiusX, innerBottomRightRadiusY, NULL);
CGContextAddPath(ctx, insetPath);
CGPathRelease(insetPath);
}
@ -486,12 +483,12 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
BOOL hasEqualColor = !_borderTopColor && !_borderRightColor && !_borderBottomColor && !_borderLeftColor;
BOOL hasEqualBorder = _borderWidth >= 0 && _borderTopWidth < 0 && _borderRightWidth < 0 && _borderBottomWidth < 0 && _borderLeftWidth < 0;
if (radius <= 0 && hasEqualBorder && hasEqualColor) {
if (!hasRadius && hasEqualBorder && hasEqualColor) {
CGContextSetStrokeColorWithColor(ctx, _borderColor);
CGContextSetLineWidth(ctx, 2 * _borderWidth);
CGContextClipToRect(ctx, rect);
CGContextStrokeRect(ctx, rect);
} else if (radius <= 0 && hasEqualColor) {
} else if (!hasRadius && hasEqualColor) {
CGContextSetFillColorWithColor(ctx, _borderColor);
CGContextAddRect(ctx, rect);
const CGRect insetRect = UIEdgeInsetsInsetRect(rect, edgeInsets);
@ -500,9 +497,9 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
} else {
BOOL didSet = NO;
CGPoint topLeft;
if (topRadius > 0 && leftRadius > 0) {
if (innerTopLeftRadiusX > 0 && innerTopLeftRadiusY > 0) {
CGPoint points[2];
RCTEllipseGetIntersectionsWithLine(CGRectMake(leftWidth, topWidth, 2 * leftRadius, 2 * topRadius), CGPointMake(0, 0), CGPointMake(leftWidth, topWidth), points);
RCTEllipseGetIntersectionsWithLine(CGRectMake(leftWidth, topWidth, 2 * innerTopLeftRadiusX, 2 * innerTopLeftRadiusY), CGPointMake(0, 0), CGPointMake(leftWidth, topWidth), points);
if (!isnan(points[1].x) && !isnan(points[1].y)) {
topLeft = points[1];
didSet = YES;
@ -515,9 +512,9 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
didSet = NO;
CGPoint bottomLeft;
if (bottomRadius > 0 && leftRadius > 0) {
if (innerBottomLeftRadiusX > 0 && innerBottomLeftRadiusY > 0) {
CGPoint points[2];
RCTEllipseGetIntersectionsWithLine(CGRectMake(leftWidth, (size.height - bottomWidth) - 2 * bottomRadius, 2 * leftRadius, 2 * bottomRadius), CGPointMake(0, size.height), CGPointMake(leftWidth, size.height - bottomWidth), points);
RCTEllipseGetIntersectionsWithLine(CGRectMake(leftWidth, (size.height - bottomWidth) - 2 * innerBottomLeftRadiusY, 2 * innerBottomLeftRadiusX, 2 * innerBottomLeftRadiusY), CGPointMake(0, size.height), CGPointMake(leftWidth, size.height - bottomWidth), points);
if (!isnan(points[1].x) && !isnan(points[1].y)) {
bottomLeft = points[1];
didSet = YES;
@ -530,9 +527,9 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
didSet = NO;
CGPoint topRight;
if (topRadius > 0 && rightRadius > 0) {
if (innerTopRightRadiusX > 0 && innerTopRightRadiusY > 0) {
CGPoint points[2];
RCTEllipseGetIntersectionsWithLine(CGRectMake((size.width - rightWidth) - 2 * rightRadius, topWidth, 2 * rightRadius, 2 * topRadius), CGPointMake(size.width, 0), CGPointMake(size.width - rightWidth, topWidth), points);
RCTEllipseGetIntersectionsWithLine(CGRectMake((size.width - rightWidth) - 2 * innerTopRightRadiusX, topWidth, 2 * innerTopRightRadiusX, 2 * innerTopRightRadiusY), CGPointMake(size.width, 0), CGPointMake(size.width - rightWidth, topWidth), points);
if (!isnan(points[0].x) && !isnan(points[0].y)) {
topRight = points[0];
didSet = YES;
@ -545,9 +542,9 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
didSet = NO;
CGPoint bottomRight;
if (bottomRadius > 0 && rightRadius > 0) {
if (innerBottomRightRadiusX > 0 && innerBottomRightRadiusY > 0) {
CGPoint points[2];
RCTEllipseGetIntersectionsWithLine(CGRectMake((size.width - rightWidth) - 2 * rightRadius, (size.height - bottomWidth) - 2 * bottomRadius, 2 * rightRadius, 2 * bottomRadius), CGPointMake(size.width, size.height), CGPointMake(size.width - rightWidth, size.height - bottomWidth), points);
RCTEllipseGetIntersectionsWithLine(CGRectMake((size.width - rightWidth) - 2 * innerBottomRightRadiusX, (size.height - bottomWidth) - 2 * innerBottomRightRadiusY, 2 * innerBottomRightRadiusX, 2 * innerBottomRightRadiusY), CGPointMake(size.width, size.height), CGPointMake(size.width - rightWidth, size.height - bottomWidth), points);
if (!isnan(points[0].x) && !isnan(points[0].y)) {
bottomRight = points[0];
didSet = YES;
@ -695,6 +692,22 @@ setBorderWidth(Right)
setBorderWidth(Bottom)
setBorderWidth(Left)
#define setBorderRadius(side) \
- (void)setBorder##side##Radius:(CGFloat)border##side##Radius \
{ \
if (_border##side##Radius == border##side##Radius) { \
return; \
} \
_border##side##Radius = border##side##Radius; \
[self.layer setNeedsDisplay]; \
}
setBorderRadius()
setBorderRadius(TopLeft)
setBorderRadius(TopRight)
setBorderRadius(BottomLeft)
setBorderRadius(BottomRight)
@end
static void RCTPathAddEllipticArc(CGMutablePathRef path, const CGAffineTransform *m, CGFloat x, CGFloat y, CGFloat xRadius, CGFloat yRadius, CGFloat startAngle, CGFloat endAngle, bool clockwise)

View File

@ -113,7 +113,23 @@ RCT_CUSTOM_VIEW_PROPERTY(removeClippedSubviews, BOOL, RCTView)
view.removeClippedSubviews = json ? [RCTConvert BOOL:json] : defaultView.removeClippedSubviews;
}
}
RCT_REMAP_VIEW_PROPERTY(borderRadius, layer.cornerRadius, CGFloat)
RCT_CUSTOM_VIEW_PROPERTY(borderRadius, CGFloat, RCTView) {
if ([view respondsToSelector:@selector(setBorderRadius:)]) {
if (json) {
view.borderRadius = [RCTConvert CGFloat:json];
} else if ([view respondsToSelector:@selector(borderRadius)]) {
view.borderRadius = [defaultView borderRadius];
} else {
view.borderRadius = defaultView.layer.cornerRadius;
}
} else {
if (json) {
view.layer.cornerRadius = [RCTConvert CGFloat:json];
} else {
view.layer.cornerRadius = defaultView.layer.cornerRadius;
}
}
}
RCT_CUSTOM_VIEW_PROPERTY(borderColor, CGColor, RCTView)
{
if ([view respondsToSelector:@selector(setBorderColor:)]) {
@ -150,6 +166,19 @@ RCT_VIEW_BORDER_PROPERTY(Right)
RCT_VIEW_BORDER_PROPERTY(Bottom)
RCT_VIEW_BORDER_PROPERTY(Left)
#define RCT_VIEW_BORDER_RADIUS_PROPERTY(SIDE) \
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Radius, CGFloat, RCTView) \
{ \
if ([view respondsToSelector:@selector(setBorder##SIDE##Radius:)]) { \
view.border##SIDE##Radius = json ? [RCTConvert CGFloat:json] : defaultView.border##SIDE##Radius; \
} \
} \
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopLeft)
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopRight)
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomLeft)
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomRight)
#pragma mark - ShadowView properties
RCT_EXPORT_SHADOW_PROPERTY(top, CGFloat);

View File

@ -63,12 +63,12 @@
"stacktrace-parser": "git://github.com/frantic/stacktrace-parser.git#493c5e5638",
"uglify-js": "~2.4.16",
"underscore": "1.7.0",
"worker-farm": "1.1.0",
"worker-farm": "^1.3.0",
"ws": "0.4.31",
"yargs": "1.3.2"
},
"devDependencies": {
"jest-cli": "0.2.1",
"jest-cli": "0.4.3",
"eslint": "0.9.2"
}
}

View File

@ -1,10 +1,13 @@
'use strict';
jest
.dontMock('path')
.dontMock('../../lib/getAssetDataFromName')
.dontMock('../');
jest
.mock('crypto')
.mock('fs');
var Promise = require('bluebird');
describe('AssetServer', function() {

View File

@ -10,13 +10,14 @@
jest
.dontMock('../index')
.dontMock('path')
.dontMock('absolute-path')
.dontMock('../docblock')
.dontMock('../../replacePatterns')
.dontMock('../../../../lib/getAssetDataFromName')
.setMock('../../../ModuleDescriptor', function(data) {return data;});
jest.mock('fs');
describe('DependencyGraph', function() {
var DependencyGraph;
var fileWatcher;

View File

@ -13,6 +13,8 @@ jest.dontMock('../')
.dontMock('../replacePatterns')
.setMock('../../ModuleDescriptor', function(data) {return data;});
jest.mock('path');
var Promise = require('bluebird');
describe('HasteDependencyResolver', function() {

View File

@ -22,14 +22,17 @@
ErrorUtils._globalHandler = fun;
},
reportError: function(error) {
Error._globalHandler && ErrorUtils._globalHandler(error);
ErrorUtils._globalHandler && ErrorUtils._globalHandler(error);
},
reportFatalError: function(error) {
ErrorUtils._globalHandler && ErrorUtils._globalHandler(error, true);
},
applyWithGuard: function(fun, context, args) {
try {
ErrorUtils._inGuard++;
return fun.apply(context, args);
} catch (e) {
ErrorUtils._globalHandler && ErrorUtils._globalHandler(e);
ErrorUtils.reportError(e);
} finally {
ErrorUtils._inGuard--;
}

View File

@ -10,11 +10,13 @@
jest
.dontMock('underscore')
.dontMock('path')
.dontMock('absolute-path')
.dontMock('crypto')
.dontMock('../Cache');
jest
.mock('os')
.mock('fs');
var Promise = require('bluebird');
describe('JSTransformer Cache', function() {

Some files were not shown because too many files have changed in this diff Show More