From aefb3d362886f619c7b8494118ea051ac02d1d6d Mon Sep 17 00:00:00 2001 From: Andrei Coman Date: Thu, 23 Jul 2015 12:22:41 -0700 Subject: [PATCH 01/37] [ReactNative] Use new animation library for 2048 game demo --- Examples/2048/Game2048.js | 70 +++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Examples/2048/Game2048.js b/Examples/2048/Game2048.js index e43eefa758da22..90111d38b87147 100644 --- a/Examples/2048/Game2048.js +++ b/Examples/2048/Game2048.js @@ -24,7 +24,7 @@ var { View, } = React; -var AnimationExperimental = require('AnimationExperimental'); +var Animated = require('Animated'); var GameBoard = require('GameBoard'); var TouchableBounce = require('TouchableBounce'); @@ -53,58 +53,58 @@ class Board extends React.Component { } class Tile extends React.Component { - calculateOffset(): {top: number; left: number; opacity: number} { + static _getPosition(index): number { + return BOARD_PADDING + (index * (CELL_SIZE + CELL_MARGIN * 2) + CELL_MARGIN); + } + + constructor(props: {}) { + super(props); + var tile = this.props.tile; - var pos = (i) => { - return BOARD_PADDING + (i * (CELL_SIZE + CELL_MARGIN * 2) + CELL_MARGIN); + this.state = { + opacity: new Animated.Value(0), + top: new Animated.Value(Tile._getPosition(tile.toRow())), + left: new Animated.Value(Tile._getPosition(tile.toColumn())), }; + } - var animationPosition = (i) => { - return pos(i) + (CELL_SIZE / 2); - }; + calculateOffset(): {top: number; left: number; opacity: number} { + var tile = this.props.tile; var offset = { - top: pos(tile.toRow()), - left: pos(tile.toColumn()), - opacity: 1, + top: this.state.top, + left: this.state.left, + opacity: this.state.opacity, }; if (tile.isNew()) { - offset.opacity = 0; - } else { - var point = { - x: animationPosition(tile.toColumn()), - y: animationPosition(tile.toRow()), - }; - AnimationExperimental.startAnimation({ - node: this.refs['this'], + Animated.timing(this.state.opacity, { duration: 100, - easing: 'easeInOutQuad', - property: 'position', - toValue: point, - }); + toValue: 1, + }).start(); + } else { + Animated.parallel([ + Animated.timing(offset.top, { + duration: 100, + toValue: Tile._getPosition(tile.toRow()), + }), + Animated.timing(offset.left, { + duration: 100, + toValue: Tile._getPosition(tile.toColumn()), + }), + ]).start(); } return offset; } - componentDidMount() { - AnimationExperimental.startAnimation({ - node: this.refs['this'], - duration: 100, - easing: 'easeInOutQuad', - property: 'opacity', - toValue: 1, - }); - } - render() { var tile = this.props.tile; var tileStyles = [ styles.tile, styles['tile' + tile.value], - this.calculateOffset() + this.calculateOffset(), ]; var textStyles = [ @@ -115,9 +115,9 @@ class Tile extends React.Component { ]; return ( - + {tile.value} - + ); } } From 3fa39634655007a68e85a28a71f7d798e41f12ff Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 23 Jul 2015 14:53:52 -0700 Subject: [PATCH 02/37] [MovieApp] Add key to image components inside of MovieCell. Summary: Closes https://github.com/facebook/react-native/pull/2065 Github Author: Christopher --- Examples/Movies/SearchScreen.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Examples/Movies/SearchScreen.js b/Examples/Movies/SearchScreen.js index c0877d978a7c9b..a88d7bfacb0b5b 100644 --- a/Examples/Movies/SearchScreen.js +++ b/Examples/Movies/SearchScreen.js @@ -262,6 +262,7 @@ var SearchScreen = React.createClass({ ) { return ( this.selectMovie(movie)} onHighlight={() => highlightRowFunc(sectionID, rowID)} onUnhighlight={() => highlightRowFunc(null, null)} From 10ffe170c2f0be530e5946614e8df1cf0bd2df7e Mon Sep 17 00:00:00 2001 From: Mark Miyashita Date: Thu, 23 Jul 2015 16:19:27 -0700 Subject: [PATCH 03/37] [StatusBar] Add ability to toggle the network activity indicator in the status bar + example in UIExplorer Summary: Added the ability to turn on and off the network activity indicator using: ``` StatusBarIOS.setNetworkActivityIndicatorVisible(true) ``` and ``` StatusBarIOS.setNetworkActivityIndicatorVisible(false) ``` Also added an example to the UIExplorer example app. Fix #986 Closes https://github.com/facebook/react-native/pull/2079 Github Author: Mark Miyashita --- Examples/UIExplorer/StatusBarIOSExample.js | 20 +++++++++++++++++++ .../Components/StatusBar/StatusBarIOS.ios.js | 4 ++++ React/Modules/RCTStatusBarManager.m | 5 +++++ 3 files changed, 29 insertions(+) diff --git a/Examples/UIExplorer/StatusBarIOSExample.js b/Examples/UIExplorer/StatusBarIOSExample.js index ab649197eed994..28d5e2a7c07692 100644 --- a/Examples/UIExplorer/StatusBarIOSExample.js +++ b/Examples/UIExplorer/StatusBarIOSExample.js @@ -83,6 +83,26 @@ exports.examples = [{ ); }, +}, { + title: 'Status Bar Network Activity Indicator', + render() { + return ( + + StatusBarIOS.setNetworkActivityIndicatorVisible(true)}> + + setNetworkActivityIndicatorVisible(true) + + + StatusBarIOS.setNetworkActivityIndicatorVisible(false)}> + + setNetworkActivityIndicatorVisible(false) + + + + ); + }, }]; var styles = StyleSheet.create({ diff --git a/Libraries/Components/StatusBar/StatusBarIOS.ios.js b/Libraries/Components/StatusBar/StatusBarIOS.ios.js index adfed78b7b23a5..59369ef143dd37 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.ios.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.ios.js @@ -35,6 +35,10 @@ var StatusBarIOS = { animation = animation || 'none'; RCTStatusBarManager.setHidden(hidden, animation); }, + + setNetworkActivityIndicatorVisible(visible: boolean) { + RCTStatusBarManager.setNetworkActivityIndicatorVisible(visible); + }, }; module.exports = StatusBarIOS; diff --git a/React/Modules/RCTStatusBarManager.m b/React/Modules/RCTStatusBarManager.m index cb9ddfe690a088..bf32f835cf5d77 100644 --- a/React/Modules/RCTStatusBarManager.m +++ b/React/Modules/RCTStatusBarManager.m @@ -71,4 +71,9 @@ - (dispatch_queue_t)methodQueue } } +RCT_EXPORT_METHOD(setNetworkActivityIndicatorVisible:(BOOL)visible) +{ + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:visible]; +} + @end From 9e4af68d91b3c5a321627bd393e4a3991bf94db1 Mon Sep 17 00:00:00 2001 From: Jared Forsyth Date: Thu, 23 Jul 2015 16:56:23 -0700 Subject: [PATCH 04/37] [react-native] enable react devtools from JavascriptCore --- Libraries/Devtools/setupDevtools.js | 105 ++++++++++++++++++++ Libraries/Inspector/Inspector.js | 18 ++-- Libraries/ReactIOS/renderApplication.ios.js | 5 + packager/webSocketProxy.js | 14 +++ 4 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 Libraries/Devtools/setupDevtools.js diff --git a/Libraries/Devtools/setupDevtools.js b/Libraries/Devtools/setupDevtools.js new file mode 100644 index 00000000000000..0bd003dca79955 --- /dev/null +++ b/Libraries/Devtools/setupDevtools.js @@ -0,0 +1,105 @@ +/** + * 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 setupDevtools + * @flow + */ +'use strict'; + +function setupDevtools() { + var messageListeners = []; + var closeListeners = []; + var ws = new window.WebSocket('ws://localhost:8081/devtools'); + // this is accessed by the eval'd backend code + var FOR_BACKEND = { // eslint-disable-line no-unused-vars + resolveRNStyle: require('flattenStyle'), + wall: { + listen(fn) { + messageListeners.push(fn); + }, + onClose(fn) { + closeListeners.push(fn); + }, + send(data) { + ws.send(JSON.stringify(data)); + }, + }, + }; + ws.onclose = () => { + console.warn('devtools socket closed'); + closeListeners.forEach(fn => fn()); + }; + ws.onerror = error => { + console.warn('devtools socket errored', error); + closeListeners.forEach(fn => fn()); + }; + ws.onopen = function () { + tryToConnect(); + }; + + function tryToConnect() { + ws.send('attach:agent'); + var _interval = setInterval(() => ws.send('attach:agent'), 500); + ws.onmessage = evt => { + if (evt.data.indexOf('eval:') === 0) { + clearInterval(_interval); + initialize(evt.data.slice('eval:'.length)); + } + }; + } + + function initialize(text) { + try { + // FOR_BACKEND is used by the eval'd code + eval(text); // eslint-disable-line no-eval + } catch (e) { + console.error('Failed to eval' + e.message); + return; + } + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ + CurrentOwner: require('ReactCurrentOwner'), + InstanceHandles: require('ReactInstanceHandles'), + Mount: require('ReactNativeMount'), + Reconciler: require('ReactReconciler'), + TextComponent: require('ReactNativeTextComponent'), + }); + ws.onmessage = handleMessage; + } + + function handleMessage(evt) { + var data; + try { + data = JSON.parse(evt.data); + } catch (e) { + return console.error('failed to parse json: ' + evt.data); + } + // the devtools closed + if (data.$close || data.$error) { + closeListeners.forEach(fn => fn()); + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.emit('shutdown'); + tryToConnect(); + return; + } + if (data.$open) { + return; // ignore + } + messageListeners.forEach(fn => { + try { + fn(data); + } catch (e) { + // jsc doesn't play so well with tracebacks that go into eval'd code, + // so the stack trace here will stop at the `eval()` call. Getting the + // message that caused the error is the best we can do for now. + console.log(data); + throw e; + } + }); + } +} + +module.exports = setupDevtools; diff --git a/Libraries/Inspector/Inspector.js b/Libraries/Inspector/Inspector.js index c014c29c43de10..7dbec7443acee5 100644 --- a/Libraries/Inspector/Inspector.js +++ b/Libraries/Inspector/Inspector.js @@ -20,11 +20,9 @@ var StyleSheet = require('StyleSheet'); var UIManager = require('NativeModules').UIManager; var View = require('View'); -var REACT_DEVTOOLS_HOOK: ?Object = typeof window !== 'undefined' ? window.__REACT_DEVTOOLS_GLOBAL_HOOK__ : null; - -if (REACT_DEVTOOLS_HOOK) { +if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) { // required for devtools to be able to edit react native styles - REACT_DEVTOOLS_HOOK.resolveRNStyle = require('flattenStyle'); + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = require('flattenStyle'); } class Inspector extends React.Component { @@ -43,12 +41,12 @@ class Inspector extends React.Component { } componentDidMount() { - if (REACT_DEVTOOLS_HOOK) { + if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) { this.attachToDevtools = this.attachToDevtools.bind(this); - REACT_DEVTOOLS_HOOK.on('react-devtools', this.attachToDevtools); + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on('react-devtools', this.attachToDevtools); // if devtools is already started - if (REACT_DEVTOOLS_HOOK.reactDevtoolsAgent) { - this.attachToDevtools(REACT_DEVTOOLS_HOOK.reactDevtoolsAgent); + if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent) { + this.attachToDevtools(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent); } } } @@ -57,8 +55,8 @@ class Inspector extends React.Component { if (this._subs) { this._subs.map(fn => fn()); } - if (REACT_DEVTOOLS_HOOK) { - REACT_DEVTOOLS_HOOK.off('react-devtools', this.attachToDevtools); + if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) { + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.off('react-devtools', this.attachToDevtools); } } diff --git a/Libraries/ReactIOS/renderApplication.ios.js b/Libraries/ReactIOS/renderApplication.ios.js index 53a786e2aded8f..6a4bb5f68cd28e 100644 --- a/Libraries/ReactIOS/renderApplication.ios.js +++ b/Libraries/ReactIOS/renderApplication.ios.js @@ -69,6 +69,11 @@ function renderApplication( rootTag, 'Expect to have a valid rootTag, instead got ', rootTag ); + // not when debugging in chrome + if (__DEV__ && !window.document) { + var setupDevtools = require('setupDevtools'); + setupDevtools(); + } React.render( Date: Thu, 23 Jul 2015 17:50:09 -0700 Subject: [PATCH 05/37] [ReactNative] Update React to 0.14-beta1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d119c5d29b028..8feb81b2f0af59 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "optimist": "0.6.1", "promise": "^7.0.3", "react-timer-mixin": "^0.13.1", - "react-tools": "0.13.2", + "react-tools": "git://github.com/facebook/react#b4e74e38e43ac53af8acd62c78c9213be0194245", "rebound": "^0.0.12", "sane": "^1.1.2", "semver": "^4.3.6", From e01f90784f961ad88a4cde114089bc5839207d29 Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Thu, 23 Jul 2015 17:50:16 -0700 Subject: [PATCH 06/37] [ReactNative] Update core RN modules to work with React 0.14-beta1 --- .flowconfig | 12 ++++--- Examples/UIExplorer/createExamplePage.js | 5 +-- Libraries/Components/ScrollView/ScrollView.js | 32 +++++++++--------- .../CustomComponents/ListView/ListView.js | 3 +- .../Initialization/ExceptionsManager.js | 5 +++ Libraries/ReactNative/ReactNative.js | 25 +++++--------- .../ReactNativeDefaultInjection.js | 2 +- Libraries/ReactNative/ReactNativeMount.js | 33 ++++++++++++++++--- packager/blacklist.js | 17 ++++------ 9 files changed, 78 insertions(+), 56 deletions(-) diff --git a/.flowconfig b/.flowconfig index 31a4d53177816f..ac39b85d92f065 100644 --- a/.flowconfig +++ b/.flowconfig @@ -9,11 +9,13 @@ # Ignore react-tools where there are overlaps, but don't ignore anything that # react-native relies on -.*/node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js -.*/node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js -.*/node_modules/react-tools/src/browser/ui/React.js -.*/node_modules/react-tools/src/core/ReactInstanceHandles.js -.*/node_modules/react-tools/src/event/EventPropagators.js +.*/node_modules/react-tools/src/React.js +.*/node_modules/react-tools/src/renderers/shared/reconciler/ReactInstanceHandles.js +.*/node_modules/react-tools/src/renderers/shared/event/EventPropagators.js +.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js +.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js +.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderTouchHistoryStore.js +.*/node_modules/react-tools/src/shared/vendor/core/ExecutionEnvironment.js # Ignore commoner tests .*/node_modules/commoner/test/.* diff --git a/Examples/UIExplorer/createExamplePage.js b/Examples/UIExplorer/createExamplePage.js index 352f84a4c4adec..86525c485e4fec 100644 --- a/Examples/UIExplorer/createExamplePage.js +++ b/Examples/UIExplorer/createExamplePage.js @@ -54,8 +54,9 @@ var createExamplePage = function(title: ?string, exampleModule: ExampleModule) }; var result = example.render(null); if (result) { - renderedComponent = result; - result.props.navigator = this.props.navigator; + renderedComponent = React.cloneElement(result, { + navigator: this.props.navigator, + }); } (React: Object).render = originalRender; (React: Object).renderComponent = originalRenderComponent; diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 48dd3c4659c699..cd2dbf5758f93a 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -309,6 +309,21 @@ var ScrollView = React.createClass({ ); }, + handleScroll: function(e: Event) { + if (__DEV__) { + if (this.props.onScroll && !this.props.scrollEventThrottle) { + console.log( + 'You specified `onScroll` on a but not ' + + '`scrollEventThrottle`. You will only receive one event. ' + + 'Using `16` you get all the events but be aware that it may ' + + 'cause frame drops, use a bigger number if you don\'t need as ' + + 'much precision.' + ); + } + } + this.scrollResponderHandleScroll(e); + }, + render: function() { var contentContainerStyle = [ this.props.horizontal && styles.contentContainerHorizontal, @@ -324,21 +339,6 @@ var ScrollView = React.createClass({ ') must by applied through the contentContainerStyle prop.' ); } - if (__DEV__) { - if (this.props.onScroll && !this.props.scrollEventThrottle) { - var onScroll = this.props.onScroll; - this.props.onScroll = function() { - console.log( - 'You specified `onScroll` on a but not ' + - '`scrollEventThrottle`. You will only receive one event. ' + - 'Using `16` you get all the events but be aware that it may ' + - 'cause frame drops, use a bigger number if you don\'t need as ' + - 'much precision.' - ); - onScroll.apply(this, arguments); - }; - } - } var contentContainer = void) + ): ?ReactComponent { + warning('Use React.render instead of React.renderComponent'); + return ReactNative.render(element, mountInto, callback); + }, }; // Inject the runtime into a devtools global hook regardless of browser. diff --git a/Libraries/ReactNative/ReactNativeDefaultInjection.js b/Libraries/ReactNative/ReactNativeDefaultInjection.js index 15a3e54004acc0..c959924022be3b 100644 --- a/Libraries/ReactNative/ReactNativeDefaultInjection.js +++ b/Libraries/ReactNative/ReactNativeDefaultInjection.js @@ -90,7 +90,7 @@ function inject() { ReactNativeComponent.injection.injectTextComponentClass( ReactNativeTextComponent ); - ReactNativeComponent.injection.injectAutoWrapper(function(tag) { + ReactNativeComponent.injection.injectGenericComponentClass(function(tag) { // Show a nicer error message for non-function tags var info = ''; if (typeof tag === 'string' && /^[a-z]/.test(tag)) { diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js index b61f1a24373a2c..6312267649bf3b 100644 --- a/Libraries/ReactNative/ReactNativeMount.js +++ b/Libraries/ReactNative/ReactNativeMount.js @@ -13,6 +13,7 @@ var RCTUIManager = require('NativeModules').UIManager; +var ReactElement = require('ReactElement'); var ReactNativeTagHandles = require('ReactNativeTagHandles'); var ReactPerf = require('ReactPerf'); var ReactReconciler = require('ReactReconciler'); @@ -27,6 +28,17 @@ function instanceNumberToChildRootID(rootNodeID, instanceNumber) { return rootNodeID + '[' + instanceNumber + ']'; } +/** + * Temporary (?) hack so that we can store all top-level pending updates on + * composites instead of having to worry about different types of components + * here. + */ +var TopLevelWrapper = function() {}; +TopLevelWrapper.prototype.render = function() { + // this.props is actually a ReactElement + return this.props; +}; + /** * Mounts this component and inserts it into the DOM. * @@ -43,7 +55,7 @@ function mountComponentIntoNode( var markup = ReactReconciler.mountComponent( componentInstance, rootID, transaction, emptyObject ); - componentInstance._isTopLevel = true; + componentInstance._renderedComponent._topLevelWrapper = componentInstance; ReactNativeMount._mountImageIntoNode(markup, container); } @@ -94,13 +106,22 @@ var ReactNativeMount = { containerTag: number, callback?: ?(() => void) ): ?ReactComponent { + var nextWrappedElement = new ReactElement( + TopLevelWrapper, + null, + null, + null, + nextElement + ); + var topRootNodeID = ReactNativeTagHandles.tagToRootNodeID[containerTag]; if (topRootNodeID) { var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID]; if (prevComponent) { - var prevElement = prevComponent._currentElement; + var prevWrappedElement = prevComponent._currentElement; + var prevElement = prevWrappedElement.props; if (shouldUpdateReactComponent(prevElement, nextElement)) { - ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement); + ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement); if (callback) { ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback); } @@ -122,7 +143,7 @@ var ReactNativeMount = { containerTag ); - var instance = instantiateReactComponent(nextElement); + var instance = instantiateReactComponent(nextWrappedElement); ReactNativeMount._instancesByContainerID[topRootNodeID] = instance; var childRootNodeID = instanceNumberToChildRootID( @@ -234,6 +255,10 @@ var ReactNativeMount = { getNode: function(id: T): T { return id; + }, + + getID: function(id: T): T { + return id; } }; diff --git a/packager/blacklist.js b/packager/blacklist.js index 237691a85e9491..a1b9c946d73fe6 100644 --- a/packager/blacklist.js +++ b/packager/blacklist.js @@ -14,9 +14,13 @@ var path = require('path'); // modulePathIgnorePatterns. var sharedBlacklist = [ 'website', - 'node_modules/react-tools/src/utils/ImmutableObject.js', - 'node_modules/react-tools/src/core/ReactInstanceHandles.js', - 'node_modules/react-tools/src/event/EventPropagators.js' + 'node_modules/react-tools/src/React.js', + 'node_modules/react-tools/src/renderers/shared/event/EventPropagators.js', + 'node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js', + 'node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js', + 'node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderTouchHistoryStore.js', + 'node_modules/react-tools/src/renderers/shared/reconciler/ReactInstanceHandles.js', + 'node_modules/react-tools/src/shared/vendor/core/ExecutionEnvironment.js', ]; var platformBlacklists = { @@ -24,17 +28,10 @@ var platformBlacklists = { '.ios.js' ], ios: [ - 'node_modules/react-tools/src/browser/ui/React.js', - 'node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js', - 'node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js', '.web.js', '.android.js', ], android: [ - 'node_modules/react-tools/src/browser/ui/React.js', - 'node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js', - 'node_modules/react-tools/src/browser/ReactTextComponent.js', - 'node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js', '.web.js', '.ios.js', ], From accf6f12e4b5e5d802ac07ab24fef2c433daa813 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Thu, 23 Jul 2015 17:57:42 -0700 Subject: [PATCH 07/37] Make the scrollResponderScrollNativeHandleToKeyboard works on Android --- Libraries/Components/ScrollResponder.js | 24 +++++++++++++++---- Libraries/Components/ScrollView/ScrollView.js | 15 ++---------- .../CustomComponents/ListView/ListView.js | 4 ++++ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index ab03e55fbbc6f1..920b564789d9fb 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -12,13 +12,13 @@ 'use strict'; var NativeModules = require('NativeModules'); +var Platform = require('Platform'); var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); var React = require('React'); var Subscribable = require('Subscribable'); var TextInputState = require('TextInputState'); var RCTUIManager = NativeModules.UIManager; -var RCTUIManagerDeprecated = NativeModules.UIManager; var RCTScrollViewConsts = RCTUIManager.RCTScrollView.Constants; var warning = require('warning'); @@ -351,7 +351,19 @@ var ScrollResponderMixin = { * can also be used to quickly scroll to any element we want to focus */ scrollResponderScrollTo: function(offsetX: number, offsetY: number) { - RCTUIManagerDeprecated.scrollTo(React.findNodeHandle(this), offsetX, offsetY); + if (Platform.OS === 'android') { + RCTUIManager.dispatchViewManagerCommand( + React.findNodeHandle(this), + RCTUIManager.RCTScrollView.Commands.scrollTo, + [offsetX, offsetY], + ); + } else { + RCTUIManager.scrollTo( + React.findNodeHandle(this), + offsetX, + offsetY + ); + } }, /** @@ -359,7 +371,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(React.findNodeHandle(this), rect); + RCTUIManager.zoomToRect(React.findNodeHandle(this), rect); }, /** @@ -377,7 +389,7 @@ var ScrollResponderMixin = { this.preventNegativeScrollOffset = !!preventNegativeScrollOffset; RCTUIManager.measureLayout( nodeHandle, - React.findNodeHandle(this), + React.findNodeHandle(this.getInnerViewNode()), this.scrollResponderTextInputFocusError, this.scrollResponderInputMeasureAndScrollToKeyboard ); @@ -429,6 +441,10 @@ var ScrollResponderMixin = { this.addListenerOn(RCTDeviceEventEmitter, 'keyboardWillHide', this.scrollResponderKeyboardWillHide); this.addListenerOn(RCTDeviceEventEmitter, 'keyboardDidShow', this.scrollResponderKeyboardDidShow); this.addListenerOn(RCTDeviceEventEmitter, 'keyboardDidHide', this.scrollResponderKeyboardDidHide); + warning(this.getInnerViewNode, 'You need to implement getInnerViewNode in ' + + this.constructor.displayName + ' to get full' + + 'functionality from ScrollResponder mixin. See example of ListView and' + + ' ScrollView.'); }, /** diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index cd2dbf5758f93a..e82c5134b7cba8 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -286,19 +286,8 @@ var ScrollView = React.createClass({ }, scrollTo: function(destY?: number, destX?: number) { - if (Platform.OS === 'android') { - RCTUIManager.dispatchViewManagerCommand( - React.findNodeHandle(this), - RCTUIManager.RCTScrollView.Commands.scrollTo, - [destX || 0, destY || 0] - ); - } else { - RCTUIManager.scrollTo( - React.findNodeHandle(this), - destX || 0, - destY || 0 - ); - } + // $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now + this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0); }, scrollWithoutAnimationTo: function(destY?: number, destX?: number) { diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js index b1183c253e21a4..fda582c3af5bf6 100644 --- a/Libraries/CustomComponents/ListView/ListView.js +++ b/Libraries/CustomComponents/ListView/ListView.js @@ -252,6 +252,10 @@ var ListView = React.createClass({ }; }, + getInnerViewNode: function() { + return this.refs[SCROLLVIEW_REF].getInnerViewNode(); + }, + componentWillMount: function() { // this data should never trigger a render pass, so don't put in state this.scrollProperties = { From 1b06e41c8319010a9b659e47e51a931600793268 Mon Sep 17 00:00:00 2001 From: lh_wang Date: Thu, 23 Jul 2015 19:01:18 -0700 Subject: [PATCH 08/37] fix examaple TabBarIOSExample bug; show click num when user click second & third tabbar Summary: Closes https://github.com/facebook/react-native/pull/1522 Github Author: lh_wang --- Examples/UIExplorer/TabBarIOSExample.js | 12 ++++++------ .../testTabBarExample_1@2x.png | Bin 25872 -> 25483 bytes 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Examples/UIExplorer/TabBarIOSExample.js b/Examples/UIExplorer/TabBarIOSExample.js index 0cbd1fb9a055d4..9991951326c49a 100644 --- a/Examples/UIExplorer/TabBarIOSExample.js +++ b/Examples/UIExplorer/TabBarIOSExample.js @@ -39,11 +39,11 @@ var TabBarExample = React.createClass({ }; }, - _renderContent: function(color: string, pageText: string) { + _renderContent: function(color: string, pageText: string, num?: number) { return ( {pageText} - {this.state.presses} re-renders of the More tab + {num} re-renders of the {pageText} ); }, @@ -51,8 +51,8 @@ var TabBarExample = React.createClass({ render: function() { return ( + tintColor="white" + barTintColor="darkslateblue"> - {this._renderContent('#783E33', 'Red Tab')} + {this._renderContent('#783E33', 'Red Tab', this.state.notifCount)} - {this._renderContent('#21551C', 'Green Tab')} + {this._renderContent('#21551C', 'Green Tab', this.state.presses)} ); diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTabBarExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTabBarExample_1@2x.png index 65cadda4f888a78dc13bf1d3dfe344832d781f82..0f306f68382dbcad6e11cc4690946f1463e529bb 100644 GIT binary patch literal 25483 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 J?m6pQ{{>$GCLaI* literal 25872 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 XAh)BNr`Q1ie=c7%yij<~?&1Fex`rOQ From 7c87952e431967b21639c6a818a99e2063eabc6e Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Fri, 24 Jul 2015 06:01:33 -0700 Subject: [PATCH 09/37] [ReactNative] Image docs Summary: In preparation for open sourcing React Native for Android, document which Image props are platform-specific. --- Libraries/Image/Image.ios.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index e1fc6df2f16432..549b3dee928a44 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -53,7 +53,6 @@ var warning = require('warning'); * }, * ``` */ - var Image = React.createClass({ propTypes: { style: StyleSheetPropType(ImageStylePropTypes), @@ -68,16 +67,20 @@ var Image = React.createClass({ /** * A static image to display while downloading the final image off the * network. + * @platform ios */ defaultSource: PropTypes.shape({ uri: PropTypes.string, }), /** - * Whether this element should be revealed as an accessible element. + * When true, indicates the image is an accessibility element. + * @platform ios */ accessible: PropTypes.bool, /** - * Custom string to display for accessibility. + * The text that's read by the screen reader when the user interacts with + * the image. + * @platform ios */ accessibilityLabel: PropTypes.string, /** @@ -86,6 +89,7 @@ var Image = React.createClass({ * of the image will be stretched. This is useful for creating resizable * rounded buttons, shadows, and other resizable assets. More info on * [Apple documentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/index.html#//apple_ref/occ/instm/UIImage/resizableImageWithCapInsets) + * @platform ios */ capInsets: EdgeInsetsPropType, /** @@ -100,32 +104,32 @@ var Image = React.createClass({ testID: PropTypes.string, /** * Invoked on mount and layout changes with - * - * {nativeEvent: {layout: {x, y, width, height}}}. + * `{nativeEvent: {layout: {x, y, width, height}}}`. */ onLayout: PropTypes.func, /** * Invoked on load start + * @platform ios */ onLoadStart: PropTypes.func, /** - * Invoked on download progress with - * - * {nativeEvent: {loaded, total}}. + * Invoked on download progress with `{nativeEvent: {loaded, total}}` + * @platform ios */ onProgress: PropTypes.func, /** - * Invoked on load error - * - * {nativeEvent: {error}}. + * Invoked on load error with `{nativeEvent: {error}}` + * @platform ios */ onError: PropTypes.func, /** * Invoked when load completes successfully + * @platform ios */ onLoad: PropTypes.func, /** * Invoked when load either succeeds or fails + * @platform ios */ onLoadEnd: PropTypes.func, }, From ef5cec4f087be58f4a994636a2251ef7cffd622f Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Fri, 24 Jul 2015 08:25:51 -0700 Subject: [PATCH 10/37] Text highlighting on iOS Summary: This diff implements highlighting of tapped text subranges for the iOS `` component, styled to match how iOS webkit views highlight links (translucent grey overlay with rounded corners). Highlighting is enabled by default for any `` component which has an onPress handler. To disable the highlight, add `suppressHighlighting={true}` to the component props. --- Examples/UIExplorer/TextExample.ios.js | 11 +++++++- .../UIExplorer.xcodeproj/project.pbxproj | 2 ++ .../RCTActionSheet.xcodeproj/project.pbxproj | 2 ++ .../RCTAdSupport.xcodeproj/project.pbxproj | 2 ++ .../RCTGeolocation.xcodeproj/project.pbxproj | 2 ++ .../Image/RCTImage.xcodeproj/project.pbxproj | 2 ++ .../RCTLinking.xcodeproj/project.pbxproj | 2 ++ .../RCTNetwork.xcodeproj/project.pbxproj | 2 ++ .../project.pbxproj | 2 ++ .../RCTTest/RCTTest.xcodeproj/project.pbxproj | 2 ++ .../RCTSettings.xcodeproj/project.pbxproj | 2 ++ Libraries/Text/RCTText.m | 28 +++++++++++++++++++ .../Text/RCTText.xcodeproj/project.pbxproj | 2 ++ .../RCTVibration.xcodeproj/project.pbxproj | 2 ++ .../RCTWebSocket.xcodeproj/project.pbxproj | 2 ++ React/React.xcodeproj/project.pbxproj | 2 ++ 16 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Examples/UIExplorer/TextExample.ios.js b/Examples/UIExplorer/TextExample.ios.js index 4aff00e73fa351..1574f8a0bcf558 100644 --- a/Examples/UIExplorer/TextExample.ios.js +++ b/Examples/UIExplorer/TextExample.ios.js @@ -269,7 +269,7 @@ exports.examples = [ right right right right right right right right right right right right right - justify: this text component's contents are laid out with "textAlign: justify" + justify: this text component{"'"}s contents are laid out with "textAlign: justify" and as you can see all of the lines except the last one span the available width of the parent container. @@ -369,6 +369,15 @@ exports.examples = [ ); }, +}, { + title: 'Text highlighting (tap the link to see highlight)', + render: function() { + return ( + + Lorem ipsum dolor sit amet, null}>consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + ); + }, }]; var styles = StyleSheet.create({ diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj index dd7200d21bc07c..9052af3e2c2691 100644 --- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj +++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj @@ -1037,6 +1037,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -1092,6 +1093,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; diff --git a/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj/project.pbxproj b/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj/project.pbxproj index a73b70085685b6..ba116104de2d98 100644 --- a/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj/project.pbxproj +++ b/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -190,6 +191,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/AdSupport/RCTAdSupport.xcodeproj/project.pbxproj b/Libraries/AdSupport/RCTAdSupport.xcodeproj/project.pbxproj index 238838a938e13b..b4cd622b88afbe 100644 --- a/Libraries/AdSupport/RCTAdSupport.xcodeproj/project.pbxproj +++ b/Libraries/AdSupport/RCTAdSupport.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -195,6 +196,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/Geolocation/RCTGeolocation.xcodeproj/project.pbxproj b/Libraries/Geolocation/RCTGeolocation.xcodeproj/project.pbxproj index 93d6a375f42245..0295e541cec42e 100644 --- a/Libraries/Geolocation/RCTGeolocation.xcodeproj/project.pbxproj +++ b/Libraries/Geolocation/RCTGeolocation.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -190,6 +191,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj index 6f18a284fecd1e..372b7bc5b01696 100644 --- a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj +++ b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj @@ -211,6 +211,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -250,6 +251,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj b/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj index 89fcdffb189c57..844d94cf6e63b3 100644 --- a/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj +++ b/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -182,6 +183,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj index 88835214ba8167..8243ac65fc8e70 100644 --- a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj +++ b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj @@ -169,6 +169,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -208,6 +209,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj b/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj index 7b555c089664f2..4281a469ff28cf 100644 --- a/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj +++ b/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -188,6 +189,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj b/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj index 24ffac3925a686..eae9a6e6275ce6 100644 --- a/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj +++ b/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj @@ -189,6 +189,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -233,6 +234,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj b/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj index a0a5e1bf1163c8..8d9edf8d414397 100644 --- a/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj +++ b/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj @@ -149,6 +149,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -188,6 +189,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/Text/RCTText.m b/Libraries/Text/RCTText.m index 9dc8e42000eb11..23dabfbc559b55 100644 --- a/Libraries/Text/RCTText.m +++ b/Libraries/Text/RCTText.m @@ -17,6 +17,7 @@ @implementation RCTText { NSTextStorage *_textStorage; NSMutableArray *_reactSubviews; + CAShapeLayer *_highlightLayer; } - (instancetype)initWithFrame:(CGRect)frame @@ -78,8 +79,35 @@ - (void)drawRect:(CGRect)rect NSTextContainer *textContainer = [layoutManager.textContainers firstObject]; CGRect textFrame = UIEdgeInsetsInsetRect(self.bounds, _contentInset); NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; + [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textFrame.origin]; [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textFrame.origin]; + + __block UIBezierPath *highlightPath = nil; + [layoutManager.textStorage enumerateAttributesInRange:glyphRange options:0 usingBlock:^(NSDictionary *attrs, NSRange range, __unused BOOL *stop){ + if ([attrs[RCTIsHighlightedAttributeName] boolValue]) { + [layoutManager enumerateEnclosingRectsForGlyphRange:range withinSelectedGlyphRange:range inTextContainer:textContainer usingBlock:^(CGRect r, __unused BOOL *s){ + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(r, -2, -2) cornerRadius:2]; + if (highlightPath) { + [highlightPath appendPath:path]; + } else { + highlightPath = path; + } + }]; + } + }]; + + if (highlightPath) { + if (!_highlightLayer) { + _highlightLayer = [CAShapeLayer layer]; + _highlightLayer.fillColor = [UIColor colorWithWhite:0 alpha:0.25].CGColor; + [self.layer addSublayer:_highlightLayer]; + } + _highlightLayer.path = highlightPath.CGPath; + } else { + [_highlightLayer removeFromSuperlayer]; + _highlightLayer = nil; + } } - (NSNumber *)reactTagAtPoint:(CGPoint)point diff --git a/Libraries/Text/RCTText.xcodeproj/project.pbxproj b/Libraries/Text/RCTText.xcodeproj/project.pbxproj index b983615e33b1fb..3e9af67317c450 100644 --- a/Libraries/Text/RCTText.xcodeproj/project.pbxproj +++ b/Libraries/Text/RCTText.xcodeproj/project.pbxproj @@ -199,6 +199,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -238,6 +239,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/Vibration/RCTVibration.xcodeproj/project.pbxproj b/Libraries/Vibration/RCTVibration.xcodeproj/project.pbxproj index e4c3e4a2ee64d8..30613f87462345 100644 --- a/Libraries/Vibration/RCTVibration.xcodeproj/project.pbxproj +++ b/Libraries/Vibration/RCTVibration.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -195,6 +196,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj index 817cf7fd826e91..e1862d5818be86 100644 --- a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj +++ b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj @@ -152,6 +152,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -193,6 +194,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 2c551600b4d1ac..70e4e41204eb25 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -656,6 +656,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -697,6 +698,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; From 4499f28c1dafc17fa54ff7b13c06729675ddb391 Mon Sep 17 00:00:00 2001 From: Tadeu Zagallo Date: Fri, 24 Jul 2015 09:15:20 -0700 Subject: [PATCH 11/37] [ReactNative] Remove wrong lock from RCTProfile Summary: Remove sad lock from RCTProfileForwardInvocation that was locking concurrent calls and messing with the profiler. --- React/Base/RCTProfile.m | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/React/Base/RCTProfile.m b/React/Base/RCTProfile.m index 5174af4f153d7e..dace71faa79d00 100644 --- a/React/Base/RCTProfile.m +++ b/React/Base/RCTProfile.m @@ -118,19 +118,17 @@ static void RCTProfileForwardInvocation(NSObject *self, __unused SEL cmd, NSInvo NSString *name = [NSString stringWithFormat:@"-[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(invocation.selector)]; SEL newSel = RCTProfileProxySelector(invocation.selector); - RCTProfileLock( - if ([object_getClass(self) instancesRespondToSelector:newSel]) { - invocation.selector = newSel; - RCTProfileBeginEvent(); - [invocation invoke]; - RCTProfileEndEvent(name, @"objc_call,modules,auto", nil); - } else if ([self respondsToSelector:invocation.selector]) { - [invocation invoke]; - } else { - // Use original selector to don't change error message - [self doesNotRecognizeSelector:invocation.selector]; - } - ); + if ([object_getClass(self) instancesRespondToSelector:newSel]) { + invocation.selector = newSel; + RCTProfileBeginEvent(); + [invocation invoke]; + RCTProfileEndEvent(name, @"objc_call,modules,auto", nil); + } else if ([self respondsToSelector:invocation.selector]) { + [invocation invoke]; + } else { + // Use original selector to don't change error message + [self doesNotRecognizeSelector:invocation.selector]; + } } static IMP RCTProfileMsgForward(NSObject *, SEL); @@ -192,15 +190,13 @@ void RCTProfileHookModules(RCTBridge *bridge) void RCTProfileUnhookModules(RCTBridge *bridge) { - RCTProfileLock( - for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { - Class proxyClass = object_getClass(moduleData.instance); - if (moduleData.cls != proxyClass) { - object_setClass(moduleData.instance, moduleData.cls); - objc_disposeClassPair(proxyClass); - } - }; - ); + for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { + Class proxyClass = object_getClass(moduleData.instance); + if (moduleData.cls != proxyClass) { + object_setClass(moduleData.instance, moduleData.cls); + objc_disposeClassPair(proxyClass); + } + }; } From 81dd9c27ea174d2eee82a30cbbb7afba3ebbe7c2 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Fri, 24 Jul 2015 09:34:18 -0700 Subject: [PATCH 12/37] Optimized property setting and conversion --- React/Base/RCTConvert.m | 140 +++++++++++++++++++++++++++-------- React/Base/RCTModuleMethod.m | 2 +- 2 files changed, 110 insertions(+), 32 deletions(-) diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index e61e6f6eda4c6f..4d3355eb92e7e8 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -1075,24 +1075,64 @@ BOOL RCTSetProperty(id target, NSString *keyPath, SEL type, id json) } @try { - // Get converted value + NSMethodSignature *signature = [RCTConvert methodSignatureForSelector:type]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setArgument:&type atIndex:1]; - [invocation setArgument:&json atIndex:2]; - [invocation invokeWithTarget:[RCTConvert class]]; - NSUInteger length = [signature methodReturnLength]; - void *value = malloc(length); - [invocation getReturnValue:value]; - - // Set converted value - signature = [target methodSignatureForSelector:setter]; - invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setArgument:&setter atIndex:1]; - [invocation setArgument:value atIndex:2]; - [invocation invokeWithTarget:target]; - free(value); + switch (signature.methodReturnType[0]) { + +#define RCT_SET_CASE(_value, _type) \ + case _value: { \ + _type (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend; \ + void (*set)(id, SEL, _type) = (typeof(set))objc_msgSend; \ + set(target, setter, convert([RCTConvert class], type, json)); \ + break; \ + } + RCT_SET_CASE(':', SEL) + RCT_SET_CASE('*', const char *) + RCT_SET_CASE('c', char) + RCT_SET_CASE('C', unsigned char) + RCT_SET_CASE('s', short) + RCT_SET_CASE('S', unsigned short) + RCT_SET_CASE('i', int) + RCT_SET_CASE('I', unsigned int) + RCT_SET_CASE('l', long) + RCT_SET_CASE('L', unsigned long) + RCT_SET_CASE('q', long long) + RCT_SET_CASE('Q', unsigned long long) + RCT_SET_CASE('f', float) + RCT_SET_CASE('d', double) + RCT_SET_CASE('B', BOOL) + RCT_SET_CASE('^', void *) + + case '@': { + id (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend; + void (*set)(id, SEL, id) = (typeof(set))objc_msgSend; + set(target, setter, convert([RCTConvert class], type, json)); + break; + } + case '{': + default: { + + // Get converted value + void *value = malloc(signature.methodReturnLength); + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setTarget:[RCTConvert class]]; + [invocation setSelector:type]; + [invocation setArgument:&json atIndex:2]; + [invocation invoke]; + [invocation getReturnValue:value]; + + // Set converted value + signature = [target methodSignatureForSelector:setter]; + invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setArgument:&setter atIndex:1]; + [invocation setArgument:value atIndex:2]; + [invocation invokeWithTarget:target]; + free(value); + + break; + } + } return YES; } @catch (NSException *exception) { @@ -1128,22 +1168,60 @@ BOOL RCTCopyProperty(id target, id source, NSString *keyPath) return NO; } - // Get value NSMethodSignature *signature = [source methodSignatureForSelector:getter]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setArgument:&getter atIndex:1]; - [invocation invokeWithTarget:source]; - NSUInteger length = [signature methodReturnLength]; - void *value = malloc(length); - [invocation getReturnValue:value]; - - // Set value - signature = [target methodSignatureForSelector:setter]; - invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setArgument:&setter atIndex:1]; - [invocation setArgument:value atIndex:2]; - [invocation invokeWithTarget:target]; - free(value); + switch (signature.methodReturnType[0]) { + +#define RCT_COPY_CASE(_value, _type) \ + case _value: { \ + _type (*get)(id, SEL) = (typeof(get))objc_msgSend; \ + void (*set)(id, SEL, _type) = (typeof(set))objc_msgSend; \ + set(target, setter, get(source, getter)); \ + break; \ + } + RCT_COPY_CASE(':', SEL) + RCT_COPY_CASE('*', const char *) + RCT_COPY_CASE('c', char) + RCT_COPY_CASE('C', unsigned char) + RCT_COPY_CASE('s', short) + RCT_COPY_CASE('S', unsigned short) + RCT_COPY_CASE('i', int) + RCT_COPY_CASE('I', unsigned int) + RCT_COPY_CASE('l', long) + RCT_COPY_CASE('L', unsigned long) + RCT_COPY_CASE('q', long long) + RCT_COPY_CASE('Q', unsigned long long) + RCT_COPY_CASE('f', float) + RCT_COPY_CASE('d', double) + RCT_COPY_CASE('B', BOOL) + RCT_COPY_CASE('^', void *) + + case '@': { + id (*get)(id, SEL) = (typeof(get))objc_msgSend; + void (*set)(id, SEL, id) = (typeof(set))objc_msgSend; + set(target, setter, get(source, getter)); + break; + } + case '{': + default: { + + // Get value + void *value = malloc(signature.methodReturnLength); + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setArgument:&getter atIndex:1]; + [invocation invokeWithTarget:source]; + [invocation getReturnValue:value]; + + // Set value + signature = [target methodSignatureForSelector:setter]; + invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setArgument:&setter atIndex:1]; + [invocation setArgument:value atIndex:2]; + [invocation invokeWithTarget:target]; + free(value); + + break; + } + } return YES; } diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m index d132326464b9a3..00ed6c1f2211a1 100644 --- a/React/Base/RCTModuleMethod.m +++ b/React/Base/RCTModuleMethod.m @@ -91,7 +91,7 @@ - (instancetype)initWithObjCMethodName:(NSString *)objCMethodName [argumentBlocks addObject:^(__unused RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) { \ _logic \ [invocation setArgument:&value atIndex:index]; \ - }]; \ + }]; void (^addBlockArgument)(void) = ^{ RCT_ARG_BLOCK( From 000ab1139f0dfdcf034d9864d459fe5b91e03030 Mon Sep 17 00:00:00 2001 From: Matej Hamas Date: Fri, 24 Jul 2015 09:34:18 -0700 Subject: [PATCH 13/37] [ReactNative] Adding clear function to the react native TextInput component. --- Libraries/Components/TextInput/TextInput.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 01d6dbbfb5f744..9d4de3a770d943 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -346,6 +346,10 @@ var TextInput = React.createClass({ isInAParentText: React.PropTypes.bool }, + clear: function() { + this.setNativeProps({text: ''}); + }, + render: function() { if (Platform.OS === 'ios') { return this._renderIOS(); From a1612a7dd211e91b5f8468aa46f5bc1387eadbb2 Mon Sep 17 00:00:00 2001 From: Michael Mitchell Date: Fri, 24 Jul 2015 10:21:07 -0700 Subject: [PATCH 14/37] [ReactNative] Delete AnimationExperimental and AnimationUtils Summary: AnimationExperimental is deprecated and being removed in favor of the Animated library. Refer to https://facebook.github.io/react-native/docs/animations.html for information on how to use Animated and https://facebook.github.io/react-native/docs/animations.html#animationexperimental-deprecated for the reasoning behind this. --- Libraries/Animation/AnimationExperimental.js | 99 ------ Libraries/Animation/AnimationUtils.js | 244 -------------- .../project.pbxproj | 250 --------------- .../RCTAnimationExperimentalManager.h | 17 - .../RCTAnimationExperimentalManager.m | 299 ------------------ 5 files changed, 909 deletions(-) delete mode 100644 Libraries/Animation/AnimationExperimental.js delete mode 100644 Libraries/Animation/AnimationUtils.js delete mode 100644 Libraries/Animation/RCTAnimationExperimental.xcodeproj/project.pbxproj delete mode 100644 Libraries/Animation/RCTAnimationExperimentalManager.h delete mode 100644 Libraries/Animation/RCTAnimationExperimentalManager.m diff --git a/Libraries/Animation/AnimationExperimental.js b/Libraries/Animation/AnimationExperimental.js deleted file mode 100644 index e871c6a0d520fe..00000000000000 --- a/Libraries/Animation/AnimationExperimental.js +++ /dev/null @@ -1,99 +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 AnimationExperimental - */ -'use strict'; - -var RCTAnimationManager = require('NativeModules').AnimationExperimentalManager; -if (!RCTAnimationManager) { - // AnimationExperimental isn't available internally - this is a temporary - // workaround to enable its availability to be determined at runtime. - // For Flow let's pretend like we always export AnimationExperimental - // so all our users don't need to do null checks - module.exports = null; -} else { - -var React = require('React'); -var AnimationUtils = require('AnimationUtils'); - -type EasingFunction = (t: number) => number; - -var Properties = { - opacity: true, - position: true, - positionX: true, - positionY: true, - rotation: true, - scaleXY: true, -}; - -type ValueType = number | Array | {[key: string]: number}; - -/** - * This is an experimental module that is under development, incomplete, - * potentially buggy, not used in any production apps, and will probably change - * in non-backward compatible ways. - * - * Use at your own risk. - */ -var AnimationExperimental = { - startAnimation: function( - anim: { - node: any; - duration: number; - easing: ($Enum | EasingFunction); - property: $Enum; - toValue: ValueType; - fromValue?: ValueType; - delay?: number; - }, - callback?: ?(finished: bool) => void - ): number { - var nodeHandle = React.findNodeHandle(anim.node); - var easingSample = AnimationUtils.evaluateEasingFunction( - anim.duration, - anim.easing - ); - var tag: number = AnimationUtils.allocateTag(); - var props = {}; - props[anim.property] = {to: anim.toValue}; - RCTAnimationManager.startAnimation( - nodeHandle, - tag, - anim.duration, - anim.delay, - easingSample, - props, - callback - ); - return tag; - }, - - stopAnimation: function(tag: number) { - RCTAnimationManager.stopAnimation(tag); - }, -}; - -if (__DEV__) { - if (RCTAnimationManager && RCTAnimationManager.Properties) { - var a = Object.keys(Properties); - var b = RCTAnimationManager.Properties; - var diff = a.filter((i) => b.indexOf(i) < 0).concat( - b.filter((i) => a.indexOf(i) < 0) - ); - if (diff.length > 0) { - throw new Error('JS animation properties don\'t match native properties.' + - JSON.stringify(diff, null, ' ')); - } - } -} - -module.exports = AnimationExperimental; - -} diff --git a/Libraries/Animation/AnimationUtils.js b/Libraries/Animation/AnimationUtils.js deleted file mode 100644 index 2ee2d8a7097591..00000000000000 --- a/Libraries/Animation/AnimationUtils.js +++ /dev/null @@ -1,244 +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. - * - * The easing functions come from the the jQuery UI project. - * See http://api.jqueryui.com/easings/ - * Copyright jQuery Foundation and other contributors, https://jquery.org/ - * Copyright (c) 2008 George McGinley Smith - * Copyright (c) 2001 Robert Penner - * - * @providesModule AnimationUtils - * @flow - */ -'use strict'; - -type EasingFunction = (t: number) => number; - -var defaults = { - linear: function(t: number): number { - return t; - }, - easeInQuad: function(t: number): number { - return t * t; - }, - easeOutQuad: function(t: number): number { - return -t * (t - 2); - }, - easeInOutQuad: function(t: number): number { - t = t * 2; - if (t < 1) { - return 0.5 * t * t; - } - return -((t - 1) * (t - 3) - 1) / 2; - }, - easeInCubic: function(t: number): number { - return t * t * t; - }, - easeOutCubic: function(t: number): number { - t -= 1; - return t * t * t + 1; - }, - easeInOutCubic: function(t: number): number { - t *= 2; - if (t < 1) { - return 0.5 * t * t * t; - } - t -= 2; - return (t * t * t + 2) / 2; - }, - easeInQuart: function(t: number): number { - return t * t * t * t; - }, - easeOutQuart: function(t: number): number { - t -= 1; - return -(t * t * t * t - 1); - }, - easeInOutQuart: function(t: number): number { - t *= 2; - if (t < 1) { - return 0.5 * t * t * t * t; - } - t -= 2; - return -(t * t * t * t - 2) / 2; - }, - easeInQuint: function(t: number): number { - return t * t * t * t * t; - }, - easeOutQuint: function(t: number): number { - t -= 1; - return t * t * t * t * t + 1; - }, - easeInOutQuint: function(t: number): number { - t *= 2; - if (t < 1) { - return (t * t * t * t * t) / 2; - } - t -= 2; - return (t * t * t * t * t + 2) / 2; - }, - easeInSine: function(t: number): number { - return -Math.cos(t * (Math.PI / 2)) + 1; - }, - easeOutSine: function(t: number): number { - return Math.sin(t * (Math.PI / 2)); - }, - easeInOutSine: function(t: number): number { - return -(Math.cos(Math.PI * t) - 1) / 2; - }, - easeInExpo: function(t: number): number { - return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)); - }, - easeOutExpo: function(t: number): number { - return (t === 1) ? 1 : (-Math.pow(2, -10 * t) + 1); - }, - easeInOutExpo: function(t: number): number { - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - t *= 2; - if (t < 1) { - return 0.5 * Math.pow(2, 10 * (t - 1)); - } - return (-Math.pow(2, -10 * (t - 1)) + 2) / 2; - }, - easeInCirc: function(t: number): number { - return -(Math.sqrt(1 - t * t) - 1); - }, - easeOutCirc: function(t: number): number { - t -= 1; - return Math.sqrt(1 - t * t); - }, - easeInOutCirc: function(t: number): number { - t *= 2; - if (t < 1) { - return -(Math.sqrt(1 - t * t) - 1) / 2; - } - t -= 2; - return (Math.sqrt(1 - t * t) + 1) / 2; - }, - easeInElastic: function(t: number): number { - var s = 1.70158; - var p = 0.3; - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - var s = p / (2 * Math.PI) * Math.asin(1); - t -= 1; - return -(Math.pow(2, 10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)); - }, - easeOutElastic: function(t: number): number { - var s = 1.70158; - var p = 0.3; - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - var s = p / (2 * Math.PI) * Math.asin(1); - return Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1; - }, - easeInOutElastic: function(t: number): number { - var s = 1.70158; - var p = 0.3 * 1.5; - if (t === 0) { - return 0; - } - t *= 2; - if (t === 2) { - return 1; - } - var s = p / (2 * Math.PI) * Math.asin(1); - if (t < 1) { - t -= 1; - return -(Math.pow(2, 10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)) / 2; - } - t -= 1; - return Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) / 2 + 1; - }, - easeInBack: function(t: number): number { - var s = 1.70158; - return t * t * ((s + 1) * t - s); - }, - easeOutBack: function(t: number): number { - var s = 1.70158; - t -= 1; - return (t * t * ((s + 1) * t + s) + 1); - }, - easeInOutBack: function(t: number): number { - var s = 1.70158 * 1.525; - t *= 2; - if (t < 1) { - return (t * t * ((s + 1) * t - s)) / 2; - } - t -= 2; - return (t * t * ((s + 1) * t + s) + 2) / 2; - }, - easeInBounce: function(t: number): number { - return 1 - this.easeOutBounce(1 - t); - }, - easeOutBounce: function(t: number): number { - if (t < (1 / 2.75)) { - return 7.5625 * t * t; - } else if (t < (2 / 2.75)) { - t -= 1.5 / 2.75; - return 7.5625 * t * t + 0.75; - } else if (t < (2.5 / 2.75)) { - t -= 2.25 / 2.75; - return 7.5625 * t * t + 0.9375; - } else { - t -= 2.625 / 2.75; - return 7.5625 * t * t + 0.984375; - } - }, - easeInOutBounce: function(t: number): number { - if (t < 0.5) { - return this.easeInBounce(t * 2) / 2; - } - return this.easeOutBounce(t * 2 - 1) / 2 + 0.5; - }, -}; - -var ticksPerSecond = 60; -var lastUsedTag = 0; - -module.exports = { - /** - * Returns a new unique animation tag. - */ - allocateTag: function(): number { - return ++lastUsedTag; - }, - - /** - * Returns the values of the easing function at discrete ticks (60 per second). - */ - evaluateEasingFunction: function(duration: number, easing: string | EasingFunction): Array { - if (typeof easing === 'string') { - easing = defaults[easing] || defaults.easeOutQuad; - } - - var tickCount = Math.round(duration * ticksPerSecond / 1000); - var samples = []; - if (tickCount > 0) { - for (var i = 0; i <= tickCount; i++) { - samples.push(easing.call(defaults, i / tickCount)); - } - } - - return samples; - }, - - Defaults: defaults, -}; diff --git a/Libraries/Animation/RCTAnimationExperimental.xcodeproj/project.pbxproj b/Libraries/Animation/RCTAnimationExperimental.xcodeproj/project.pbxproj deleted file mode 100644 index 038ec7252017e7..00000000000000 --- a/Libraries/Animation/RCTAnimationExperimental.xcodeproj/project.pbxproj +++ /dev/null @@ -1,250 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 13BE3DEE1AC21097009241FE /* RCTAnimationExperimentalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* RCTAnimationExperimentalManager.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 58B511D91A9E6C8500147676 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "include/$(PRODUCT_NAME)"; - dstSubfolderSpec = 16; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 134814201AA4EA6300B7C361 /* libRCTAnimationExperimental.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimationExperimental.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 13BE3DEC1AC21097009241FE /* RCTAnimationExperimentalManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationExperimentalManager.h; sourceTree = ""; }; - 13BE3DED1AC21097009241FE /* RCTAnimationExperimentalManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationExperimentalManager.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 58B511D81A9E6C8500147676 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 134814211AA4EA7D00B7C361 /* Products */ = { - isa = PBXGroup; - children = ( - 134814201AA4EA6300B7C361 /* libRCTAnimationExperimental.a */, - ); - name = Products; - sourceTree = ""; - }; - 58B511D21A9E6C8500147676 = { - isa = PBXGroup; - children = ( - 13BE3DEC1AC21097009241FE /* RCTAnimationExperimentalManager.h */, - 13BE3DED1AC21097009241FE /* RCTAnimationExperimentalManager.m */, - 134814211AA4EA7D00B7C361 /* Products */, - ); - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 58B511DA1A9E6C8500147676 /* RCTAnimationExperimental */ = { - isa = PBXNativeTarget; - buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimationExperimental" */; - buildPhases = ( - 58B511D71A9E6C8500147676 /* Sources */, - 58B511D81A9E6C8500147676 /* Frameworks */, - 58B511D91A9E6C8500147676 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = RCTAnimationExperimental; - productName = RCTDataManager; - productReference = 134814201AA4EA6300B7C361 /* libRCTAnimationExperimental.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 58B511D31A9E6C8500147676 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0610; - ORGANIZATIONNAME = Facebook; - TargetAttributes = { - 58B511DA1A9E6C8500147676 = { - CreatedOnToolsVersion = 6.1.1; - }; - }; - }; - buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimationExperimental" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 58B511D21A9E6C8500147676; - productRefGroup = 58B511D21A9E6C8500147676; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 58B511DA1A9E6C8500147676 /* RCTAnimationExperimental */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 58B511D71A9E6C8500147676 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13BE3DEE1AC21097009241FE /* RCTAnimationExperimentalManager.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 58B511ED1A9E6C8500147676 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 58B511EE1A9E6C8500147676 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 58B511F01A9E6C8500147676 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/../../React/**", - ); - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTAnimationExperimental; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 58B511F11A9E6C8500147676 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/../../React/**", - ); - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTAnimationExperimental; - SKIP_INSTALL = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimationExperimental" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 58B511ED1A9E6C8500147676 /* Debug */, - 58B511EE1A9E6C8500147676 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimationExperimental" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 58B511F01A9E6C8500147676 /* Debug */, - 58B511F11A9E6C8500147676 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 58B511D31A9E6C8500147676 /* Project object */; -} diff --git a/Libraries/Animation/RCTAnimationExperimentalManager.h b/Libraries/Animation/RCTAnimationExperimentalManager.h deleted file mode 100644 index 0affc5233fef29..00000000000000 --- a/Libraries/Animation/RCTAnimationExperimentalManager.h +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import -#import - -#import "RCTBridgeModule.h" - -@interface RCTAnimationExperimentalManager : NSObject - -@end diff --git a/Libraries/Animation/RCTAnimationExperimentalManager.m b/Libraries/Animation/RCTAnimationExperimentalManager.m deleted file mode 100644 index cff4ece15b9ca7..00000000000000 --- a/Libraries/Animation/RCTAnimationExperimentalManager.m +++ /dev/null @@ -1,299 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "RCTAnimationExperimentalManager.h" - -#import - -#import "RCTSparseArray.h" -#import "RCTUIManager.h" -#import "RCTUtils.h" - -#if CGFLOAT_IS_DOUBLE - #define CG_APPEND(PREFIX, SUFFIX_F, SUFFIX_D) PREFIX##SUFFIX_D -#else - #define CG_APPEND(PREFIX, SUFFIX_F, SUFFIX_D) PREFIX##SUFFIX_F -#endif - -@implementation RCTAnimationExperimentalManager -{ - RCTSparseArray *_animationRegistry; // Main thread only; animation tag -> view tag - RCTSparseArray *_callbackRegistry; // Main thread only; animation tag -> callback - NSDictionary *_keypathMapping; -} - -RCT_EXPORT_MODULE() - -@synthesize bridge = _bridge; - -- (instancetype)init -{ - if ((self = [super init])) { - _animationRegistry = [[RCTSparseArray alloc] init]; - _callbackRegistry = [[RCTSparseArray alloc] init]; - _keypathMapping = @{ - @"opacity": @{ - @"keypath": @"opacity", - @"type": @"NSNumber", - }, - @"position": @{ - @"keypath": @"position", - @"type": @"CGPoint", - }, - @"positionX": @{ - @"keypath": @"position.x", - @"type": @"NSNumber", - }, - @"positionY": @{ - @"keypath": @"position.y", - @"type": @"NSNumber", - }, - @"rotation": @{ - @"keypath": @"transform.rotation.z", - @"type": @"NSNumber", - }, - @"scaleXY": @{ - @"keypath": @"transform.scale", - @"type": @"CGPoint", - }, - }; - } - - return self; -} - -- (dispatch_queue_t)methodQueue -{ - return _bridge.uiManager.methodQueue; -} - -- (id (^)(CGFloat))interpolateFrom:(CGFloat[])fromArray to:(CGFloat[])toArray count:(NSUInteger)count typeName:(const char *)typeName -{ - if (count == 1) { - CGFloat from = *fromArray, to = *toArray, delta = to - from; - return ^(CGFloat t) { - return @(from + t * delta); - }; - } - - CG_APPEND(vDSP_vsub,,D)(fromArray, 1, toArray, 1, toArray, 1, count); - - const size_t size = count * sizeof(CGFloat); - NSData *deltaData = [NSData dataWithBytes:toArray length:size]; - NSData *fromData = [NSData dataWithBytes:fromArray length:size]; - - return ^(CGFloat t) { - const CGFloat *delta = deltaData.bytes; - const CGFloat *_fromArray = fromData.bytes; - - CGFloat value[count]; - CG_APPEND(vDSP_vma,,D)(delta, 1, &t, 0, _fromArray, 1, value, 1, count); - return [NSValue valueWithBytes:value objCType:typeName]; - }; -} - -static void RCTInvalidAnimationProp(RCTSparseArray *callbacks, NSNumber *tag, NSString *key, id value) -{ - RCTResponseSenderBlock callback = callbacks[tag]; - RCTLogError(@"Invalid animation property `%@ = %@`", key, value); - if (callback) { - callback(@[@NO]); - callbacks[tag] = nil; - } - [CATransaction commit]; - return; -} - -RCT_EXPORT_METHOD(startAnimation:(NSNumber *)reactTag - animationTag:(NSNumber *)animationTag - duration:(NSTimeInterval)duration - delay:(NSTimeInterval)delay - easingSample:(NSNumberArray *)easingSample - properties:(NSDictionary *)properties - callback:(RCTResponseSenderBlock)callback) -{ - __weak RCTAnimationExperimentalManager *weakSelf = self; - [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { - RCTAnimationExperimentalManager *strongSelf = weakSelf; - - UIView *view = viewRegistry[reactTag]; - if (!view) { - RCTLogWarn(@"React tag #%@ is not registered with the view registry", reactTag); - return; - } - __block BOOL completionBlockSet = NO; - [CATransaction begin]; - for (NSString *prop in properties) { - NSString *keypath = _keypathMapping[prop][@"keypath"]; - id obj = properties[prop][@"to"]; - if (!keypath) { - return RCTInvalidAnimationProp(strongSelf->_callbackRegistry, animationTag, keypath, obj); - } - NSValue *toValue = nil; - if ([keypath isEqualToString:@"transform.scale"]) { - CGPoint point = [RCTConvert CGPoint:obj]; - if (point.x != point.y) { - return RCTInvalidAnimationProp(strongSelf->_callbackRegistry, animationTag, keypath, obj); - } - toValue = @(point.x); - } else if ([obj respondsToSelector:@selector(count)]) { - switch ([obj count]) { - case 2: - if (![obj respondsToSelector:@selector(objectForKeyedSubscript:)] || obj[@"x"]) { - toValue = [NSValue valueWithCGPoint:[RCTConvert CGPoint:obj]]; - } else { - toValue = [NSValue valueWithCGSize:[RCTConvert CGSize:obj]]; - } - break; - case 4: - toValue = [NSValue valueWithCGRect:[RCTConvert CGRect:obj]]; - break; - case 16: - toValue = [NSValue valueWithCGAffineTransform:[RCTConvert CGAffineTransform:obj]]; - break; - default: - return RCTInvalidAnimationProp(strongSelf->_callbackRegistry, animationTag, keypath, obj); - } - } else if (![obj respondsToSelector:@selector(objCType)]) { - return RCTInvalidAnimationProp(strongSelf->_callbackRegistry, animationTag, keypath, obj); - } - if (!toValue) { - toValue = obj; - } - const char *typeName = toValue.objCType; - - size_t count; - switch (typeName[0]) { - case 'i': - case 'I': - case 's': - case 'S': - case 'l': - case 'L': - case 'q': - case 'Q': - count = 1; - break; - - default: { - NSUInteger size; - NSGetSizeAndAlignment(typeName, &size, NULL); - count = size / sizeof(CGFloat); - break; - } - } - - CGFloat toFields[count]; - - switch (typeName[0]) { -#define CASE(encoding, type) \ - case encoding: { \ - type value; \ - [toValue getValue:&value]; \ - toFields[0] = value; \ - break; \ - } - - CASE('i', int) - CASE('I', unsigned int) - CASE('s', short) - CASE('S', unsigned short) - CASE('l', long) - CASE('L', unsigned long) - CASE('q', long long) - CASE('Q', unsigned long long) - -#undef CASE - - default: - [toValue getValue:toFields]; - break; - } - - NSValue *fromValue = [view.layer.presentationLayer valueForKeyPath:keypath]; -#if !CGFLOAT_IS_DOUBLE - if ([fromValue isKindOfClass:[NSNumber class]]) { - fromValue = [NSNumber numberWithFloat:[(NSNumber *)fromValue doubleValue]]; - } -#endif - CGFloat fromFields[count]; - [fromValue getValue:fromFields]; - - id (^interpolationBlock)(CGFloat t) = [strongSelf interpolateFrom:fromFields to:toFields count:count typeName:typeName]; - - NSMutableArray *sampledValues = [NSMutableArray arrayWithCapacity:easingSample.count]; - for (NSNumber *sample in easingSample) { - CGFloat t = sample.CG_APPEND(, floatValue, doubleValue); - [sampledValues addObject:interpolationBlock(t)]; - } - CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:keypath]; - animation.beginTime = CACurrentMediaTime() + delay; - animation.duration = duration; - animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; - animation.values = sampledValues; - @try { - [view.layer setValue:toValue forKey:keypath]; - NSString *animationKey = [@"RCT" stringByAppendingString:RCTJSONStringify(@{@"tag": animationTag, @"key": keypath}, nil)]; - if (!completionBlockSet) { - strongSelf->_callbackRegistry[animationTag] = callback; - [CATransaction setCompletionBlock:^{ - RCTResponseSenderBlock cb = strongSelf->_callbackRegistry[animationTag]; - if (cb) { - cb(@[@YES]); - strongSelf->_callbackRegistry[animationTag] = nil; - } - }]; - completionBlockSet = YES; - } - [view.layer addAnimation:animation forKey:animationKey]; - } - @catch (NSException *exception) { - return RCTInvalidAnimationProp(strongSelf->_callbackRegistry, animationTag, keypath, toValue); - } - } - [CATransaction commit]; - strongSelf->_animationRegistry[animationTag] = reactTag; - }]; -} - -RCT_EXPORT_METHOD(stopAnimation:(NSNumber *)animationTag) -{ - __weak RCTAnimationExperimentalManager *weakSelf = self; - [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { - RCTAnimationExperimentalManager *strongSelf = weakSelf; - - NSNumber *reactTag = strongSelf->_animationRegistry[animationTag]; - if (!reactTag) { - return; - } - - UIView *view = viewRegistry[reactTag]; - for (NSString *animationKey in view.layer.animationKeys) { - if ([animationKey hasPrefix:@"RCT{"]) { - NSDictionary *data = RCTJSONParse([animationKey substringFromIndex:3], nil); - if (animationTag.integerValue == [data[@"tag"] integerValue]) { - [view.layer removeAnimationForKey:animationKey]; - } - } - } - RCTResponseSenderBlock cb = strongSelf->_callbackRegistry[animationTag]; - if (cb) { - cb(@[@NO]); - strongSelf->_callbackRegistry[animationTag] = nil; - } - strongSelf->_animationRegistry[animationTag] = nil; - }]; -} - -- (NSDictionary *)constantsToExport -{ - return @{@"Properties": [_keypathMapping allKeys] }; -} - -@end From d10e4dbf0f33746ce0e23171940440f112b2419b Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Fri, 24 Jul 2015 12:58:12 -0700 Subject: [PATCH 15/37] [ReactNative] Use ASCII double quotes Summary: We mix ASCII double quotes with left and right quotes: https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/ListView/ListView.js#L13 Let's be consistent. --- Examples/Movies/SearchScreen.js | 2 +- Libraries/CustomComponents/LICENSE | 2 +- Libraries/CustomComponents/ListView/ListView.js | 6 +++--- Libraries/CustomComponents/ListView/ListViewDataSource.js | 6 +++--- .../Navigator/Navigation/NavigationContext.js | 6 +++--- .../Navigator/Navigation/NavigationEvent.js | 6 +++--- .../Navigator/Navigation/NavigationEventEmitter.js | 6 +++--- .../Navigation/__tests__/NavigationContext-test.js | 6 +++--- .../Navigator/Navigation/__tests__/NavigationEvent-test.js | 6 +++--- .../Navigation/__tests__/NavigationEventEmitter-test.js | 6 +++--- .../Navigation/__tests__/NavigationRouteStack-test.js | 6 +++--- Libraries/CustomComponents/Navigator/Navigator.js | 6 +++--- .../Navigator/NavigatorBreadcrumbNavigationBar.js | 6 +++--- .../Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js | 6 +++--- .../CustomComponents/Navigator/NavigatorNavigationBar.js | 6 +++--- .../Navigator/NavigatorNavigationBarStyles.ios.js | 6 +++--- .../CustomComponents/Navigator/NavigatorSceneConfigs.js | 6 +++--- .../JavaScriptAppEngine/Initialization/source-map-url.js | 2 +- 18 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Examples/Movies/SearchScreen.js b/Examples/Movies/SearchScreen.js index a88d7bfacb0b5b..477ed6a5017bc4 100644 --- a/Examples/Movies/SearchScreen.js +++ b/Examples/Movies/SearchScreen.js @@ -308,7 +308,7 @@ var NoMovies = React.createClass({ render: function() { var text = ''; if (this.props.filter) { - text = `No results for “${this.props.filter}”`; + text = `No results for "${this.props.filter}"`; } else if (!this.props.isLoading) { // If we're looking at the latest movies, aren't currently loading, and // still have no results, show a message diff --git a/Libraries/CustomComponents/LICENSE b/Libraries/CustomComponents/LICENSE index 01f2fbc020bb37..ef4ae1360ea149 100644 --- a/Libraries/CustomComponents/LICENSE +++ b/Libraries/CustomComponents/LICENSE @@ -4,6 +4,6 @@ For React Native Custom Components software Copyright (c) 2015, Facebook, Inc. All rights reserved. -Facebook, Inc. (“Facebook”) owns all right, title and interest, including all intellectual property and other proprietary rights, in and to the React Native Custom Components software (the “Software”). Subject to your compliance with these terms, you are hereby granted a non-exclusive, worldwide, royalty-free copyright license to (1) use and copy the Software; and (2) reproduce and distribute the Software as part of your own software (“Your Software”). Facebook reserves all rights not expressly granted to you in this license agreement. +Facebook, Inc. ("Facebook") owns all right, title and interest, including all intellectual property and other proprietary rights, in and to the React Native Custom Components software (the "Software"). Subject to your compliance with these terms, you are hereby granted a non-exclusive, worldwide, royalty-free copyright license to (1) use and copy the Software; and (2) reproduce and distribute the Software as part of your own software ("Your Software"). Facebook reserves all rights not expressly granted to you in this license agreement. THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED. IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js index fda582c3af5bf6..5ca25fe01a6aad 100644 --- a/Libraries/CustomComponents/ListView/ListView.js +++ b/Libraries/CustomComponents/ListView/ListView.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/ListView/ListViewDataSource.js b/Libraries/CustomComponents/ListView/ListViewDataSource.js index 18838bd72539bb..8af08f1c54d6d6 100644 --- a/Libraries/CustomComponents/ListView/ListViewDataSource.js +++ b/Libraries/CustomComponents/ListView/ListViewDataSource.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js index 7f6153a33b9271..48e721f4ba9249 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js +++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js index 3a7a3d6defd060..b1d6268dadd1b6 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js +++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js index ef63bd39d62708..a379edd7a1a79d 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js +++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationContext-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationContext-test.js index f81c9314affeb3..7a66159c47a5d5 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationContext-test.js +++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationContext-test.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js index 8ae24ddb423208..c3fc0f5ef6cc01 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js +++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js @@ -2,13 +2,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js index cc2875c814ce7b..361892084e53ca 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js +++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js index a80bf82670efb5..3340baf59c2bae 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js +++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js index f55f44e35d230c..743d914a709a73 100644 --- a/Libraries/CustomComponents/Navigator/Navigator.js +++ b/Libraries/CustomComponents/Navigator/Navigator.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js index aa9eb64cebc739..7f8debc84238ed 100644 --- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js +++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js index 69d0d52a254870..bf6a96b61b0ae6 100644 --- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js +++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js index 7b69e2635c8ba9..a2470518fe58ae 100644 --- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js +++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStyles.ios.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStyles.ios.js index fff116745bed98..769722a64210a7 100644 --- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStyles.ios.js +++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStyles.ios.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js b/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js index 37715e67896dab..32cd3363a2d3ce 100644 --- a/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js +++ b/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js @@ -1,13 +1,13 @@ /** * Copyright (c) 2015, Facebook, Inc. All rights reserved. * - * Facebook, Inc. (“Facebook”) owns all right, title and interest, including + * Facebook, Inc. ("Facebook") owns all right, title and interest, including * all intellectual property and other proprietary rights, in and to the React - * Native CustomComponents software (the “Software”). Subject to your + * Native CustomComponents software (the "Software"). Subject to your * compliance with these terms, you are hereby granted a non-exclusive, * worldwide, royalty-free copyright license to (1) use and copy the Software; * and (2) reproduce and distribute the Software as part of your own software - * (“Your Software”). Facebook reserves all rights not expressly granted to + * ("Your Software"). Facebook reserves all rights not expressly granted to * you in this license agreement. * * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS diff --git a/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js b/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js index 98610724af2c0c..8342a5a90ccfa2 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js +++ b/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js @@ -17,7 +17,7 @@ var define = null; // Hack to make it work with our packager // Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) +// X11 ("MIT") Licensed. (See LICENSE.) void (function(root, factory) { if (typeof define === "function" && define.amd) { From bf7e2a85d08b96aacc97b56f535d49f9d853044f Mon Sep 17 00:00:00 2001 From: James Ide Date: Fri, 24 Jul 2015 14:22:31 -0700 Subject: [PATCH 16/37] [Navigator] Vertically hide disabled scenes and use pointerEvents="none" Summary: Hides disabled scenes using `top` instead of `left`, which fixes a bug with the native UITabBar. When the UITabBar's width is zeroed because the scene has `left: SCREEN_WIDTH, right: 0` applied, this triggers a bug with the kerning of the tab titles. Instead, zeroing the height by setting `top: SCREEN_HEIGHT` avoids the bug. Also applies `pointerEvents="none"` to disabled scenes so that views in the off-screen scenes definitely don't receive touches, which was occurring before. Fixes #1401, fixes #2011 Closes https://github.com/facebook/react-native/pull/2104 Github Author: James Ide --- .../CustomComponents/Navigator/Navigator.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js index 743d914a709a73..6589e7d780dbfe 100644 --- a/Libraries/CustomComponents/Navigator/Navigator.js +++ b/Libraries/CustomComponents/Navigator/Navigator.js @@ -56,8 +56,9 @@ var PropTypes = React.PropTypes; var SCREEN_WIDTH = Dimensions.get('window').width; var SCREEN_HEIGHT = Dimensions.get('window').height; var SCENE_DISABLED_NATIVE_PROPS = { + pointerEvents: 'none', style: { - left: SCREEN_WIDTH, + top: SCREEN_HEIGHT, opacity: 0, }, }; @@ -107,7 +108,7 @@ var styles = StyleSheet.create({ top: 0, }, disabledScene: { - left: SCREEN_WIDTH, + top: SCREEN_HEIGHT, }, transitioner: { flex: 1, @@ -529,15 +530,18 @@ var Navigator = React.createClass({ _enableScene: function(sceneIndex) { // First, determine what the defined styles are for scenes in this navigator var sceneStyle = flattenStyle([styles.baseScene, this.props.sceneStyle]); - // Then restore the left value for this scene + // Then restore the pointer events and top value for this scene var enabledSceneNativeProps = { - left: sceneStyle.left, + pointerEvents: 'auto', + style: { + top: sceneStyle.top, + }, }; if (sceneIndex !== this.state.transitionFromIndex && sceneIndex !== this.state.presentedIndex) { // If we are not in a transition from this index, make sure opacity is 0 // to prevent the enabled scene from flashing over the presented scene - enabledSceneNativeProps.opacity = 0; + enabledSceneNativeProps.style.opacity = 0; } this.refs['scene_' + sceneIndex] && this.refs['scene_' + sceneIndex].setNativeProps(enabledSceneNativeProps); @@ -1021,8 +1025,10 @@ var Navigator = React.createClass({ _renderScene: function(route, i) { var disabledSceneStyle = null; + var disabledScenePointerEvents = 'auto'; if (i !== this.state.presentedIndex) { disabledSceneStyle = styles.disabledScene; + disabledScenePointerEvents = 'none'; } return ( { return (this.state.transitionFromIndex != null) || (this.state.transitionFromIndex != null); }} + pointerEvents={disabledScenePointerEvents} style={[styles.baseScene, this.props.sceneStyle, disabledSceneStyle]}> {this.props.renderScene( route, From c8373d2ad66192a42010f40b2e58bd157665c644 Mon Sep 17 00:00:00 2001 From: James Ide Date: Fri, 24 Jul 2015 15:24:46 -0700 Subject: [PATCH 17/37] [Chrome Debugger] Update ws dependency to 0.7.2 Summary: ws 0.7.2 officially supports io.js Closes https://github.com/facebook/react-native/pull/2013 Github Author: James Ide --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8feb81b2f0af59..b5f90776b6f5b4 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "underscore": "1.7.0", "wordwrap": "^1.0.0", "worker-farm": "^1.3.1", - "ws": "0.4.31", + "ws": "^0.7.2", "yargs": "1.3.2" }, "devDependencies": { From ea5276ed24233b1dc99558173601f34e81331884 Mon Sep 17 00:00:00 2001 From: Hedger Wang Date: Fri, 24 Jul 2015 16:50:19 -0700 Subject: [PATCH 18/37] [Navigator] Port navigation APIs from Navigator to NavigationContext --- .../Navigator/Navigation/NavigationRouteStack.js | 2 +- .../Navigator/Navigation/__tests__/NavigationRouteStack-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js index 78fbfd1576bae7..6f1f4d7a4b71e4 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js +++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js @@ -135,7 +135,7 @@ class RouteStack { ); var routes = this._routes.set(index, route); - return this._update(this._index, routes); + return this._update(index, routes); } _update(index: number, routes: List): RouteStack { diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js index 3340baf59c2bae..9752b856f30e66 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js +++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationRouteStack-test.js @@ -201,7 +201,7 @@ describe('NavigationRouteStack:', () => { expect(stack2).not.toBe(stack1); expect(stack2.toArray()).toEqual(['x', 'b']); - expect(stack2.index).toBe(1); + expect(stack2.index).toBe(0); }); it('replaces route at negative index', () => { From 5f0317291b6545f857ab35c63633f6003cf04948 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Fri, 24 Jul 2015 17:21:39 -0700 Subject: [PATCH 19/37] Switched to OSS implementation for internal apps --- Examples/UIExplorer/TextInputExample.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/UIExplorer/TextInputExample.js b/Examples/UIExplorer/TextInputExample.js index b2a42ffeb0294d..d51a95e33bb5fd 100644 --- a/Examples/UIExplorer/TextInputExample.js +++ b/Examples/UIExplorer/TextInputExample.js @@ -411,7 +411,7 @@ exports.examples = [ style={styles.multiline} /> Date: Fri, 24 Jul 2015 18:31:41 -0700 Subject: [PATCH 20/37] [Packager] Include Content-Type headers with bundle and source maps Summary: The packager did not send back the Content-Type headers. Adding these. Closes https://github.com/facebook/react-native/pull/2029 Github Author: James Ide --- .../react-packager/src/Server/__tests__/Server-test.js | 1 + packager/react-packager/src/Server/index.js | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js index 32c9060a4ecf25..7d399cb2a3bcfc 100644 --- a/packager/react-packager/src/Server/__tests__/Server-test.js +++ b/packager/react-packager/src/Server/__tests__/Server-test.js @@ -39,6 +39,7 @@ describe('processRequest', function() { requestHandler( { url: requrl }, { + setHeader: jest.genMockFunction(), end: function(res) { resolve(res); } diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js index 1d2140ef508c8e..a4ee53ef63171b 100644 --- a/packager/react-packager/src/Server/index.js +++ b/packager/react-packager/src/Server/index.js @@ -358,13 +358,17 @@ Server.prototype.processRequest = function(req, res, next) { building.then( function(p) { if (requestType === 'bundle') { - res.end(p.getSource({ + var bundleSource = p.getSource({ inlineSourceMap: options.inlineSourceMap, minify: options.minify, - })); + }); + res.setHeader('Content-Type', 'application/javascript'); + res.end(bundleSource); Activity.endEvent(startReqEventId); } else if (requestType === 'map') { - res.end(JSON.stringify(p.getSourceMap())); + var sourceMap = JSON.stringify(p.getSourceMap()); + res.setHeader('Content-Type', 'application/json'); + res.end(sourceMap); Activity.endEvent(startReqEventId); } }, From f1bd1cbc942662e93035d16aebd8b5c311298cee Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Fri, 24 Jul 2015 18:31:55 -0700 Subject: [PATCH 21/37] [ReactNative] cleanup native components --- .../ActivityIndicatorIOS.ios.js | 12 +----- .../Components/Navigation/NavigatorIOS.ios.js | 39 ++----------------- .../ProgressViewIOS/ProgressViewIOS.ios.js | 1 - .../SegmentedControlIOS.ios.js | 1 - Libraries/Image/Image.ios.js | 19 +++++++-- Libraries/ReactIOS/requireNativeComponent.js | 16 ++++++-- Libraries/ReactIOS/verifyPropTypes.js | 18 ++++++--- .../createReactNativeComponentClass.js | 2 + 8 files changed, 49 insertions(+), 59 deletions(-) diff --git a/Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js b/Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js index 53390cabed3e6a..7e0ea69363f32e 100644 --- a/Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js +++ b/Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js @@ -18,7 +18,6 @@ var StyleSheet = require('StyleSheet'); var View = require('View'); var requireNativeComponent = require('requireNativeComponent'); -var verifyPropTypes = require('verifyPropTypes'); var GRAY = '#999999'; @@ -99,15 +98,8 @@ var styles = StyleSheet.create({ var RCTActivityIndicatorView = requireNativeComponent( 'RCTActivityIndicatorView', - null + ActivityIndicatorIOS, + {nativeOnly: {activityIndicatorViewStyle: true}}, ); -if (__DEV__) { - var nativeOnlyProps = {activityIndicatorViewStyle: true}; - verifyPropTypes( - ActivityIndicatorIOS, - RCTActivityIndicatorView.viewConfig, - nativeOnlyProps - ); -} module.exports = ActivityIndicatorIOS; diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js index 5d47b4df6e2447..4c8e1b6e7e3bed 100644 --- a/Libraries/Components/Navigation/NavigatorIOS.ios.js +++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js @@ -15,17 +15,14 @@ var EventEmitter = require('EventEmitter'); var Image = require('Image'); var NavigationContext = require('NavigationContext'); var React = require('React'); -var ReactNativeViewAttributes = require('ReactNativeViewAttributes'); var RCTNavigatorManager = require('NativeModules').NavigatorManager; var StyleSheet = require('StyleSheet'); var StaticContainer = require('StaticContainer.react'); var View = require('View'); -var createReactNativeComponentClass = - require('createReactNativeComponentClass'); +var requireNativeComponent = require('requireNativeComponent'); var invariant = require('invariant'); var logError = require('logError'); -var merge = require('merge'); var TRANSITIONER_REF = 'transitionerRef'; @@ -36,37 +33,6 @@ function getuid() { return __uid++; } -var RCTNavigator = createReactNativeComponentClass({ - validAttributes: merge(ReactNativeViewAttributes.UIView, { - requestedTopOfStack: true - }), - uiViewClassName: 'RCTNavigator', -}); - -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 - title: true, - barTintColor: true, - leftButtonIcon: true, - leftButtonTitle: true, - onNavLeftButtonTap: true, - rightButtonIcon: true, - rightButtonTitle: true, - onNavRightButtonTap: true, - backButtonIcon: true, - backButtonTitle: true, - tintColor: true, - translucent: true, - navigationBarHidden: true, - shadowHidden: true, - titleTextColor: true, - style: true, - }, - uiViewClassName: 'RCTNavItem', -}); - var NavigatorTransitionerIOS = React.createClass({ requestSchedulingNavigation: function(cb) { RCTNavigatorManager.requestSchedulingJavaScriptNavigation( @@ -711,4 +677,7 @@ var styles = StyleSheet.create({ }, }); +var RCTNavigator = requireNativeComponent('RCTNavigator'); +var RCTNavigatorItem = requireNativeComponent('RCTNavItem'); + module.exports = NavigatorIOS; diff --git a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js index cbdf43ae5729a5..c8ff595d580b8f 100644 --- a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js +++ b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js @@ -19,7 +19,6 @@ var React = require('React'); var StyleSheet = require('StyleSheet'); var requireNativeComponent = require('requireNativeComponent'); -var verifyPropTypes = require('verifyPropTypes'); /** * Use `ProgressViewIOS` to render a UIProgressView on iOS. diff --git a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js index ec3b6c6147622f..0fcc92e884d2cf 100644 --- a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js +++ b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js @@ -18,7 +18,6 @@ var React = require('React'); var StyleSheet = require('StyleSheet'); var requireNativeComponent = require('requireNativeComponent'); -var verifyPropTypes = require('verifyPropTypes'); type DefaultProps = { values: Array; diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index 549b3dee928a44..1674fb8a505dda 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -26,7 +26,6 @@ var flattenStyle = require('flattenStyle'); var invariant = require('invariant'); var requireNativeComponent = require('requireNativeComponent'); var resolveAssetSource = require('resolveAssetSource'); -var verifyPropTypes = require('verifyPropTypes'); var warning = require('warning'); /** @@ -150,6 +149,12 @@ var Image = React.createClass({ }, render: function() { + for (var prop in cfg.nativeOnly) { + if (this.props[prop] !== undefined) { + console.warn('Prop `' + prop + ' = ' + this.props[prop] + '` should ' + + 'not be set directly on Image.'); + } + } var source = resolveAssetSource(this.props.source) || {}; var defaultSource = (this.props.defaultSource && resolveAssetSource(this.props.defaultSource)) || {}; @@ -180,7 +185,15 @@ var styles = StyleSheet.create({ }, }); -var RCTImageView = requireNativeComponent('RCTImageView', null); -var RCTNetworkImageView = (NativeModules.NetworkImageViewManager) ? requireNativeComponent('RCTNetworkImageView', null) : RCTImageView; +var cfg = { + nativeOnly: { + src: true, + defaultImageSrc: true, + imageTag: true, + progressHandlerRegistered: true, + }, +}; +var RCTImageView = requireNativeComponent('RCTImageView', Image, cfg); +var RCTNetworkImageView = (NativeModules.NetworkImageViewManager) ? requireNativeComponent('RCTNetworkImageView', Image, cfg) : RCTImageView; module.exports = Image; diff --git a/Libraries/ReactIOS/requireNativeComponent.js b/Libraries/ReactIOS/requireNativeComponent.js index 716b8f8068f702..b291c7abee7b3c 100644 --- a/Libraries/ReactIOS/requireNativeComponent.js +++ b/Libraries/ReactIOS/requireNativeComponent.js @@ -27,19 +27,22 @@ var warning = require('warning'); * implementations. Config information is extracted from data exported from the * RCTUIManager module. You should also wrap the native component in a * hand-written component with full propTypes definitions and other - * documentation - pass the hand-written component in as `wrapperComponent` to + * documentation - pass the hand-written component in as `componentInterface` to * verify all the native props are documented via `propTypes`. * * If some native props shouldn't be exposed in the wrapper interface, you can - * pass null for `wrapperComponent` and call `verifyPropTypes` directly + * pass null for `componentInterface` and call `verifyPropTypes` directly * with `nativePropsToIgnore`; * * Common types are lined up with the appropriate prop differs with * `TypeToDifferMap`. Non-scalar types not in the map default to `deepDiffer`. */ +import type { ComponentInterface } from 'verifyPropTypes'; + function requireNativeComponent( viewName: string, - wrapperComponent: ?Function + componentInterface?: ?ComponentInterface, + extraConfig?: ?{nativeOnly?: Object}, ): Function { var viewConfig = RCTUIManager[viewName]; if (!viewConfig || !viewConfig.NativeProps) { @@ -52,12 +55,17 @@ function requireNativeComponent( }; viewConfig.uiViewClassName = viewName; viewConfig.validAttributes = {}; + viewConfig.propTypes = componentInterface && componentInterface.propTypes; for (var key in nativeProps) { var differ = TypeToDifferMap[nativeProps[key]]; viewConfig.validAttributes[key] = differ ? {diff: differ} : true; } if (__DEV__) { - wrapperComponent && verifyPropTypes(wrapperComponent, viewConfig); + componentInterface && verifyPropTypes( + componentInterface, + viewConfig, + extraConfig && extraConfig.nativeOnly + ); } return createReactNativeComponentClass(viewConfig); } diff --git a/Libraries/ReactIOS/verifyPropTypes.js b/Libraries/ReactIOS/verifyPropTypes.js index 73cb57e9fc14a5..02715c080772ef 100644 --- a/Libraries/ReactIOS/verifyPropTypes.js +++ b/Libraries/ReactIOS/verifyPropTypes.js @@ -14,16 +14,24 @@ var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); var View = require('View'); +export type ComponentInterface = ReactClass | { + name?: string; + displayName?: string; + propTypes: Object; +}; + function verifyPropTypes( - component: Function, + componentInterface: ComponentInterface, viewConfig: Object, - nativePropsToIgnore?: Object + nativePropsToIgnore?: ?Object ) { if (!viewConfig) { return; // This happens for UnimplementedView. } - var componentName = component.name || component.displayName; - if (!component.propTypes) { + var componentName = componentInterface.name || + componentInterface.displayName || + 'unknown'; + if (!componentInterface.propTypes) { throw new Error( '`' + componentName + '` has no propTypes defined`' ); @@ -31,7 +39,7 @@ function verifyPropTypes( var nativeProps = viewConfig.NativeProps; for (var prop in nativeProps) { - if (!component.propTypes[prop] && + if (!componentInterface.propTypes[prop] && !View.propTypes[prop] && !ReactNativeStyleAttributes[prop] && (!nativePropsToIgnore || !nativePropsToIgnore[prop])) { diff --git a/Libraries/ReactNative/createReactNativeComponentClass.js b/Libraries/ReactNative/createReactNativeComponentClass.js index 5d6d87cd8f2a01..18937f9cf367d9 100644 --- a/Libraries/ReactNative/createReactNativeComponentClass.js +++ b/Libraries/ReactNative/createReactNativeComponentClass.js @@ -18,6 +18,7 @@ var ReactNativeBaseComponent = require('ReactNativeBaseComponent'); type ReactNativeBaseComponentViewConfig = { validAttributes: Object; uiViewClassName: string; + propTypes?: Object, } /** @@ -36,6 +37,7 @@ var createReactNativeComponentClass = function( }; Constructor.displayName = viewConfig.uiViewClassName; Constructor.viewConfig = viewConfig; + Constructor.propTypes = viewConfig.propTypes; Constructor.prototype = new ReactNativeBaseComponent(viewConfig); Constructor.prototype.constructor = Constructor; From aca76c75dd54321da1f8c4a60057b0d727ed7605 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 27 Jul 2015 01:15:53 -0700 Subject: [PATCH 22/37] Fix gzip on iOS 9 --- React/Base/RCTUtils.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m index c577bf00c25c16..8f58753595f147 100644 --- a/React/Base/RCTUtils.m +++ b/React/Base/RCTUtils.m @@ -386,7 +386,7 @@ BOOL RCTIsGzippedData(NSData *data) return input; } - void *libz = dlopen("libz.dylib", RTLD_NOW); + void *libz = dlopen("/usr/lib/libz.dylib", RTLD_LAZY); int (*deflateInit2_)(z_streamp, int, int, int, int, int, const char *, int) = dlsym(libz, "deflateInit2_"); int (*deflate)(z_streamp, int) = dlsym(libz, "deflate"); int (*deflateEnd)(z_streamp) = dlsym(libz, "deflateEnd"); From f69e33e6a8c6a02a53cbed346baaacb2e6c32011 Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Mon, 27 Jul 2015 06:22:44 -0700 Subject: [PATCH 23/37] [ReactNative] Text docs Summary: In preparation for open sourcing React Native for Android, document which Text props are platform-specific. --- Libraries/Text/Text.js | 23 ++++++++-------- Libraries/Text/TextStylePropTypes.js | 40 +++++++++++++++++++++------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index d02733749bebd7..cc1b93d4c9c71e 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -74,19 +74,24 @@ var Text = React.createClass({ propTypes: { /** * Used to truncate the text with an elipsis after computing the text - * layout, including line wrapping, such that the total number of lines does - * not exceed this number. + * layout, including line wrapping, such that the total number of lines + * does not exceed this number. */ numberOfLines: React.PropTypes.number, /** - * This function is called on press. Text intrinsically supports press - * handling with a default highlight state (which can be disabled with - * `suppressHighlighting`). + * Invoked on mount and layout changes with + * + * `{nativeEvent: {layout: {x, y, width, height}}}` + */ + onLayout: React.PropTypes.func, + /** + * This function is called on press. */ onPress: React.PropTypes.func, /** - * When true, no visual change is made when text is pressed down. By + * When true, no visual change is made when text is pressed down. By * default, a gray oval highlights the text on press down. + * @platform ios */ suppressHighlighting: React.PropTypes.bool, style: stylePropType, @@ -94,12 +99,6 @@ var Text = React.createClass({ * Used to locate this view in end-to-end tests. */ testID: React.PropTypes.string, - /** - * Invoked on mount and layout changes with - * - * {nativeEvent: {layout: {x, y, width, height}}}. - */ - onLayout: React.PropTypes.func, }, viewConfig: viewConfig, diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js index 041a0d3e0b1ecf..cbd6249360f96f 100644 --- a/Libraries/Text/TextStylePropTypes.js +++ b/Libraries/Text/TextStylePropTypes.js @@ -16,30 +16,52 @@ var ViewStylePropTypes = require('ViewStylePropTypes'); // TODO: use spread instead of Object.assign/create after #6560135 is fixed var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), { + color: ReactPropTypes.string, fontFamily: ReactPropTypes.string, fontSize: ReactPropTypes.number, + fontStyle: ReactPropTypes.oneOf(['normal', 'italic']), + /** + * Specifies font weight. The values 'normal' and 'bold' are supported for + * most fonts. Not all fonts have a variant for each of the numeric values, + * in that case the closest one is chosen. + */ fontWeight: ReactPropTypes.oneOf( ['normal' /*default*/, 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'] ), - fontStyle: ReactPropTypes.oneOf(['normal', 'italic']), + /** + * @platform ios + */ + letterSpacing: ReactPropTypes.number, lineHeight: ReactPropTypes.number, - color: ReactPropTypes.string, - // NOTE: 'justify is supported only on iOS + /** + * Specifies text alignment. The value 'justify' is only supported on iOS. + */ textAlign: ReactPropTypes.oneOf( ['auto' /*default*/, 'left', 'right', 'center', 'justify'] ), - writingDirection: ReactPropTypes.oneOf( - ['auto' /*default*/, 'ltr', 'rtl'] - ), - letterSpacing: ReactPropTypes.number, - textDecorationLine:ReactPropTypes.oneOf( + /** + * @platform ios + */ + textDecorationLine: ReactPropTypes.oneOf( ['none' /*default*/, 'underline', 'line-through', 'underline line-through'] ), - textDecorationStyle:ReactPropTypes.oneOf( + /** + * @platform ios + */ + textDecorationStyle: ReactPropTypes.oneOf( ['solid' /*default*/, 'double', 'dotted','dashed'] ), + /** + * @platform ios + */ textDecorationColor: ReactPropTypes.string, + /** + * @platform ios + */ + writingDirection: ReactPropTypes.oneOf( + ['auto' /*default*/, 'ltr', 'rtl'] + ), }); // Text doesn't support padding correctly (#4841912) From c3d194d1f88262c8356ede126b5219e5989de056 Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Mon, 27 Jul 2015 06:20:37 -0700 Subject: [PATCH 24/37] [ReactNative] TextInput docs --- Libraries/Components/TextInput/TextInput.js | 62 ++++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 9d4de3a770d943..63c9c7bdca4764 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -73,8 +73,8 @@ type Event = Object; * types, such as a numeric keypad. * * The simplest use case is to plop down a `TextInput` and subscribe to the - * `onChangeText` events to read the user input. There are also other events, - * such as `onSubmitEditing` and `onFocus` that can be subscribed to. A simple + * `onChangeText` events to read the user input. There are also other events, + * such as `onSubmitEditing` and `onFocus` that can be subscribed to. A simple * example: * * ``` @@ -97,7 +97,6 @@ type Event = Object; * onSubmitEditing: true, * }; */ - var TextInput = React.createClass({ propTypes: { /** @@ -115,32 +114,44 @@ var TextInput = React.createClass({ 'characters', ]), /** - * If false, disables auto-correct. Default value is true. + * If false, disables auto-correct. The default value is true. */ autoCorrect: PropTypes.bool, /** - * If true, focuses the input on componentDidMount. Default value is false. + * If true, focuses the input on componentDidMount. + * The default value is false. */ autoFocus: PropTypes.bool, /** * Set the position of the cursor from where editing will begin. + * @platorm android */ textAlign: PropTypes.oneOf([ 'start', 'center', 'end', ]), + /** + * Aligns text vertically within the TextInput. + * @platform android + */ textAlignVertical: PropTypes.oneOf([ 'top', 'center', 'bottom', ]), /** - * If false, text is not editable. Default value is true. + * If false, text is not editable. The default value is true. + * @platform ios */ editable: PropTypes.bool, /** * Determines which keyboard to open, e.g.`numeric`. + * + * The following values work across platforms: + * - default + * - numeric + * - email-address */ keyboardType: PropTypes.oneOf([ // Cross-platform @@ -160,6 +171,7 @@ var TextInput = React.createClass({ ]), /** * Determines how the return key should look. + * @platform ios */ returnKeyType: PropTypes.oneOf([ 'default', @@ -175,17 +187,20 @@ var TextInput = React.createClass({ 'emergency-call', ]), /** - * Limits the maximum number of characters that can be entered. Use this + * Limits the maximum number of characters that can be entered. Use this * instead of implementing the logic in JS to avoid flicker. + * @platform ios */ maxLength: PropTypes.number, /** * If true, the keyboard disables the return key when there is no text and - * automatically enables it when there is text. Default value is false. + * automatically enables it when there is text. The default value is false. + * @platform ios */ enablesReturnKeyAutomatically: PropTypes.bool, /** - * If true, the text input can be multiple lines. Default value is false. + * If true, the text input can be multiple lines. + * The default value is false. */ multiline: PropTypes.bool, /** @@ -214,14 +229,9 @@ var TextInput = React.createClass({ */ onSubmitEditing: PropTypes.func, /** - * Invoked on mount and layout changes with {x, y, width, height}. + * Invoked on mount and layout changes with `{x, y, width, height}`. */ onLayout: PropTypes.func, - /** - * If true, the text input obscures the text entered so that sensitive text - * like passwords stay secure. Default value is false. - */ - password: PropTypes.bool, /** * The string that will be rendered before text input has been entered */ @@ -230,17 +240,23 @@ var TextInput = React.createClass({ * The text color of the placeholder string */ placeholderTextColor: PropTypes.string, + /** + * If true, the text input obscures the text entered so that sensitive text + * like passwords stay secure. The default value is false. + */ + secureTextEntry: PropTypes.bool, /** * See DocumentSelectionState.js, some state that is responsible for * maintaining selection information for a document + * @platform ios */ selectionState: PropTypes.instanceOf(DocumentSelectionState), /** - * The value to show for the text input. TextInput is a controlled + * The value to show for the text input. TextInput is a controlled * component, which means the native value will be forced to match this - * value prop if provided. For most uses this works great, but in some + * value prop if provided. For most uses this works great, but in some * cases this may cause flickering - one common cause is preventing edits - * by keeping value the same. In addition to simply setting the same value, + * by keeping value the same. In addition to simply setting the same value, * either set `editable={false}`, or set/update `maxLength` to prevent * unwanted edits without flicker. */ @@ -253,6 +269,7 @@ var TextInput = React.createClass({ defaultValue: PropTypes.string, /** * When the clear button should appear on the right side of the text view + * @platform ios */ clearButtonMode: PropTypes.oneOf([ 'never', @@ -262,10 +279,12 @@ var TextInput = React.createClass({ ]), /** * If true, clears the text field automatically when editing begins + * @platform ios */ clearTextOnFocus: PropTypes.bool, /** - * If true, selected the text automatically when editing begins + * If true, all text will automatically be selected on focus + * @platform ios */ selectTextOnFocus: PropTypes.bool, /** @@ -273,11 +292,12 @@ var TextInput = React.createClass({ */ style: Text.propTypes.style, /** - * Used to locate this view in end-to-end tests. + * Used to locate this view in end-to-end tests */ testID: PropTypes.string, /** - * The color of the textInput underline. Is only supported on Android. + * The color of the textInput underline. + * @platform android */ underlineColorAndroid: PropTypes.string, }, From 0e5422f36c36a809327a5aa438533a56b20304be Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 27 Jul 2015 07:19:31 -0700 Subject: [PATCH 25/37] Fixed text highlight alignment when text has nonzero padding. Summary: Previously the text highlight overlay did not take padding into account in its positioning, so it would be misaligned for padded text. This fixes that. --- Libraries/Text/RCTText.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries/Text/RCTText.m b/Libraries/Text/RCTText.m index 23dabfbc559b55..6d182619c45998 100644 --- a/Libraries/Text/RCTText.m +++ b/Libraries/Text/RCTText.m @@ -103,6 +103,7 @@ - (void)drawRect:(CGRect)rect _highlightLayer.fillColor = [UIColor colorWithWhite:0 alpha:0.25].CGColor; [self.layer addSublayer:_highlightLayer]; } + _highlightLayer.position = (CGPoint){_contentInset.left, _contentInset.top}; _highlightLayer.path = highlightPath.CGPath; } else { [_highlightLayer removeFromSuperlayer]; From f9abb5aae2fc752a5c32761336ac4b38bcfdc6da Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 27 Jul 2015 07:19:38 -0700 Subject: [PATCH 26/37] Fixed missing redbox at startup Summary: Fixed bug where redbox errors thrown during startup would be dismissed as soon as JS loaded, so they would never be seen. --- React/Base/RCTBatchedBridge.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index a38476f4db525b..88640487a3773e 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -282,7 +282,14 @@ - (void)initJS return; } - [[RCTRedBox sharedInstance] dismiss]; + static BOOL shouldDismiss = NO; + if (shouldDismiss) { + [[RCTRedBox sharedInstance] dismiss]; + } + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shouldDismiss = YES; + }); RCTSourceCode *sourceCodeModule = self.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])]; sourceCodeModule.scriptURL = bundleURL; From d178e27939fe596ec4740c145e384e7aeb3bef85 Mon Sep 17 00:00:00 2001 From: Alex Akers Date: Mon, 27 Jul 2015 08:21:08 -0700 Subject: [PATCH 27/37] Fix UIExplorer freezing / persistence --- Examples/UIExplorer/UIExplorerList.ios.js | 37 ++++++++++++++--------- Examples/UIExplorer/UIExplorerList.js | 9 ------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js index 2e1c444f10eaee..d2e04063be377a 100644 --- a/Examples/UIExplorer/UIExplorerList.ios.js +++ b/Examples/UIExplorer/UIExplorerList.ios.js @@ -121,23 +121,30 @@ class UIExplorerList extends React.Component { ); } - componentWillMount() { - this.props.navigator.navigationContext.addListener('didfocus', function(event) { - if (event.data.route.title === 'UIExplorer') { - Settings.set({visibleExample: null}); - } - }); - } - componentDidMount() { - var visibleExampleTitle = Settings.get('visibleExample'); - if (visibleExampleTitle) { - var predicate = (example) => example.title === visibleExampleTitle; - var foundExample = APIS.find(predicate) || COMPONENTS.find(predicate); - if (foundExample) { - setTimeout(() => this._openExample(foundExample), 100); + var wasUIExplorer = false; + var didOpenExample = false; + + this.props.navigator.navigationContext.addListener('didfocus', (event) => { + var isUIExplorer = event.data.route.title === 'UIExplorer'; + + if (!didOpenExample && isUIExplorer) { + didOpenExample = true; + + var visibleExampleTitle = Settings.get('visibleExample'); + if (visibleExampleTitle) { + var predicate = (example) => example.title === visibleExampleTitle; + var foundExample = APIS.find(predicate) || COMPONENTS.find(predicate); + if (foundExample) { + setTimeout(() => this._openExample(foundExample), 100); + } + } else if (!wasUIExplorer && isUIExplorer) { + Settings.set({visibleExample: null}); + } } - } + + wasUIExplorer = isUIExplorer; + }); } renderAdditionalView(renderRow: Function, renderTextInput: Function): React.Component { diff --git a/Examples/UIExplorer/UIExplorerList.js b/Examples/UIExplorer/UIExplorerList.js index c3fc0492a2f0f3..cbb24a1260d7cf 100644 --- a/Examples/UIExplorer/UIExplorerList.js +++ b/Examples/UIExplorer/UIExplorerList.js @@ -166,15 +166,6 @@ class UIExplorerList extends React.Component { componentDidMount() { this._search(this.state.searchText); - - var visibleExampleTitle = Settings.get('visibleExample'); - if (visibleExampleTitle) { - var predicate = (example) => example.title === visibleExampleTitle; - var foundExample = APIS.find(predicate) || COMPONENTS.find(predicate); - if (foundExample) { - setTimeout(() => this._openExample(foundExample), 100); - } - } } render() { From 2c5290946bd7d06fc4138b8c7ffd2061a55d401d Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 27 Jul 2015 08:48:31 -0700 Subject: [PATCH 28/37] Converted RCTImageLoader to be a bridge module --- Libraries/Image/RCTCameraRollManager.m | 6 ++-- Libraries/Image/RCTImageLoader.h | 36 +++++++++++-------- Libraries/Image/RCTImageLoader.m | 44 ++++++++++++++++-------- Libraries/Image/RCTImageRequestHandler.m | 15 +++++--- Libraries/Image/RCTImageView.m | 13 ++++--- 5 files changed, 71 insertions(+), 43 deletions(-) diff --git a/Libraries/Image/RCTCameraRollManager.m b/Libraries/Image/RCTCameraRollManager.m index 3d331a8f15e95e..d28198ac089456 100644 --- a/Libraries/Image/RCTCameraRollManager.m +++ b/Libraries/Image/RCTCameraRollManager.m @@ -29,12 +29,12 @@ @implementation RCTCameraRollManager successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseErrorBlock)errorCallback) { - [RCTImageLoader loadImageWithTag:imageTag bridge:_bridge callback:^(NSError *loadError, UIImage *loadedImage) { + [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) { if (loadError) { errorCallback(loadError); return; } - [[RCTImageLoader assetsLibrary] writeImageToSavedPhotosAlbum:[loadedImage CGImage] metadata:nil completionBlock:^(NSURL *assetURL, NSError *saveError) { + [_bridge.assetsLibrary writeImageToSavedPhotosAlbum:[loadedImage CGImage] metadata:nil completionBlock:^(NSURL *assetURL, NSError *saveError) { if (saveError) { RCTLogWarn(@"Error saving cropped image: %@", saveError); errorCallback(saveError); @@ -96,7 +96,7 @@ - (void)callCallback:(RCTResponseSenderBlock)callback withAssets:(NSArray *)asse BOOL __block calledCallback = NO; NSMutableArray *assets = [[NSMutableArray alloc] init]; - [[RCTImageLoader assetsLibrary] enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) { + [_bridge.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) { if (group && (groupName == nil || [groupName isEqualToString:[group valueForProperty:ALAssetsGroupPropertyName]])) { if (assetType == nil || [assetType isEqualToString:@"Photos"]) { diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h index 5498f23b710b57..f86d2a1d89f8f6 100644 --- a/Libraries/Image/RCTImageLoader.h +++ b/Libraries/Image/RCTImageLoader.h @@ -9,37 +9,31 @@ #import +#import "RCTBridge.h" + @class ALAssetsLibrary; -@class RCTBridge; typedef void (^RCTImageLoaderProgressBlock)(int64_t written, int64_t total); -typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, id /* UIImage or CAAnimation */); +typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, id image /* UIImage or CAAnimation */); typedef void (^RCTImageLoaderCancellationBlock)(void); -@interface RCTImageLoader : NSObject - -/** - * The shared asset library instance. - */ -+ (ALAssetsLibrary *)assetsLibrary; +@interface RCTImageLoader : NSObject /** - * Can be called from any thread. - * Will always call callback on main thread. + * Loads the specified image at the highest available resolution. + * Can be called from any thread, will always call callback on main thread. */ -+ (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag - bridge:(RCTBridge *)bridge +- (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag callback:(RCTImageLoaderCompletionBlock)callback; /** * As above, but includes target size, scale and resizeMode, which are used to * select the optimal dimensions for the loaded image. */ -+ (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag +- (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag size:(CGSize)size scale:(CGFloat)scale resizeMode:(UIViewContentMode)resizeMode - bridge:(RCTBridge *)bridge progressBlock:(RCTImageLoaderProgressBlock)progress completionBlock:(RCTImageLoaderCompletionBlock)completion; @@ -54,3 +48,17 @@ typedef void (^RCTImageLoaderCancellationBlock)(void); + (BOOL)isRemoteImage:(NSString *)imageTag; @end + +@interface RCTBridge (RCTImageLoader) + +/** + * The shared image loader instance + */ +@property (nonatomic, readonly) RCTImageLoader *imageLoader; + +/** + * The shared asset library instance. + */ +@property (nonatomic, readonly) ALAssetsLibrary *assetsLibrary; + +@end diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index c9aeff5fed9fdc..191472a915c1be 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -48,26 +48,21 @@ static dispatch_queue_t RCTImageLoaderQueue(void) } @implementation RCTImageLoader - -+ (ALAssetsLibrary *)assetsLibrary { - static ALAssetsLibrary *assetsLibrary = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - assetsLibrary = [[ALAssetsLibrary alloc] init]; - }); - return assetsLibrary; + ALAssetsLibrary *_assetsLibrary; } -+ (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag - bridge:(RCTBridge *)bridge +@synthesize bridge = _bridge; + +RCT_EXPORT_MODULE() + +- (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag callback:(RCTImageLoaderCompletionBlock)callback { return [self loadImageWithTag:imageTag size:CGSizeZero scale:0 resizeMode:UIViewContentModeScaleToFill - bridge:bridge progressBlock:nil completionBlock:callback]; } @@ -116,11 +111,18 @@ + (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag return nil; } -+ (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag +- (ALAssetsLibrary *)assetsLibrary +{ + if (!_assetsLibrary) { + _assetsLibrary = [[ALAssetsLibrary alloc] init]; + } + return _assetsLibrary; +} + +- (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag size:(CGSize)size scale:(CGFloat)scale resizeMode:(UIViewContentMode)resizeMode - bridge:(RCTBridge *)bridge progressBlock:(RCTImageLoaderProgressBlock)progress completionBlock:(RCTImageLoaderCompletionBlock)completion { @@ -229,7 +231,7 @@ + (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag }]; } } else if ([imageTag hasPrefix:@"rct-image-store://"]) { - [bridge.imageStoreManager getImageForTag:imageTag withBlock:^(UIImage *image) { + [_bridge.imageStoreManager getImageForTag:imageTag withBlock:^(UIImage *image) { if (image) { RCTDispatchCallbackOnMainQueue(completion, nil, image); } else { @@ -273,3 +275,17 @@ + (BOOL)isRemoteImage:(NSString *)imageTag } @end + +@implementation RCTBridge (RCTImageLoader) + +- (RCTImageLoader *)imageLoader +{ + return self.modules[RCTBridgeModuleNameForClass([RCTImageLoader class])]; +} + +- (ALAssetsLibrary *)assetsLibrary +{ + return [self.imageLoader assetsLibrary]; +} + +@end diff --git a/Libraries/Image/RCTImageRequestHandler.m b/Libraries/Image/RCTImageRequestHandler.m index c1f485b3382983..595c9424715cbc 100644 --- a/Libraries/Image/RCTImageRequestHandler.m +++ b/Libraries/Image/RCTImageRequestHandler.m @@ -15,9 +15,6 @@ #import "RCTUtils.h" @implementation RCTImageRequestHandler -{ - NSInteger _currentToken; -} RCT_EXPORT_MODULE() @@ -31,9 +28,10 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request - (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate { - NSNumber *requestToken = @(++_currentToken); NSString *URLString = [request.URL absoluteString]; - [RCTImageLoader loadImageWithTag:URLString bridge:_bridge callback:^(NSError *error, UIImage *image) { + + __block RCTImageLoaderCancellationBlock requestToken = nil; + requestToken = [_bridge.imageLoader loadImageWithTag:URLString callback:^(NSError *error, UIImage *image) { if (error) { [delegate URLRequest:requestToken didCompleteWithError:error]; return; @@ -62,4 +60,11 @@ - (id)sendRequest:(NSURLRequest *)request return requestToken; } +- (void)cancelRequest:(id /* RCTImageLoaderCancellationBlock */)requestToken +{ + if (requestToken) { + ((RCTImageLoaderCancellationBlock)requestToken)(); + } +} + @end diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index ea7b6047eab4fa..e0a26a3ceba80a 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -120,13 +120,12 @@ - (void)reloadImage }; } - [RCTImageLoader loadImageWithTag:_src - size:self.bounds.size - scale:RCTScreenScale() - resizeMode:self.contentMode - bridge:_bridge - progressBlock:progressHandler - completionBlock:^(NSError *error, id image) { + [_bridge.imageLoader loadImageWithTag:_src + size:self.bounds.size + scale:RCTScreenScale() + resizeMode:self.contentMode + progressBlock:progressHandler + completionBlock:^(NSError *error, id image) { if ([image isKindOfClass:[CAAnimation class]]) { [self.layer addAnimation:image forKey:@"contents"]; From 7996c322119be6562109b1e07dc80c1a94f15148 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 27 Jul 2015 08:51:28 -0700 Subject: [PATCH 29/37] Unregistered modules will now only error when called, not on bridge init Summary: Occasionally people create RCTBridgeModule subclasses or base classes that are not intended to be accessed from JS, and so they don't export them. This was previously flagged as an error by the system. I've now downgraded this error to a warning at startup, and deferred the redbox error until the module is directly accessed by native or JS code. --- .../UIExplorer.xcodeproj/project.pbxproj | 2 + React/Base/RCTBatchedBridge.m | 41 ++++++---- React/Base/RCTBridge.m | 17 +++- React/Base/RCTModuleData.h | 3 +- React/Base/RCTModuleData.m | 10 +-- React/Base/RCTModuleMap.h | 16 ++++ React/Base/RCTModuleMap.m | 79 +++++++++++++++++++ React/Base/RCTProfile.m | 6 +- React/Base/RCTRootView.m | 3 +- React/React.xcodeproj/project.pbxproj | 8 ++ 10 files changed, 153 insertions(+), 32 deletions(-) create mode 100644 React/Base/RCTModuleMap.h create mode 100644 React/Base/RCTModuleMap.m diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj index 9052af3e2c2691..b2c4a89103537a 100644 --- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj +++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj @@ -1034,6 +1034,7 @@ GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; @@ -1090,6 +1091,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 88640487a3773e..f04acd298d1799 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -17,6 +17,7 @@ #import "RCTJavaScriptLoader.h" #import "RCTLog.h" #import "RCTModuleData.h" +#import "RCTModuleMap.h" #import "RCTModuleMethod.h" #import "RCTPerformanceLogger.h" #import "RCTPerfStats.h" @@ -62,8 +63,8 @@ @implementation RCTBatchedBridge { BOOL _loading; __weak id _javaScriptExecutor; - NSMutableArray *_modules; - NSDictionary *_modulesByName; + NSMutableArray *_moduleDataByID; + RCTModuleMap *_modulesByName; CADisplayLink *_mainDisplayLink; CADisplayLink *_jsDisplayLink; NSMutableSet *_frameUpdateObservers; @@ -89,7 +90,7 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge */ _valid = YES; _loading = YES; - _modules = [[NSMutableArray alloc] init]; + _moduleDataByID = [[NSMutableArray alloc] init]; _frameUpdateObservers = [[NSMutableSet alloc] init]; _scheduledCalls = [[NSMutableArray alloc] init]; _scheduledCallbacks = [[RCTSparseArray alloc] init]; @@ -166,7 +167,7 @@ - (void)registerModules } // Instantiate modules - _modules = [[NSMutableArray alloc] init]; + _moduleDataByID = [[NSMutableArray alloc] init]; NSMutableDictionary *modulesByName = [preregisteredModules mutableCopy]; for (Class moduleClass in RCTGetModuleClasses()) { NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass); @@ -199,7 +200,7 @@ - (void)registerModules } // Store modules - _modulesByName = [modulesByName copy]; + _modulesByName = [[RCTModuleMap alloc] initWithDictionary:modulesByName]; /** * The executor is a bridge module, wait for it to be created and set it before @@ -217,9 +218,9 @@ - (void)registerModules } RCTModuleData *moduleData = [[RCTModuleData alloc] initWithExecutor:_javaScriptExecutor - uid:@(_modules.count) + uid:@(_moduleDataByID.count) instance:module]; - [_modules addObject:moduleData]; + [_moduleDataByID addObject:moduleData]; if ([module conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) { [_frameUpdateObservers addObject:moduleData]; @@ -236,7 +237,7 @@ - (void)initJS // Inject module data into JS context NSMutableDictionary *config = [[NSMutableDictionary alloc] init]; - for (RCTModuleData *moduleData in _modules) { + for (RCTModuleData *moduleData in _moduleDataByID) { config[moduleData.name] = moduleData.config; } NSString *configJSON = RCTJSONStringify(@{ @@ -275,7 +276,7 @@ - (void)initJS RCTJavaScriptLoader *loader = [[RCTJavaScriptLoader alloc] initWithBridge:self]; [loader loadBundleAtURL:bundleURL onComplete:^(NSError *error, NSString *script) { RCTPerformanceLoggerEnd(RCTPLScriptDownload); - RCTProfileEndEvent(@"JavaScript dowload", @"init,download", @[]); + RCTProfileEndEvent(@"JavaScript download", @"init,download", @[]); _loading = NO; if (!self.isValid) { @@ -363,7 +364,7 @@ - (void)invalidate // Invalidate modules dispatch_group_t group = dispatch_group_create(); - for (RCTModuleData *moduleData in _modules) { + for (RCTModuleData *moduleData in _moduleDataByID) { if (moduleData.instance == _javaScriptExecutor) { continue; } @@ -387,7 +388,7 @@ - (void)invalidate if (RCTProfileIsProfiling()) { RCTProfileUnhookModules(self); } - _modules = nil; + _moduleDataByID = nil; _modulesByName = nil; _frameUpdateObservers = nil; @@ -568,9 +569,15 @@ - (void)_handleBuffer:(id)buffer return; } - NSMapTable *buckets = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:_modules.count]; + NSMapTable *buckets = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory + valueOptions:NSPointerFunctionsStrongMemory + capacity:_moduleDataByID.count]; for (NSUInteger i = 0; i < numRequests; i++) { - RCTModuleData *moduleData = _modules[[moduleIDs[i] integerValue]]; + RCTModuleData *moduleData = _moduleDataByID[[moduleIDs[i] integerValue]]; + if (RCT_DEBUG) { + // verify that class has been registered + (void)_modulesByName[moduleData.name]; + } NSMutableOrderedSet *set = [buckets objectForKey:moduleData]; if (!set) { set = [[NSMutableOrderedSet alloc] init]; @@ -596,12 +603,13 @@ - (void)_handleBuffer:(id)buffer params:paramsArrays[index]]; } } - RCTProfileEndEvent(RCTCurrentThreadName(), @"objc_call,dispatch_async", @{ @"calls": @(calls.count) }); + + RCTProfileEndEvent(RCTCurrentThreadName(), @"objc_call,dispatch_async", @{ @"calls": @(calls.count) }); }]; } // TODO: batchDidComplete is only used by RCTUIManager - can we eliminate this special case? - for (RCTModuleData *moduleData in _modules) { + for (RCTModuleData *moduleData in _moduleDataByID) { if ([moduleData.instance respondsToSelector:@selector(batchDidComplete)]) { [moduleData dispatchBlock:^{ [moduleData.instance batchDidComplete]; @@ -624,10 +632,9 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i return NO; } - RCTProfileBeginEvent(); - RCTModuleData *moduleData = _modules[moduleID]; + RCTModuleData *moduleData = _moduleDataByID[moduleID]; if (RCT_DEBUG && !moduleData) { RCTLogError(@"No module found for id '%zd'", moduleID); return NO; diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index b81eae17accfbf..c670a528d7e007 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -80,6 +80,14 @@ void RCTRegisterModule(Class moduleClass) return name; } +/** + * Check if class has been registered + */ +BOOL RCTBridgeModuleClassIsRegistered(Class); +BOOL RCTBridgeModuleClassIsRegistered(Class cls) +{ + return [objc_getAssociatedObject(cls, &RCTBridgeModuleClassIsRegistered) ?: @YES boolValue]; +} @implementation RCTBridge @@ -108,8 +116,12 @@ + (void)initialize if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) { if (![RCTModuleClasses containsObject:cls]) { - RCTLogError(@"Class %@ was not exported. Did you forget to use " - "RCT_EXPORT_MODULE()?", NSStringFromClass(cls)); + RCTLogWarn(@"Class %@ was not exported. Did you forget to use " + "RCT_EXPORT_MODULE()?", cls); + + RCTRegisterModule(cls); + objc_setAssociatedObject(cls, &RCTBridgeModuleClassIsRegistered, + @NO, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } break; } @@ -254,5 +266,4 @@ - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(__unused NSString *)module method:(__unused NSString *)method arguments:(__unused NSArray *)args); - @end diff --git a/React/Base/RCTModuleData.h b/React/Base/RCTModuleData.h index a9ecbb06e34a46..7e92010ffced31 100644 --- a/React/Base/RCTModuleData.h +++ b/React/Base/RCTModuleData.h @@ -17,7 +17,7 @@ @property (nonatomic, strong, readonly) NSNumber *uid; @property (nonatomic, strong, readonly) id instance; -@property (nonatomic, strong, readonly) Class cls; +@property (nonatomic, strong, readonly) Class moduleClass; @property (nonatomic, copy, readonly) NSString *name; @property (nonatomic, copy, readonly) NSArray *methods; @property (nonatomic, copy, readonly) NSDictionary *config; @@ -28,7 +28,6 @@ uid:(NSNumber *)uid instance:(id)instance NS_DESIGNATED_INITIALIZER; - - (void)dispatchBlock:(dispatch_block_t)block; - (void)dispatchBlock:(dispatch_block_t)block dispatchGroup:(dispatch_group_t)group; diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m index 651b8b68488f82..4738eecd14ef9d 100644 --- a/React/Base/RCTModuleData.m +++ b/React/Base/RCTModuleData.m @@ -23,8 +23,8 @@ - (instancetype)initWithExecutor:(id)javaScriptExecutor _javaScriptExecutor = javaScriptExecutor; _uid = uid; _instance = instance; - _cls = [instance class]; - _name = RCTBridgeModuleNameForClass(_cls); + _moduleClass = [instance class]; + _name = RCTBridgeModuleNameForClass(_moduleClass); [self loadMethods]; [self generateConfig]; @@ -39,18 +39,18 @@ - (void)loadMethods { NSMutableArray *moduleMethods = [[NSMutableArray alloc] init]; unsigned int methodCount; - Method *methods = class_copyMethodList(object_getClass(_cls), &methodCount); + Method *methods = class_copyMethodList(object_getClass(_moduleClass), &methodCount); for (unsigned int i = 0; i < methodCount; i++) { Method method = methods[i]; SEL selector = method_getName(method); if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) { IMP imp = method_getImplementation(method); - NSArray *entries = ((NSArray *(*)(id, SEL))imp)(_cls, selector); + NSArray *entries = ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector); RCTModuleMethod *moduleMethod = [[RCTModuleMethod alloc] initWithObjCMethodName:entries[1] JSMethodName:entries[0] - moduleClass:_cls]; + moduleClass:_moduleClass]; [moduleMethods addObject:moduleMethod]; } diff --git a/React/Base/RCTModuleMap.h b/React/Base/RCTModuleMap.h new file mode 100644 index 00000000000000..48e7c73e66a719 --- /dev/null +++ b/React/Base/RCTModuleMap.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +@interface RCTModuleMap : NSDictionary + +- (instancetype)initWithDictionary:(NSDictionary *)modulesByName NS_DESIGNATED_INITIALIZER; + +@end diff --git a/React/Base/RCTModuleMap.m b/React/Base/RCTModuleMap.m new file mode 100644 index 00000000000000..cd10c5b889d3cc --- /dev/null +++ b/React/Base/RCTModuleMap.m @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTModuleMap.h" + +#import "RCTBridge.h" +#import "RCTBridgeModule.h" +#import "RCTDefines.h" +#import "RCTLog.h" + +@implementation RCTModuleMap +{ + NSDictionary *_modulesByName; +} + +RCT_NOT_IMPLEMENTED(-init) +RCT_NOT_IMPLEMENTED(-initWithCoder:aDecoder) +RCT_NOT_IMPLEMENTED(-initWithObjects:(const id [])objects + forKeys:(const id [])keys + count:(NSUInteger)cnt) + +- (instancetype)initWithDictionary:(NSDictionary *)modulesByName +{ + if ((self = [super init])) { + _modulesByName = [modulesByName copy]; + } + return self; +} + +- (NSUInteger)count +{ + return _modulesByName.count; +} + +//declared in RCTBridge.m +extern BOOL RCTBridgeModuleClassIsRegistered(Class cls); + +- (id)objectForKey:(NSString *)moduleName +{ + id module = _modulesByName[moduleName]; + if (RCT_DEBUG) { + if (module) { + Class moduleClass = [module class]; + if (!RCTBridgeModuleClassIsRegistered(moduleClass)) { + RCTLogError(@"Class %@ was not exported. Did you forget to use " + "RCT_EXPORT_MODULE()?", moduleClass); + } + } else { + Class moduleClass = NSClassFromString(moduleName); + module = _modulesByName[moduleName]; + if (module) { + RCTLogError(@"bridge.modules[name] expects a module name, not a class " + "name. Did you mean to pass '%@' instead?", + RCTBridgeModuleNameForClass(moduleClass)); + } + } + } + return module; +} + +- (NSEnumerator *)keyEnumerator +{ + return [_modulesByName keyEnumerator]; +} + +- (NSArray *)allValues +{ + // don't perform validation in this case because we only want to error when + // an invalid module is specifically requested + return _modulesByName.allValues; +} + +@end diff --git a/React/Base/RCTProfile.m b/React/Base/RCTProfile.m index dace71faa79d00..4583ef25cf00d5 100644 --- a/React/Base/RCTProfile.m +++ b/React/Base/RCTProfile.m @@ -148,7 +148,7 @@ void RCTProfileHookModules(RCTBridge *bridge) { for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { [moduleData dispatchBlock:^{ - Class moduleClass = moduleData.cls; + Class moduleClass = moduleData.moduleClass; Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0); if (!proxyClass) { @@ -192,8 +192,8 @@ void RCTProfileUnhookModules(RCTBridge *bridge) { for (RCTModuleData *moduleData in [bridge valueForKey:@"_modules"]) { Class proxyClass = object_getClass(moduleData.instance); - if (moduleData.cls != proxyClass) { - object_setClass(moduleData.instance, moduleData.cls); + if (moduleData.moduleClass != proxyClass) { + object_setClass(moduleData.instance, moduleData.moduleClass); objc_disposeClassPair(proxyClass); } }; diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index 6f9e7c71c681fd..b63dd4aaa287c8 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -169,8 +169,7 @@ - (void)bundleFinishedLoading:(RCTBridge *)bridge } [_contentView removeFromSuperview]; - _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds - bridge:bridge]; + _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds bridge:bridge]; _contentView.backgroundColor = self.backgroundColor; [self insertSubview:_contentView atIndex:0]; diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 70e4e41204eb25..74cc3e0bee95a5 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E21AA5CF210034F82E /* RCTTabBarItem.m */; }; 137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */; }; 137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E61AA5CF210034F82E /* RCTTabBarManager.m */; }; + 1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 1385D0331B665AAE000A309B /* RCTModuleMap.m */; }; 138D6A141B53CD290074A87E /* RCTCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 138D6A131B53CD290074A87E /* RCTCache.m */; }; 13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; }; 13AF20451AE707F9005F5298 /* RCTSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AF20441AE707F9005F5298 /* RCTSlider.m */; }; @@ -125,6 +126,8 @@ 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarItemManager.m; sourceTree = ""; }; 137327E51AA5CF210034F82E /* RCTTabBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarManager.h; sourceTree = ""; }; 137327E61AA5CF210034F82E /* RCTTabBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarManager.m; sourceTree = ""; }; + 1385D0331B665AAE000A309B /* RCTModuleMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMap.m; sourceTree = ""; }; + 1385D0351B6661DB000A309B /* RCTModuleMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTModuleMap.h; sourceTree = ""; }; 138D6A121B53CD290074A87E /* RCTCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCache.h; sourceTree = ""; }; 138D6A131B53CD290074A87E /* RCTCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCache.m; sourceTree = ""; }; 13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = ""; }; @@ -437,6 +440,8 @@ 83CBBA4E1A601E3B00E9B192 /* RCTLog.m */, 14C2CA721B3AC64300E6CBB2 /* RCTModuleData.h */, 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */, + 1385D0351B6661DB000A309B /* RCTModuleMap.h */, + 1385D0331B665AAE000A309B /* RCTModuleMap.m */, 14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */, 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */, 142014181B32094000CC17BA /* RCTPerformanceLogger.h */, @@ -612,6 +617,7 @@ 14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */, 134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */, 13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */, + 1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */, 1403F2B31B0AE60700C2A9A4 /* RCTPerfStats.m in Sources */, 83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */, 13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */, @@ -654,6 +660,7 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; @@ -696,6 +703,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; From 09bb761b25a7cdf9f6332441c35fe7edf85e7088 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 27 Jul 2015 09:11:15 -0700 Subject: [PATCH 30/37] Fixed RCTDownloadTaskWrapper crash on iOS7 Summary: This is a quick fix for the RCTDownloadTaskWrapper crashing on iOS 7. The issue was that the object returned by -[NSURLSession downloadTaskWithURL:] on iOS was not actually a subclass of NSURLSessionTask, so the category that adds associated blocks was not working. I've fixed that by making it a category on NSObject instead. --- Libraries/Image/RCTDownloadTaskWrapper.m | 44 +++++++++++------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/Libraries/Image/RCTDownloadTaskWrapper.m b/Libraries/Image/RCTDownloadTaskWrapper.m index e9a64369bed244..152a192599b462 100644 --- a/Libraries/Image/RCTDownloadTaskWrapper.m +++ b/Libraries/Image/RCTDownloadTaskWrapper.m @@ -12,36 +12,33 @@ #import -static void *const RCTDownloadTaskWrapperCompletionBlockKey = (void *)&RCTDownloadTaskWrapperCompletionBlockKey; -static void *const RCTDownloadTaskWrapperProgressBlockKey = (void *)&RCTDownloadTaskWrapperProgressBlockKey; +@interface NSObject (RCTDownloadTaskWrapper) -@interface NSURLSessionTask (RCTDownloadTaskWrapper) - -@property (nonatomic, copy, setter=rct_setCompletionBlock:) RCTDataCompletionBlock rct_completionBlock; -@property (nonatomic, copy, setter=rct_setProgressBlock:) RCTDataProgressBlock rct_progressBlock; +@property (nonatomic, copy) RCTDataCompletionBlock reactCompletionBlock; +@property (nonatomic, copy) RCTDataProgressBlock reactProgressBlock; @end -@implementation NSURLSessionTask (RCTDownloadTaskWrapper) +@implementation NSObject (RCTDownloadTaskWrapper) -- (RCTDataCompletionBlock)rct_completionBlock +- (RCTDataCompletionBlock)reactCompletionBlock { - return objc_getAssociatedObject(self, RCTDownloadTaskWrapperCompletionBlockKey); + return objc_getAssociatedObject(self, _cmd); } -- (void)rct_setCompletionBlock:(RCTDataCompletionBlock)completionBlock +- (void)setReactCompletionBlock:(RCTDataCompletionBlock)completionBlock { - objc_setAssociatedObject(self, RCTDownloadTaskWrapperCompletionBlockKey, completionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, @selector(reactCompletionBlock), completionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); } -- (RCTDataProgressBlock)rct_progressBlock +- (RCTDataProgressBlock)reactProgressBlock { - return objc_getAssociatedObject(self, RCTDownloadTaskWrapperProgressBlockKey); + return objc_getAssociatedObject(self, _cmd); } -- (void)rct_setProgressBlock:(RCTDataProgressBlock)progressBlock +- (void)setReactProgressBlock:(RCTDataProgressBlock)progressBlock { - objc_setAssociatedObject(self, RCTDownloadTaskWrapperProgressBlockKey, progressBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, @selector(reactProgressBlock), progressBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); } @end @@ -63,9 +60,8 @@ - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config - (NSURLSessionDownloadTask *)downloadData:(NSURL *)url progressBlock:(RCTDataProgressBlock)progressBlock completionBlock:(RCTDataCompletionBlock)completionBlock { NSURLSessionDownloadTask *task = [_URLSession downloadTaskWithURL:url]; - task.rct_completionBlock = completionBlock; - task.rct_progressBlock = progressBlock; - + task.reactCompletionBlock = completionBlock; + task.reactProgressBlock = progressBlock; return task; } @@ -73,28 +69,28 @@ - (NSURLSessionDownloadTask *)downloadData:(NSURL *)url progressBlock:(RCTDataPr - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { - if (downloadTask.rct_completionBlock) { + if (downloadTask.reactCompletionBlock) { NSData *data = [NSData dataWithContentsOfURL:location]; dispatch_async(dispatch_get_main_queue(), ^{ - downloadTask.rct_completionBlock(downloadTask.response, data, nil); + downloadTask.reactCompletionBlock(downloadTask.response, data, nil); }); } } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)didWriteData totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite; { - if (downloadTask.rct_progressBlock) { + if (downloadTask.reactProgressBlock) { dispatch_async(dispatch_get_main_queue(), ^{ - downloadTask.rct_progressBlock(totalBytesWritten, totalBytesExpectedToWrite); + downloadTask.reactProgressBlock(totalBytesWritten, totalBytesExpectedToWrite); }); } } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - if (error && task.rct_completionBlock) { + if (error && task.reactCompletionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ - task.rct_completionBlock(nil, nil, error); + task.reactCompletionBlock(nil, nil, error); }); } } From b7253dc6045ce9cb37b7f6611a58da37e9746dd2 Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Mon, 27 Jul 2015 09:25:19 -0700 Subject: [PATCH 31/37] [ReactNative] PixelRatio docs Summary: Update docs for `PixelRatio` in preparation for open sourcing React Native for Android. See http://stackoverflow.com/questions/11581649/about-android-image-and-asset-sizes --- Libraries/Utilities/PixelRatio.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Libraries/Utilities/PixelRatio.js b/Libraries/Utilities/PixelRatio.js index 7660fad3055409..940890ccec007a 100644 --- a/Libraries/Utilities/PixelRatio.js +++ b/Libraries/Utilities/PixelRatio.js @@ -20,9 +20,11 @@ var Dimensions = require('Dimensions'); * * ### Displaying a line that's as thin as the device permits * - * A width of 1 is actually pretty thick on an iPhone 4+, we can do one that's - * thinner using a width of `1 / PixelRatio.get()`. It's a technique that works - * on all the devices independent of their pixel density. + * A width of 1 is actually pretty thick on devices with high pixel density + * (such as iPhone 4+ and many Android devices), we can make one that's + * thinner using a width of `1 / PixelRatio.get()`. + * It's a technique that works on all the devices independent of their + * pixel density. * * ``` * style={{ borderWidth: 1 / PixelRatio.get() }} @@ -46,12 +48,18 @@ class PixelRatio { /** * Returns the device pixel density. Some examples: * + * - PixelRatio.get() === 1 + * - mdpi Android devices (160 dpi) + * - PixelRatio.get() === 1.5 + * - hdpi Android devices (240 dpi) * - PixelRatio.get() === 2 * - iPhone 4, 4S * - iPhone 5, 5c, 5s * - iPhone 6 + * - xhdpi Android devices (320 dpi) * - PixelRatio.get() === 3 * - iPhone 6 plus + * - xxhdpi Android devices (480 dpi) * - PixelRatio.get() === 3.5 * - Nexus 6 */ @@ -68,6 +76,7 @@ class PixelRatio { * * Currently this is only implemented on Android and reflects the user preference set in * Settings > Display > Font size, on iOS it will always return the default pixel ratio. + * @platform android */ static getFontScale(): number { return Dimensions.get('window').fontScale || PixelRatio.get(); From 33e62f71f41b00a06bf6e24322c34b4465c6fb8d Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Mon, 27 Jul 2015 09:22:51 -0700 Subject: [PATCH 32/37] [ReactNative] CameraRoll docs Summary: In preparation for open sourcing React Native for Android, document which parts of the `CameraRoll` API are platform-specific. Renders like this: http://imgur.com/rbpXHKf We should improve docs generation for `@param`s. --- Libraries/CameraRoll/CameraRoll.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js index 1f5c6c22a1582f..a710e7ec12c6ba 100644 --- a/Libraries/CameraRoll/CameraRoll.js +++ b/Libraries/CameraRoll/CameraRoll.js @@ -109,17 +109,28 @@ var getPhotosReturnChecker = createStrictShapeTypeChecker({ }).isRequired, }); +/** + * `CameraRoll` provides access to the local camera roll / gallery. + */ class CameraRoll { static GroupTypesOptions: Array; static AssetTypeOptions: Array; /** - * Saves the image with tag `tag` to the camera roll. + * Saves the image to the camera roll / gallery. + * + * @param {string} tag On Android, this is a local URI, such + * as `"file:///sdcard/img.png"`. + * + * On iOS, the tag can be one of the following: + * + * - local URI + * - assets-library tag + * - a tag not maching any of the above, which means the image data will + * be stored in memory (and consume memory as long as the process is alive) * - * @param {string} tag - Can be any of the three kinds of tags we accept: - * 1. URL - * 2. assets-library tag - * 3. tag returned from storing an image in memory + * @param successCallback Invoked with the value of `tag` on success. + * @param errorCallback Invoked with error message on error. */ static saveImageWithTag(tag, successCallback, errorCallback) { invariant( @@ -140,10 +151,10 @@ class CameraRoll { * Invokes `callback` with photo identifier objects from the local camera * roll of the device matching shape defined by `getPhotosReturnChecker`. * - * @param {object} params - See `getPhotosParamChecker`. - * @param {function} callback - Invoked with arg of shape defined by - * `getPhotosReturnChecker` on success. - * @param {function} errorCallback - Invoked with error message on error. + * @param {object} params See `getPhotosParamChecker`. + * @param {function} callback Invoked with arg of shape defined by + * `getPhotosReturnChecker` on success. + * @param {function} errorCallback Invoked with error message on error. */ static getPhotos(params, callback, errorCallback) { var metaCallback = callback; From 18e6094cabb82a5ae2110158f015ee2ea9ccc440 Mon Sep 17 00:00:00 2001 From: Christopher Chedeau Date: Mon, 27 Jul 2015 10:49:43 -0700 Subject: [PATCH 33/37] [ReactNative] Add overflow to the whitelisted Image props Summary: For some reason we're now spamming the logs everytime we render an Image because overflow is not defined in the whitelist. overflow: 'hidden' is needed for network images with cover mode. The way we currently define those is not optimal where we try to factor as many things as possible into distinct propTypes. However for Text we're not even using this but we are getting all the ones from View (which many do not apply) and remove some that aren't needed. It may be useful to cleanup this in the future but in the short term, it's better to remove this warning that doesn't have much value anyway. --- Libraries/Image/ImageStylePropTypes.js | 1 + Libraries/StyleSheet/StyleSheetValidation.js | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js index c70bee73a1908e..c4ccfb57860a67 100644 --- a/Libraries/Image/ImageStylePropTypes.js +++ b/Libraries/Image/ImageStylePropTypes.js @@ -24,6 +24,7 @@ var ImageStylePropTypes = { borderColor: ReactPropTypes.string, borderWidth: ReactPropTypes.number, borderRadius: ReactPropTypes.number, + overflow: ReactPropTypes.oneOf(['visible', 'hidden']), // iOS-Specific style to "tint" an image. // It changes the color of all the non-transparent pixels to the tintColor diff --git a/Libraries/StyleSheet/StyleSheetValidation.js b/Libraries/StyleSheet/StyleSheetValidation.js index be59b2ec50516f..f61decb3cc2ccb 100644 --- a/Libraries/StyleSheet/StyleSheetValidation.js +++ b/Libraries/StyleSheet/StyleSheetValidation.js @@ -51,11 +51,6 @@ class StyleSheetValidation { static addValidStylePropTypes(stylePropTypes) { for (var key in stylePropTypes) { - invariant( - allStylePropTypes[key] === undefined || - allStylePropTypes[key] === stylePropTypes[key], - 'Attemped to redefine existing style prop type "' + key + '".' - ); allStylePropTypes[key] = stylePropTypes[key]; } } From 58a403d3c8f8b9ce1fae765d677fd535e6a9a11c Mon Sep 17 00:00:00 2001 From: Alex Kotliarskyi Date: Mon, 27 Jul 2015 12:13:34 -0700 Subject: [PATCH 34/37] [ReactNative] Pin babel version Summary: Currently minor version babel updates add and remove transforms, but internal version is checked in and pinned to 5.6.4. Until we figure out how to update internal deps systematically, we need to make sure OSS edition of RN matches internal, otherwise we get test failures due to package version mismatches. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5f90776b6f5b4..765c7a4a0644d0 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "dependencies": { "absolute-path": "0.0.0", "babel": "5.4.3", - "babel-core": "^5.6.4", + "babel-core": "5.6.4", "chalk": "^1.0.0", "connect": "2.8.3", "debug": "~2.1.0", From 842ce5109905908eb5cc9723a7cbd91218f33693 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Mon, 27 Jul 2015 11:11:59 -0700 Subject: [PATCH 35/37] [Treehouse RN] Make smoothScrollTo works by not calling it twice --- Libraries/CustomComponents/ListView/ListView.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js index 5ca25fe01a6aad..4554eb681257a2 100644 --- a/Libraries/CustomComponents/ListView/ListView.js +++ b/Libraries/CustomComponents/ListView/ListView.js @@ -390,6 +390,13 @@ var ListView = React.createClass({ Object.assign(props, { onScroll: this._onScroll, stickyHeaderIndices: sectionHeaderIndices, + + // Do not pass these events downstream to ScrollView since they will be + // registered in ListView's own ScrollResponder.Mixin + onKeyboardWillShow: undefined, + onKeyboardWillHide: undefined, + onKeyboardDidShow: undefined, + onKeyboardDidHide: undefined, }); // TODO(ide): Use function refs so we can compose with the scroll From 3b83853713c22ba56ab644815b43b83ac8882f39 Mon Sep 17 00:00:00 2001 From: Bill Fisher Date: Mon, 27 Jul 2015 11:46:56 -0700 Subject: [PATCH 36/37] [ReactNative] fix onMoveShouldSetPanResponderCapture Summary: Typo in implementation prevented onMoveShouldSetPanResponderCapture from working. --- Libraries/vendor/react/browser/eventPlugins/PanResponder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js index b6f0a765add160..ed93f88f671f48 100644 --- a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js +++ b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js @@ -294,7 +294,7 @@ var PanResponder = { return false; } PanResponder._updateGestureStateOnMove(gestureState, touchHistory); - return config.onMoveShouldSetResponderCapture ? + return config.onMoveShouldSetPanResponderCapture ? config.onMoveShouldSetPanResponderCapture(e, gestureState) : false; }, From 3cff9be3d10b0124b096c16707be3589f7558ffc Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Mon, 27 Jul 2015 14:23:44 -0700 Subject: [PATCH 37/37] [ReactNative] Update project template .flowconfig --- Examples/SampleApp/_flowconfig | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Examples/SampleApp/_flowconfig b/Examples/SampleApp/_flowconfig index b2a76e02978922..8989253d43ac5e 100644 --- a/Examples/SampleApp/_flowconfig +++ b/Examples/SampleApp/_flowconfig @@ -9,11 +9,14 @@ # Ignore react-tools where there are overlaps, but don't ignore anything that # react-native relies on -.*/node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js -.*/node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js -.*/node_modules/react-tools/src/browser/ui/React.js -.*/node_modules/react-tools/src/core/ReactInstanceHandles.js -.*/node_modules/react-tools/src/event/EventPropagators.js +.*/node_modules/react-tools/src/React.js +.*/node_modules/react-tools/src/renderers/shared/reconciler/ReactInstanceHandles.js +.*/node_modules/react-tools/src/renderers/shared/event/EventPropagators.js +.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js +.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js +.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderTouchHistoryStore.js +.*/node_modules/react-tools/src/shared/vendor/core/ExecutionEnvironment.js + # Ignore commoner tests .*/node_modules/commoner/test/.*