Typing View style as ViewStyleProp

Summary: Locking down view style so that invalid styles can't be passed into View.

Reviewed By: yungsters

Differential Revision: D9309097

fbshipit-source-id: 69e7e3c5626609cfd47c167027a55470c42228c8
This commit is contained in:
Eli White 2018-08-14 16:31:04 -07:00 committed by Facebook Github Bot
parent 22cf5dc566
commit 76948ad1bd
15 changed files with 70 additions and 57 deletions

View File

@ -16,6 +16,8 @@ const ReactNative = require('react-native');
const {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative; const {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative;
const {TestModule} = ReactNative.NativeModules; const {TestModule} = ReactNative.NativeModules;
import type {ViewStyleProp} from 'StyleSheet';
const deepDiffer = require('deepDiffer'); const deepDiffer = require('deepDiffer');
function debug(...args) { function debug(...args) {
@ -23,14 +25,6 @@ function debug(...args) {
} }
import type {Layout, LayoutEvent} from 'CoreEventTypes'; import type {Layout, LayoutEvent} from 'CoreEventTypes';
type Style = {
margin?: number,
padding?: number,
borderColor?: string,
borderWidth?: number,
backgroundColor?: string,
width?: number,
};
type State = { type State = {
didAnimation: boolean, didAnimation: boolean,
@ -38,8 +32,8 @@ type State = {
imageLayout?: Layout, imageLayout?: Layout,
textLayout?: Layout, textLayout?: Layout,
viewLayout?: Layout, viewLayout?: Layout,
viewStyle?: Style, viewStyle?: ViewStyleProp,
containerStyle?: Style, containerStyle?: ViewStyleProp,
}; };
const LayoutEventsTest = createReactClass({ const LayoutEventsTest = createReactClass({

View File

@ -483,7 +483,6 @@ export type Props = $ReadOnly<{|
* See [RefreshControl](docs/refreshcontrol.html). * See [RefreshControl](docs/refreshcontrol.html).
*/ */
refreshControl?: ?React.Element<any>, refreshControl?: ?React.Element<any>,
style?: ?ViewStyleProp,
children?: React.Node, children?: React.Node,
|}>; |}>;

View File

@ -33,7 +33,7 @@ const requireNativeComponent = require('requireNativeComponent');
const warning = require('fbjs/lib/warning'); const warning = require('fbjs/lib/warning');
import type {ColorValue} from 'StyleSheetTypes'; import type {ColorValue} from 'StyleSheetTypes';
import type {TextStyleProp} from 'StyleSheet'; import type {TextStyleProp, ViewStyleProp} from 'StyleSheet';
import type {ViewProps} from 'ViewPropTypes'; import type {ViewProps} from 'ViewPropTypes';
let AndroidTextInput; let AndroidTextInput;
@ -169,7 +169,7 @@ type AndroidProps = $ReadOnly<{|
|}>; |}>;
type Props = $ReadOnly<{| type Props = $ReadOnly<{|
...ViewProps, ...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
...IOSProps, ...IOSProps,
...AndroidProps, ...AndroidProps,
autoCapitalize?: ?AutoCapitalize, autoCapitalize?: ?AutoCapitalize,

View File

@ -33,6 +33,7 @@ import type {
import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
import type {TVViewProps} from 'TVViewPropTypes'; import type {TVViewProps} from 'TVViewPropTypes';
import type {Layout, LayoutEvent} from 'CoreEventTypes'; import type {Layout, LayoutEvent} from 'CoreEventTypes';
import type {ViewStyleProp} from 'StyleSheet';
const stylePropType = StyleSheetPropType(ViewStylePropTypes); const stylePropType = StyleSheetPropType(ViewStylePropTypes);
@ -103,7 +104,7 @@ export type ViewProps = $ReadOnly<{|
nativeID?: string, nativeID?: string,
hitSlop?: ?EdgeInsetsProp, hitSlop?: ?EdgeInsetsProp,
pointerEvents?: null | 'box-none' | 'none' | 'box-only' | 'auto', pointerEvents?: null | 'box-none' | 'none' | 'box-only' | 'auto',
style?: stylePropType, style?: ?ViewStyleProp,
removeClippedSubviews?: boolean, removeClippedSubviews?: boolean,
renderToHardwareTextureAndroid?: boolean, renderToHardwareTextureAndroid?: boolean,
shouldRasterizeIOS?: boolean, shouldRasterizeIOS?: boolean,

View File

@ -18,6 +18,7 @@ const View = require('View');
const ViewPropTypes = require('ViewPropTypes'); const ViewPropTypes = require('ViewPropTypes');
import type {Context} from 'Incremental'; import type {Context} from 'Incremental';
import type {ViewStyleProp} from 'StyleSheet';
/** /**
* WARNING: EXPERIMENTAL. Breaking changes will probably happen a lot and will * WARNING: EXPERIMENTAL. Breaking changes will probably happen a lot and will
@ -36,7 +37,7 @@ type Props = {
disabled?: boolean, disabled?: boolean,
onDone?: () => void, onDone?: () => void,
onLayout?: (event: Object) => void, onLayout?: (event: Object) => void,
style?: mixed, style?: ViewStyleProp,
children?: any, children?: any,
}; };
class IncrementalPresenter extends React.Component<Props> { class IncrementalPresenter extends React.Component<Props> {

View File

@ -23,6 +23,7 @@ const ImageViewManager = NativeModules.ImageViewManager;
const RCTImageView = requireNativeComponent('RCTImageView'); const RCTImageView = requireNativeComponent('RCTImageView');
import type {ImageStyleProp} from 'StyleSheet';
import type {ImageProps as ImagePropsType} from 'ImageProps'; import type {ImageProps as ImagePropsType} from 'ImageProps';
function getSize( function getSize(
@ -71,12 +72,14 @@ let Image = (
}; };
let sources; let sources;
let style; let style: ImageStyleProp;
if (Array.isArray(source)) { if (Array.isArray(source)) {
// $FlowFixMe flattenStyle is not strong enough
style = flattenStyle([styles.base, props.style]) || {}; style = flattenStyle([styles.base, props.style]) || {};
sources = source; sources = source;
} else { } else {
const {width, height, uri} = source; const {width, height, uri} = source;
// $FlowFixMe flattenStyle is not strong enough
style = flattenStyle([{width, height}, styles.base, props.style]) || {}; style = flattenStyle([{width, height}, styles.base, props.style]) || {};
sources = [source]; sources = [source];

View File

@ -16,25 +16,25 @@ type ImageCropData = {
* The top-left corner of the cropped image, specified in the original * The top-left corner of the cropped image, specified in the original
* image's coordinate space. * image's coordinate space.
*/ */
offset: { offset: {|
x: number, x: number,
y: number, y: number,
}, |},
/** /**
* The size (dimensions) of the cropped image, specified in the original * The size (dimensions) of the cropped image, specified in the original
* image's coordinate space. * image's coordinate space.
*/ */
size: { size: {|
width: number, width: number,
height: number, height: number,
}, |},
/** /**
* (Optional) size to scale the cropped image to. * (Optional) size to scale the cropped image to.
*/ */
displaySize?: ?{ displaySize?: ?{|
width: number, width: number,
height: number, height: number,
}, |},
/** /**
* (Optional) the resizing mode to use when scaling the image. If the * (Optional) the resizing mode to use when scaling the image. If the
* `displaySize` param is not specified, this has no effect. * `displaySize` param is not specified, this has no effect.

View File

@ -21,7 +21,7 @@ import type {ViewProps} from 'ViewPropTypes';
import type {ImageSource} from 'ImageSource'; import type {ImageSource} from 'ImageSource';
import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
import type {SyntheticEvent} from 'CoreEventTypes'; import type {SyntheticEvent} from 'CoreEventTypes';
import type {ImageStyleProp} from 'StyleSheet'; import type {ViewStyleProp, ImageStyleProp} from 'StyleSheet';
type OnLoadEvent = SyntheticEvent< type OnLoadEvent = SyntheticEvent<
$ReadOnly<{| $ReadOnly<{|
@ -51,7 +51,7 @@ type AndroidImageProps = $ReadOnly<{|
|}>; |}>;
export type ImageProps = {| export type ImageProps = {|
...ViewProps, ...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
...IOSImageProps, ...IOSImageProps,
...AndroidImageProps, ...AndroidImageProps,
blurRadius?: number, blurRadius?: number,

View File

@ -18,7 +18,7 @@ const StyleSheet = require('StyleSheet');
const invariant = require('fbjs/lib/invariant'); const invariant = require('fbjs/lib/invariant');
import type {DangerouslyImpreciseStyleProp, ViewStyleProp} from 'StyleSheet'; import type {ViewStyleProp} from 'StyleSheet';
import type { import type {
ViewabilityConfig, ViewabilityConfig,
ViewToken, ViewToken,
@ -104,7 +104,7 @@ type OptionalProps<ItemT> = {
/** /**
* Optional custom style for multi-item rows generated when numColumns > 1. * Optional custom style for multi-item rows generated when numColumns > 1.
*/ */
columnWrapperStyle?: DangerouslyImpreciseStyleProp, columnWrapperStyle?: ViewStyleProp,
/** /**
* A marker property for telling the list to re-render (since it implements `PureComponent`). If * A marker property for telling the list to re-render (since it implements `PureComponent`). If
* any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the * any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the

View File

@ -31,7 +31,7 @@ const warning = require('fbjs/lib/warning');
const {computeWindowedRenderLimits} = require('VirtualizeUtils'); const {computeWindowedRenderLimits} = require('VirtualizeUtils');
import type {DangerouslyImpreciseStyleProp, ViewStyleProp} from 'StyleSheet'; import type {ViewStyleProp} from 'StyleSheet';
import type { import type {
ViewabilityConfig, ViewabilityConfig,
ViewToken, ViewToken,
@ -661,7 +661,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
stickyIndicesFromProps: Set<number>, stickyIndicesFromProps: Set<number>,
first: number, first: number,
last: number, last: number,
inversionStyle: ?DangerouslyImpreciseStyleProp, inversionStyle: ViewStyleProp,
) { ) {
const { const {
CellRendererComponent, CellRendererComponent,
@ -1619,7 +1619,7 @@ class CellRenderer extends React.Component<
fillRateHelper: FillRateHelper, fillRateHelper: FillRateHelper,
horizontal: ?boolean, horizontal: ?boolean,
index: number, index: number,
inversionStyle: ?DangerouslyImpreciseStyleProp, inversionStyle: ViewStyleProp,
item: Item, item: Item,
onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader
onUnmount: (cellKey: string) => void, onUnmount: (cellKey: string) => void,

View File

@ -25,24 +25,27 @@ var {
var PAGE_SIZE = 20; var PAGE_SIZE = 20;
type ImageOffset = { type ImageOffset = {|
x: number, x: number,
y: number, y: number,
}; |};
type ImageSize = { type ImageSize = {|
width: number, width: number,
height: number, height: number,
}; |};
type ImageCropData = { type ImageCropData = {|
offset: ImageOffset, offset: ImageOffset,
size: ImageSize, size: ImageSize,
displaySize?: ?ImageSize, displaySize?: ?ImageSize,
resizeMode?: ?any, resizeMode?: ?any,
}; |};
class SquareImageCropper extends React.Component<$FlowFixMeProps, $FlowFixMeState> { class SquareImageCropper extends React.Component<
$FlowFixMeProps,
$FlowFixMeState,
> {
state: any; state: any;
_isMounted: boolean; _isMounted: boolean;
_transformData: ImageCropData; _transformData: ImageCropData;

View File

@ -17,12 +17,12 @@ var {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative;
import type {ViewLayout, ViewLayoutEvent} from 'ViewPropTypes'; import type {ViewLayout, ViewLayoutEvent} from 'ViewPropTypes';
type State = { type State = {
containerStyle?: {width: number}, containerStyle?: {|width: number|},
extraText?: string, extraText?: string,
imageLayout?: ViewLayout, imageLayout?: ViewLayout,
textLayout?: ViewLayout, textLayout?: ViewLayout,
viewLayout?: ViewLayout, viewLayout?: ViewLayout,
viewStyle: {margin: number}, viewStyle: {|margin: number|},
}; };
class LayoutEventExample extends React.Component<{}, State> { class LayoutEventExample extends React.Component<{}, State> {

View File

@ -25,7 +25,7 @@ const View = require('View');
* making Flow check .android.js files. */ * making Flow check .android.js files. */
import type {RNTesterExample} from './RNTesterList.ios'; import type {RNTesterExample} from './RNTesterList.ios';
import type {PassProps} from './RNTesterStatePersister'; import type {PassProps} from './RNTesterStatePersister';
import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; import type {TextStyleProp, ViewStyleProp} from 'StyleSheet';
type Props = { type Props = {
onNavigate: Function, onNavigate: Function,
@ -34,8 +34,8 @@ type Props = {
APIExamples: Array<RNTesterExample>, APIExamples: Array<RNTesterExample>,
}, },
persister: PassProps<*>, persister: PassProps<*>,
searchTextInputStyle: DangerouslyImpreciseStyleProp, searchTextInputStyle: TextStyleProp,
style?: ?DangerouslyImpreciseStyleProp, style?: ?ViewStyleProp,
}; };
class RowComponent extends React.PureComponent<{ class RowComponent extends React.PureComponent<{

View File

@ -9,8 +9,6 @@
*/ */
'use strict'; 'use strict';
import type {DangerouslyImpreciseStyleProp} from 'StyleSheet';
const ActivityIndicator = require('ActivityIndicator'); const ActivityIndicator = require('ActivityIndicator');
const Platform = require('Platform'); const Platform = require('Platform');
const React = require('react'); const React = require('react');
@ -24,6 +22,8 @@ const {
Image, Image,
} = ReactNative; } = ReactNative;
import type {ViewStyleProp} from 'StyleSheet';
exports.displayName = 'ScrollViewExample'; exports.displayName = 'ScrollViewExample';
exports.title = '<ScrollView>'; exports.title = '<ScrollView>';
exports.description = exports.description =
@ -79,7 +79,7 @@ exports.examples = [
render: function() { render: function() {
function renderScrollView( function renderScrollView(
title: string, title: string,
additionalStyles: typeof StyleSheet, additionalStyles: ViewStyleProp,
) { ) {
let _scrollView: ?ScrollView; let _scrollView: ?ScrollView;
return ( return (
@ -261,7 +261,7 @@ if (Platform.OS === 'ios') {
class Thumb extends React.PureComponent<{| class Thumb extends React.PureComponent<{|
source?: string | number, source?: string | number,
msg?: string, msg?: string,
style?: DangerouslyImpreciseStyleProp, style?: ViewStyleProp,
|}> { |}> {
render() { render() {
const {source} = this.props; const {source} = this.props;

View File

@ -104,21 +104,33 @@ exports.examples = [
<TouchableWithoutFeedback onPress={this._handlePress}> <TouchableWithoutFeedback onPress={this._handlePress}>
<View> <View>
<View <View
style={{ style={[
borderWidth: 1, {
borderStyle: this.state.showBorder ? 'dashed' : null, borderWidth: 1,
padding: 5, padding: 5,
}}> },
this.state.showBorder
? {
borderStyle: 'dashed',
}
: null,
]}>
<Text style={{fontSize: 11}}>Dashed border style</Text> <Text style={{fontSize: 11}}>Dashed border style</Text>
</View> </View>
<View <View
style={{ style={[
marginTop: 5, {
borderWidth: 1, marginTop: 5,
borderRadius: 5, borderWidth: 1,
borderStyle: this.state.showBorder ? 'dotted' : null, borderRadius: 5,
padding: 5, padding: 5,
}}> },
this.state.showBorder
? {
borderStyle: 'dotted',
}
: null,
]}>
<Text style={{fontSize: 11}}>Dotted border style</Text> <Text style={{fontSize: 11}}>Dotted border style</Text>
</View> </View>
</View> </View>