From 76948ad1bdc472c166d71e45eb87ac309aac5aa1 Mon Sep 17 00:00:00 2001 From: Eli White Date: Tue, 14 Aug 2018 16:31:04 -0700 Subject: [PATCH] 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 --- IntegrationTests/LayoutEventsTest.js | 14 +++----- Libraries/Components/ScrollView/ScrollView.js | 1 - Libraries/Components/TextInput/TextInput.js | 4 +-- Libraries/Components/View/ViewPropTypes.js | 3 +- .../Experimental/IncrementalPresenter.js | 3 +- Libraries/Image/Image.ios.js | 5 ++- Libraries/Image/ImageEditor.js | 12 +++---- Libraries/Image/ImageProps.js | 4 +-- Libraries/Lists/FlatList.js | 4 +-- Libraries/Lists/VirtualizedList.js | 6 ++-- RNTester/js/ImageEditingExample.js | 17 +++++---- RNTester/js/LayoutEventsExample.js | 4 +-- RNTester/js/RNTesterExampleList.js | 6 ++-- RNTester/js/ScrollViewExample.js | 8 ++--- RNTester/js/ViewExample.js | 36 ++++++++++++------- 15 files changed, 70 insertions(+), 57 deletions(-) diff --git a/IntegrationTests/LayoutEventsTest.js b/IntegrationTests/LayoutEventsTest.js index 5d2676bc1..68227b3e3 100644 --- a/IntegrationTests/LayoutEventsTest.js +++ b/IntegrationTests/LayoutEventsTest.js @@ -16,6 +16,8 @@ const ReactNative = require('react-native'); const {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative; const {TestModule} = ReactNative.NativeModules; +import type {ViewStyleProp} from 'StyleSheet'; + const deepDiffer = require('deepDiffer'); function debug(...args) { @@ -23,14 +25,6 @@ function debug(...args) { } import type {Layout, LayoutEvent} from 'CoreEventTypes'; -type Style = { - margin?: number, - padding?: number, - borderColor?: string, - borderWidth?: number, - backgroundColor?: string, - width?: number, -}; type State = { didAnimation: boolean, @@ -38,8 +32,8 @@ type State = { imageLayout?: Layout, textLayout?: Layout, viewLayout?: Layout, - viewStyle?: Style, - containerStyle?: Style, + viewStyle?: ViewStyleProp, + containerStyle?: ViewStyleProp, }; const LayoutEventsTest = createReactClass({ diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 9f0688e87..aef48e3e1 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -483,7 +483,6 @@ export type Props = $ReadOnly<{| * See [RefreshControl](docs/refreshcontrol.html). */ refreshControl?: ?React.Element, - style?: ?ViewStyleProp, children?: React.Node, |}>; diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 162119b55..3da8b74b8 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -33,7 +33,7 @@ const requireNativeComponent = require('requireNativeComponent'); const warning = require('fbjs/lib/warning'); import type {ColorValue} from 'StyleSheetTypes'; -import type {TextStyleProp} from 'StyleSheet'; +import type {TextStyleProp, ViewStyleProp} from 'StyleSheet'; import type {ViewProps} from 'ViewPropTypes'; let AndroidTextInput; @@ -169,7 +169,7 @@ type AndroidProps = $ReadOnly<{| |}>; type Props = $ReadOnly<{| - ...ViewProps, + ...$Diff>, ...IOSProps, ...AndroidProps, autoCapitalize?: ?AutoCapitalize, diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 238017cf1..377c40bcb 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -33,6 +33,7 @@ import type { import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; import type {TVViewProps} from 'TVViewPropTypes'; import type {Layout, LayoutEvent} from 'CoreEventTypes'; +import type {ViewStyleProp} from 'StyleSheet'; const stylePropType = StyleSheetPropType(ViewStylePropTypes); @@ -103,7 +104,7 @@ export type ViewProps = $ReadOnly<{| nativeID?: string, hitSlop?: ?EdgeInsetsProp, pointerEvents?: null | 'box-none' | 'none' | 'box-only' | 'auto', - style?: stylePropType, + style?: ?ViewStyleProp, removeClippedSubviews?: boolean, renderToHardwareTextureAndroid?: boolean, shouldRasterizeIOS?: boolean, diff --git a/Libraries/Experimental/IncrementalPresenter.js b/Libraries/Experimental/IncrementalPresenter.js index 9927179d1..9f2c9a511 100644 --- a/Libraries/Experimental/IncrementalPresenter.js +++ b/Libraries/Experimental/IncrementalPresenter.js @@ -18,6 +18,7 @@ const View = require('View'); const ViewPropTypes = require('ViewPropTypes'); import type {Context} from 'Incremental'; +import type {ViewStyleProp} from 'StyleSheet'; /** * WARNING: EXPERIMENTAL. Breaking changes will probably happen a lot and will @@ -36,7 +37,7 @@ type Props = { disabled?: boolean, onDone?: () => void, onLayout?: (event: Object) => void, - style?: mixed, + style?: ViewStyleProp, children?: any, }; class IncrementalPresenter extends React.Component { diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index 82e651c03..fc082b098 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -23,6 +23,7 @@ const ImageViewManager = NativeModules.ImageViewManager; const RCTImageView = requireNativeComponent('RCTImageView'); +import type {ImageStyleProp} from 'StyleSheet'; import type {ImageProps as ImagePropsType} from 'ImageProps'; function getSize( @@ -71,12 +72,14 @@ let Image = ( }; let sources; - let style; + let style: ImageStyleProp; if (Array.isArray(source)) { + // $FlowFixMe flattenStyle is not strong enough style = flattenStyle([styles.base, props.style]) || {}; sources = source; } else { const {width, height, uri} = source; + // $FlowFixMe flattenStyle is not strong enough style = flattenStyle([{width, height}, styles.base, props.style]) || {}; sources = [source]; diff --git a/Libraries/Image/ImageEditor.js b/Libraries/Image/ImageEditor.js index 65edcccf1..ec7dc5794 100644 --- a/Libraries/Image/ImageEditor.js +++ b/Libraries/Image/ImageEditor.js @@ -16,25 +16,25 @@ type ImageCropData = { * The top-left corner of the cropped image, specified in the original * image's coordinate space. */ - offset: { + offset: {| x: number, y: number, - }, + |}, /** * The size (dimensions) of the cropped image, specified in the original * image's coordinate space. */ - size: { + size: {| width: number, height: number, - }, + |}, /** * (Optional) size to scale the cropped image to. */ - displaySize?: ?{ + displaySize?: ?{| width: number, height: number, - }, + |}, /** * (Optional) the resizing mode to use when scaling the image. If the * `displaySize` param is not specified, this has no effect. diff --git a/Libraries/Image/ImageProps.js b/Libraries/Image/ImageProps.js index 54f6250e1..f22209383 100644 --- a/Libraries/Image/ImageProps.js +++ b/Libraries/Image/ImageProps.js @@ -21,7 +21,7 @@ import type {ViewProps} from 'ViewPropTypes'; import type {ImageSource} from 'ImageSource'; import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; import type {SyntheticEvent} from 'CoreEventTypes'; -import type {ImageStyleProp} from 'StyleSheet'; +import type {ViewStyleProp, ImageStyleProp} from 'StyleSheet'; type OnLoadEvent = SyntheticEvent< $ReadOnly<{| @@ -51,7 +51,7 @@ type AndroidImageProps = $ReadOnly<{| |}>; export type ImageProps = {| - ...ViewProps, + ...$Diff>, ...IOSImageProps, ...AndroidImageProps, blurRadius?: number, diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index adebd267f..607919efa 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -18,7 +18,7 @@ const StyleSheet = require('StyleSheet'); const invariant = require('fbjs/lib/invariant'); -import type {DangerouslyImpreciseStyleProp, ViewStyleProp} from 'StyleSheet'; +import type {ViewStyleProp} from 'StyleSheet'; import type { ViewabilityConfig, ViewToken, @@ -104,7 +104,7 @@ type OptionalProps = { /** * 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 * any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 2efbba657..f405efcb4 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -31,7 +31,7 @@ const warning = require('fbjs/lib/warning'); const {computeWindowedRenderLimits} = require('VirtualizeUtils'); -import type {DangerouslyImpreciseStyleProp, ViewStyleProp} from 'StyleSheet'; +import type {ViewStyleProp} from 'StyleSheet'; import type { ViewabilityConfig, ViewToken, @@ -661,7 +661,7 @@ class VirtualizedList extends React.PureComponent { stickyIndicesFromProps: Set, first: number, last: number, - inversionStyle: ?DangerouslyImpreciseStyleProp, + inversionStyle: ViewStyleProp, ) { const { CellRendererComponent, @@ -1619,7 +1619,7 @@ class CellRenderer extends React.Component< fillRateHelper: FillRateHelper, horizontal: ?boolean, index: number, - inversionStyle: ?DangerouslyImpreciseStyleProp, + inversionStyle: ViewStyleProp, item: Item, onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader onUnmount: (cellKey: string) => void, diff --git a/RNTester/js/ImageEditingExample.js b/RNTester/js/ImageEditingExample.js index 0bc25ce26..fb6018bab 100644 --- a/RNTester/js/ImageEditingExample.js +++ b/RNTester/js/ImageEditingExample.js @@ -25,24 +25,27 @@ var { var PAGE_SIZE = 20; -type ImageOffset = { +type ImageOffset = {| x: number, y: number, -}; +|}; -type ImageSize = { +type ImageSize = {| width: number, height: number, -}; +|}; -type ImageCropData = { +type ImageCropData = {| offset: ImageOffset, size: ImageSize, displaySize?: ?ImageSize, resizeMode?: ?any, -}; +|}; -class SquareImageCropper extends React.Component<$FlowFixMeProps, $FlowFixMeState> { +class SquareImageCropper extends React.Component< + $FlowFixMeProps, + $FlowFixMeState, +> { state: any; _isMounted: boolean; _transformData: ImageCropData; diff --git a/RNTester/js/LayoutEventsExample.js b/RNTester/js/LayoutEventsExample.js index f5556a868..3d14aee86 100644 --- a/RNTester/js/LayoutEventsExample.js +++ b/RNTester/js/LayoutEventsExample.js @@ -17,12 +17,12 @@ var {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative; import type {ViewLayout, ViewLayoutEvent} from 'ViewPropTypes'; type State = { - containerStyle?: {width: number}, + containerStyle?: {|width: number|}, extraText?: string, imageLayout?: ViewLayout, textLayout?: ViewLayout, viewLayout?: ViewLayout, - viewStyle: {margin: number}, + viewStyle: {|margin: number|}, }; class LayoutEventExample extends React.Component<{}, State> { diff --git a/RNTester/js/RNTesterExampleList.js b/RNTester/js/RNTesterExampleList.js index 7ad207a80..1a732ae56 100644 --- a/RNTester/js/RNTesterExampleList.js +++ b/RNTester/js/RNTesterExampleList.js @@ -25,7 +25,7 @@ const View = require('View'); * making Flow check .android.js files. */ import type {RNTesterExample} from './RNTesterList.ios'; import type {PassProps} from './RNTesterStatePersister'; -import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; +import type {TextStyleProp, ViewStyleProp} from 'StyleSheet'; type Props = { onNavigate: Function, @@ -34,8 +34,8 @@ type Props = { APIExamples: Array, }, persister: PassProps<*>, - searchTextInputStyle: DangerouslyImpreciseStyleProp, - style?: ?DangerouslyImpreciseStyleProp, + searchTextInputStyle: TextStyleProp, + style?: ?ViewStyleProp, }; class RowComponent extends React.PureComponent<{ diff --git a/RNTester/js/ScrollViewExample.js b/RNTester/js/ScrollViewExample.js index 6d70a6262..6a15ae252 100644 --- a/RNTester/js/ScrollViewExample.js +++ b/RNTester/js/ScrollViewExample.js @@ -9,8 +9,6 @@ */ 'use strict'; -import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; - const ActivityIndicator = require('ActivityIndicator'); const Platform = require('Platform'); const React = require('react'); @@ -24,6 +22,8 @@ const { Image, } = ReactNative; +import type {ViewStyleProp} from 'StyleSheet'; + exports.displayName = 'ScrollViewExample'; exports.title = ''; exports.description = @@ -79,7 +79,7 @@ exports.examples = [ render: function() { function renderScrollView( title: string, - additionalStyles: typeof StyleSheet, + additionalStyles: ViewStyleProp, ) { let _scrollView: ?ScrollView; return ( @@ -261,7 +261,7 @@ if (Platform.OS === 'ios') { class Thumb extends React.PureComponent<{| source?: string | number, msg?: string, - style?: DangerouslyImpreciseStyleProp, + style?: ViewStyleProp, |}> { render() { const {source} = this.props; diff --git a/RNTester/js/ViewExample.js b/RNTester/js/ViewExample.js index 89ce92d3f..89419b22a 100644 --- a/RNTester/js/ViewExample.js +++ b/RNTester/js/ViewExample.js @@ -104,21 +104,33 @@ exports.examples = [ + style={[ + { + borderWidth: 1, + padding: 5, + }, + this.state.showBorder + ? { + borderStyle: 'dashed', + } + : null, + ]}> Dashed border style + style={[ + { + marginTop: 5, + borderWidth: 1, + borderRadius: 5, + padding: 5, + }, + this.state.showBorder + ? { + borderStyle: 'dotted', + } + : null, + ]}> Dotted border style