From f1bd1cbc942662e93035d16aebd8b5c311298cee Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Fri, 24 Jul 2015 18:31:55 -0700 Subject: [PATCH] [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 53390cabe..7e0ea6936 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 5d47b4df6..4c8e1b6e7 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 cbdf43ae5..c8ff595d5 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 ec3b6c614..0fcc92e88 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 549b3dee9..1674fb8a5 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 716b8f806..b291c7abe 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 73cb57e9f..02715c080 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 5d6d87cd8..18937f9cf 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;