[ReactNative] verifyPropTypes against native exports
This commit is contained in:
Родитель
764854c04a
Коммит
915151c5d7
|
@ -226,10 +226,8 @@ exports.examples = [
|
|||
Contain
|
||||
</Text>
|
||||
<Image
|
||||
style={[
|
||||
styles.resizeMode,
|
||||
{resizeMode: Image.resizeMode.contain}
|
||||
]}
|
||||
style={styles.resizeMode}
|
||||
resizeMode={Image.resizeMode.contain}
|
||||
source={fullImage}
|
||||
/>
|
||||
</View>
|
||||
|
@ -238,10 +236,8 @@ exports.examples = [
|
|||
Cover
|
||||
</Text>
|
||||
<Image
|
||||
style={[
|
||||
styles.resizeMode,
|
||||
{resizeMode: Image.resizeMode.cover}
|
||||
]}
|
||||
style={styles.resizeMode}
|
||||
resizeMode={Image.resizeMode.cover}
|
||||
source={fullImage}
|
||||
/>
|
||||
</View>
|
||||
|
@ -250,10 +246,8 @@ exports.examples = [
|
|||
Stretch
|
||||
</Text>
|
||||
<Image
|
||||
style={[
|
||||
styles.resizeMode,
|
||||
{resizeMode: Image.resizeMode.stretch}
|
||||
]}
|
||||
style={styles.resizeMode}
|
||||
resizeMode={Image.resizeMode.stretch}
|
||||
source={fullImage}
|
||||
/>
|
||||
</View>
|
||||
|
|
|
@ -17,7 +17,6 @@ var PointPropType = require('PointPropType');
|
|||
var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
|
||||
var RCTScrollViewConsts = RCTScrollView.Constants;
|
||||
var React = require('React');
|
||||
var ReactIOSTagHandles = require('ReactIOSTagHandles');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var RCTUIManager = require('NativeModules').UIManager;
|
||||
var ScrollResponder = require('ScrollResponder');
|
||||
|
@ -32,6 +31,7 @@ var flattenStyle = require('flattenStyle');
|
|||
var insetsDiffer = require('insetsDiffer');
|
||||
var invariant = require('invariant');
|
||||
var pointsDiffer = require('pointsDiffer');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
var PropTypes = React.PropTypes;
|
||||
|
||||
|
@ -73,6 +73,12 @@ var ScrollView = React.createClass({
|
|||
* the `alwaysBounce*` props are true. The default value is true.
|
||||
*/
|
||||
bounces: PropTypes.bool,
|
||||
/**
|
||||
* When true, gestures can drive zoom past min/max and the zoom will animate
|
||||
* to the min/max value at gesture end, otherwise the zoom will not exceed
|
||||
* the limits.
|
||||
*/
|
||||
bouncesZoom: PropTypes.bool,
|
||||
/**
|
||||
* When true, the scroll view bounces horizontally when it reaches the end
|
||||
* even if the content is smaller than the scroll view itself. The default
|
||||
|
@ -120,6 +126,16 @@ var ScrollView = React.createClass({
|
|||
* instead of vertically in a column. The default value is false.
|
||||
*/
|
||||
horizontal: PropTypes.bool,
|
||||
/**
|
||||
* When true, the ScrollView will try to lock to only vertical or horizontal
|
||||
* scrolling while dragging. The default value is false.
|
||||
*/
|
||||
directionalLockEnabled: PropTypes.bool,
|
||||
/**
|
||||
* When false, once tracking starts, won't try to drag if the touch moves.
|
||||
* The default value is true.
|
||||
*/
|
||||
canCancelContentTouches: PropTypes.bool,
|
||||
/**
|
||||
* Determines whether the keyboard gets dismissed in response to a drag.
|
||||
* - 'none' (the default), drags do not dismiss the keyboard.
|
||||
|
@ -359,6 +375,7 @@ if (Platform.OS === 'android') {
|
|||
validAttributes: validAttributes,
|
||||
uiViewClassName: 'RCTScrollView',
|
||||
});
|
||||
var RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
|
||||
}
|
||||
|
||||
module.exports = ScrollView;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var Platform = require('Platform');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
|
@ -21,6 +22,7 @@ var View = require('View');
|
|||
var createReactIOSNativeComponentClass =
|
||||
require('createReactIOSNativeComponentClass');
|
||||
var merge = require('merge');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
type Event = Object;
|
||||
|
||||
|
@ -96,16 +98,20 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
});
|
||||
|
||||
var validAttributes = {
|
||||
...ReactIOSViewAttributes.UIView,
|
||||
value: true,
|
||||
minimumValue: true,
|
||||
maximumValue: true,
|
||||
};
|
||||
if (Platform.OS === 'ios') {
|
||||
var RCTSlider = requireNativeComponent('RCTSlider', SliderIOS);
|
||||
} else {
|
||||
var validAttributes = {
|
||||
...ReactIOSViewAttributes.UIView,
|
||||
value: true,
|
||||
minimumValue: true,
|
||||
maximumValue: true,
|
||||
};
|
||||
|
||||
var RCTSlider = createReactIOSNativeComponentClass({
|
||||
validAttributes: validAttributes,
|
||||
uiViewClassName: 'RCTSlider',
|
||||
});
|
||||
var RCTSlider = createReactIOSNativeComponentClass({
|
||||
validAttributes: validAttributes,
|
||||
uiViewClassName: 'RCTSlider',
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = SliderIOS;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -10,22 +10,23 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var ImageStylePropTypes = require('ImageStylePropTypes');
|
||||
var TextStylePropTypes = require('TextStylePropTypes');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var deepDiffer = require('deepDiffer');
|
||||
var keyMirror = require('keyMirror');
|
||||
var matricesDiffer = require('matricesDiffer');
|
||||
var merge = require('merge');
|
||||
var sizesDiffer = require('sizesDiffer');
|
||||
|
||||
var ReactIOSStyleAttributes = merge(
|
||||
keyMirror(ViewStylePropTypes),
|
||||
keyMirror(TextStylePropTypes)
|
||||
);
|
||||
var ReactIOSStyleAttributes = {
|
||||
...keyMirror(ViewStylePropTypes),
|
||||
...keyMirror(TextStylePropTypes),
|
||||
...keyMirror(ImageStylePropTypes),
|
||||
};
|
||||
|
||||
ReactIOSStyleAttributes.transformMatrix = { diff: matricesDiffer };
|
||||
ReactIOSStyleAttributes.shadowOffset = { diff: deepDiffer };
|
||||
ReactIOSStyleAttributes.shadowOffset = { diff: sizesDiffer };
|
||||
|
||||
module.exports = ReactIOSStyleAttributes;
|
||||
|
|
|
@ -20,18 +20,27 @@ var insetsDiffer = require('insetsDiffer');
|
|||
var pointsDiffer = require('pointsDiffer');
|
||||
var matricesDiffer = require('matricesDiffer');
|
||||
var sizesDiffer = require('sizesDiffer');
|
||||
var verifyPropTypes = require('verifyPropTypes');
|
||||
|
||||
/**
|
||||
* Used to create React components that directly wrap native component
|
||||
* implementations. Config information is extracted from data exported from the
|
||||
* RCTUIManager module. It is still strongly preferred that you wrap the native
|
||||
* component in a hand-written component with full propTypes definitions and
|
||||
* other documentation.
|
||||
* 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
|
||||
* 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
|
||||
* with `nativePropsToIgnore`;
|
||||
*
|
||||
* Common types are lined up with the appropriate prop differs with
|
||||
* `TypeToDifferMap`. Non-scalar types not in the map default to `deepDiffer`.
|
||||
*/
|
||||
function requireNativeComponent(viewName: string): Function {
|
||||
function requireNativeComponent(
|
||||
viewName: string,
|
||||
wrapperComponent: ?Function
|
||||
): Function {
|
||||
var viewConfig = RCTUIManager.viewConfigs && RCTUIManager.viewConfigs[viewName];
|
||||
if (!viewConfig) {
|
||||
return UnimplementedView;
|
||||
|
@ -46,6 +55,9 @@ function requireNativeComponent(viewName: string): Function {
|
|||
var differ = TypeToDifferMap[nativeProps[key].type] || deepDiffer;
|
||||
viewConfig.validAttributes[key] = {diff: differ};
|
||||
}
|
||||
if (__DEV__) {
|
||||
wrapperComponent && verifyPropTypes(wrapperComponent, viewConfig);
|
||||
}
|
||||
return createReactIOSNativeComponentClass(viewConfig);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* 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 verifyPropTypes
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactIOSStyleAttributes = require('ReactIOSStyleAttributes');
|
||||
var View = require('View');
|
||||
|
||||
function verifyPropTypes(
|
||||
component: Function,
|
||||
viewConfig: Object,
|
||||
nativePropsToIgnore?: Object
|
||||
) {
|
||||
if (!viewConfig) {
|
||||
return; // This happens for UnimplementedView.
|
||||
}
|
||||
var nativeProps = viewConfig.nativeProps;
|
||||
for (var prop in viewConfig.nativeProps) {
|
||||
if (!component.propTypes[prop] &&
|
||||
!View.propTypes[prop] &&
|
||||
!ReactIOSStyleAttributes[prop] &&
|
||||
(!nativePropsToIgnore || !nativePropsToIgnore[prop])) {
|
||||
throw new Error(
|
||||
'`' + component.displayName + '` has no propType for native prop `' +
|
||||
viewConfig.uiViewClassName + '.' + prop + '` of native type `' +
|
||||
nativeProps[prop].type + '`'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = verifyPropTypes;
|
|
@ -61,7 +61,6 @@ RCT_EXPORT_MODULE()
|
|||
#pragma mark - View properties
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(accessibilityLabel, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(hidden, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
|
||||
RCT_REMAP_VIEW_PROPERTY(accessible, isAccessibilityElement, BOOL)
|
||||
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString)
|
||||
|
|
Загрузка…
Ссылка в новой задаче