[ReactNative] verifyPropTypes against native exports

This commit is contained in:
Spencer Ahrens
2015-04-16 18:17:19 -07:00
parent 764854c04a
commit 915151c5d7
10 changed files with 177 additions and 64 deletions

View File

@@ -14,6 +14,7 @@
var EdgeInsetsPropType = require('EdgeInsetsPropType');
var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModules = require('NativeModules');
var Platform = require('Platform');
var PropTypes = require('ReactPropTypes');
var ImageResizeMode = require('ImageResizeMode');
var ImageStylePropTypes = require('ImageStylePropTypes');
@@ -27,7 +28,9 @@ var flattenStyle = require('flattenStyle');
var insetsDiffer = require('insetsDiffer');
var invariant = require('invariant');
var merge = require('merge');
var requireNativeComponent = require('requireNativeComponent');
var warning = require('warning');
var verifyPropTypes = require('verifyPropTypes');
/**
* A react component for displaying different types of images,
@@ -64,6 +67,13 @@ var Image = React.createClass({
source: PropTypes.shape({
uri: PropTypes.string,
}),
/**
* A static image to display while downloading the final image off the
* network.
*/
defaultSource: PropTypes.shape({
uri: PropTypes.string,
}),
/**
* Whether this element should be revealed as an accessible element.
*/
@@ -80,6 +90,11 @@ var Image = React.createClass({
* [Apple documentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/index.html#//apple_ref/occ/instm/UIImage/resizableImageWithCapInsets)
*/
capInsets: EdgeInsetsPropType,
/**
* Determines how to resize the image when the frame doesn't match the raw
* image dimensions.
*/
resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
style: StyleSheetPropType(ImageStylePropTypes),
/**
* A unique identifier for this element to be used in UI Automation
@@ -104,6 +119,12 @@ var Image = React.createClass({
},
render: function() {
for (var prop in nativeOnlyProps) {
if (this.props[prop] !== undefined) {
console.warn('Prop `' + prop + ' = ' + this.props[prop] + '` should ' +
'not be set directly on Image.');
}
}
var style = flattenStyle([styles.base, this.props.style]);
invariant(style, "style must be initialized");
var source = this.props.source;
@@ -119,28 +140,36 @@ var Image = React.createClass({
if (this.props.style && this.props.style.tintColor) {
warning(RawImage === RCTStaticImage, 'tintColor style only supported on static images.');
}
var resizeMode = this.props.resizeMode || style.resizeMode;
var contentModes = NativeModules.UIManager.UIView.ContentMode;
var resizeMode;
if (style.resizeMode === ImageResizeMode.stretch) {
resizeMode = contentModes.ScaleToFill;
} else if (style.resizeMode === ImageResizeMode.contain) {
resizeMode = contentModes.ScaleAspectFit;
var contentMode;
if (resizeMode === ImageResizeMode.stretch) {
contentMode = contentModes.ScaleToFill;
} else if (resizeMode === ImageResizeMode.contain) {
contentMode = contentModes.ScaleAspectFit;
} else { // ImageResizeMode.cover or undefined
resizeMode = contentModes.ScaleAspectFill;
contentMode = contentModes.ScaleAspectFill;
}
var nativeProps = merge(this.props, {
style,
resizeMode,
contentMode,
tintColor: style.tintColor,
});
if (Platform.OS === 'android') {
// TODO: update android native code to not need this
nativeProps.resizeMode = contentMode;
delete nativeProps.contentMode;
}
if (isStored) {
nativeProps.imageTag = source.uri;
} else {
nativeProps.src = source.uri;
}
if (this.props.defaultSource) {
nativeProps.defaultImageSrc = this.props.defaultSource.uri;
}
return <RawImage {...nativeProps} />;
}
});
@@ -151,24 +180,39 @@ var styles = StyleSheet.create({
},
});
var CommonImageViewAttributes = merge(ReactIOSViewAttributes.UIView, {
accessible: true,
accessibilityLabel: true,
capInsets: {diff: insetsDiffer}, // UIEdgeInsets=UIEdgeInsetsZero
imageTag: true,
resizeMode: true,
if (Platform.OS === 'android') {
var CommonImageViewAttributes = merge(ReactIOSViewAttributes.UIView, {
accessible: true,
accessibilityLabel: true,
capInsets: {diff: insetsDiffer}, // UIEdgeInsets=UIEdgeInsetsZero
imageTag: true,
resizeMode: true,
src: true,
testID: PropTypes.string,
});
var RCTStaticImage = createReactIOSNativeComponentClass({
validAttributes: merge(CommonImageViewAttributes, { tintColor: true }),
uiViewClassName: 'RCTStaticImage',
});
var RCTNetworkImage = createReactIOSNativeComponentClass({
validAttributes: merge(CommonImageViewAttributes, { defaultImageSrc: true }),
uiViewClassName: 'RCTNetworkImageView',
});
} else {
var RCTStaticImage = requireNativeComponent('RCTStaticImage', null);
var RCTNetworkImage = requireNativeComponent('RCTNetworkImageView', null);
}
var nativeOnlyProps = {
src: true,
testID: PropTypes.string,
});
var RCTStaticImage = createReactIOSNativeComponentClass({
validAttributes: merge(CommonImageViewAttributes, { tintColor: true }),
uiViewClassName: 'RCTStaticImage',
});
var RCTNetworkImage = createReactIOSNativeComponentClass({
validAttributes: merge(CommonImageViewAttributes, { defaultImageSrc: true }),
uiViewClassName: 'RCTNetworkImageView',
});
defaultImageSrc: true,
imageTag: true,
contentMode: true,
};
if (__DEV__) {
verifyPropTypes(Image, RCTStaticImage.viewConfig, nativeOnlyProps);
verifyPropTypes(Image, RCTNetworkImage.viewConfig, nativeOnlyProps);
}
module.exports = Image;

View File

@@ -29,6 +29,6 @@ RCT_EXPORT_MODULE()
RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage, UIImage)
RCT_REMAP_VIEW_PROPERTY(src, imageURL, NSURL)
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
RCT_EXPORT_VIEW_PROPERTY(contentMode, UIViewContentMode)
@end

View File

@@ -26,7 +26,7 @@ RCT_EXPORT_MODULE()
}
RCT_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
RCT_EXPORT_VIEW_PROPERTY(contentMode, UIViewContentMode)
RCT_CUSTOM_VIEW_PROPERTY(src, NSURL, RCTStaticImage)
{
if (json) {