Merge pull request #1264 from vjeux/Update_Wed_13_May
Update wed 13 may
This commit is contained in:
commit
fec81947bd
|
@ -150,7 +150,7 @@ class Game2048 extends React.Component {
|
|||
startX: number;
|
||||
startY: number;
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
this.state = {
|
||||
board: new GameBoard(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]} />;
|
||||
}
|
||||
},
|
||||
];
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -168,7 +168,7 @@ var MapViewExample = React.createClass({
|
|||
/>
|
||||
<MapRegionInput
|
||||
onChange={this._onRegionInputChanged}
|
||||
region={this.state.mapRegionInput}
|
||||
region={this.state.mapRegionInput || undefined}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
@ -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`',
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 |
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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',
|
||||
});
|
|
@ -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
|
||||
|
|
|
@ -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]));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -92,6 +92,8 @@ var getPhotosReturnChecker = createStrictShapeTypeChecker({
|
|||
});
|
||||
|
||||
class CameraRoll {
|
||||
|
||||
static GroupTypesOptions: Array<string>;
|
||||
/**
|
||||
* Saves the image with tag `tag` to the camera roll.
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
|
|
|
@ -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 {
|
||||
|
@ -582,7 +582,7 @@ var TextInput = React.createClass({
|
|||
var counter = event.nativeEvent.eventCounter;
|
||||
if (counter > this.state.mostRecentEventCounter) {
|
||||
this.setState({mostRecentEventCounter: counter});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -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',
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 + '`'
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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,8 +880,13 @@ 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();
|
||||
this.spring.setCurrentValue(0);
|
||||
if (this.state.pendingGestureProgress != null) {
|
||||
this.spring.setCurrentValue(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this._doesGestureOverswipe(this.state.activeGesture)) {
|
||||
var frictionConstant = gesture.overswipe.frictionConstant;
|
||||
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"Unrecognized tag protocol: %@", imageTag];
|
||||
NSError *error = errorWithMessage(errorMessage);
|
||||
callback(error, nil);
|
||||
UIImage *image = [RCTConvert UIImage:imageTag];
|
||||
if (image) {
|
||||
RCTDispatchCallbackOnMainQueue(callback, nil, image);
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"Unrecognized tag protocol: %@", imageTag];
|
||||
NSError *error = RCTErrorWithMessage(errorMessage);
|
||||
RCTDispatchCallbackOnMainQueue(callback, error, nil);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
view.image = image;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
RCTExceptionsManager.reportUnhandledException(e.message, stack);
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
|
|
|
@ -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
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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 = {
|
||||
|
|
|
@ -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 `' +
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
module.exports = require('ReactIOS');
|
||||
module.exports = require('ReactNative');
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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],
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
static startDetecting() {}
|
||||
}
|
||||
|
||||
// No-op for iOS, but used on the web. Should not be documented.
|
||||
PixelRatio.startDetecting = function() {};
|
||||
|
||||
module.exports = PixelRatio;
|
||||
|
|
|
@ -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]);
|
||||
});
|
||||
|
||||
});
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -819,9 +820,9 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
|||
|
||||
- (void)reload
|
||||
{
|
||||
/**
|
||||
* AnyThread
|
||||
*/
|
||||
/**
|
||||
* AnyThread
|
||||
*/
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self invalidate];
|
||||
[self setUp];
|
||||
|
@ -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)];
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
self.userInteractionEnabled = NO;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_bridge enqueueJSCall:@"ReactIOS.unmountComponentAtNodeAndRemoveContainer"
|
||||
args:@[self.reactTag]];
|
||||
if (self.isValid) {
|
||||
self.userInteractionEnabled = NO;
|
||||
[self removeFromSuperview];
|
||||
[_bridge enqueueJSCall:@"ReactNative.unmountComponentAtNodeAndRemoveContainer"
|
||||
args:@[self.reactTag]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]] -
|
||||
getPaddingAndBorderAxis(node, axis) -
|
||||
getMarginAxis(child, axis) -
|
||||
getPosition(child, leading[axis]) -
|
||||
getPosition(child, trailing[axis])),
|
||||
node->layout.dimensions[dim[axis]] -
|
||||
getPaddingAndBorderAxis(node, axis) -
|
||||
getMarginAxis(child, axis) -
|
||||
getPosition(child, leading[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) -
|
||||
getMarginAxis(child, axis) -
|
||||
getPosition(child, leading[axis]) -
|
||||
getPosition(child, trailing[axis])
|
||||
),
|
||||
node->layout.dimensions[dim[axis]] -
|
||||
getPaddingAndBorderAxis(node, axis) -
|
||||
getMarginAxis(child, axis) -
|
||||
getPosition(child, leading[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]] =
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -13,6 +13,8 @@ jest.dontMock('../')
|
|||
.dontMock('../replacePatterns')
|
||||
.setMock('../../ModuleDescriptor', function(data) {return data;});
|
||||
|
||||
jest.mock('path');
|
||||
|
||||
var Promise = require('bluebird');
|
||||
|
||||
describe('HasteDependencyResolver', function() {
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue