diff --git a/Libraries/ActivityIndicator/ActivityIndicator.web.js b/Libraries/ActivityIndicator/ActivityIndicator.web.js index 462aa82..74bbf8e 100644 --- a/Libraries/ActivityIndicator/ActivityIndicator.web.js +++ b/Libraries/ActivityIndicator/ActivityIndicator.web.js @@ -9,7 +9,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import View from 'ReactView'; import StyleSheet from 'ReactStyleSheet'; import assign from 'domkit/appendVendorPrefix'; diff --git a/Libraries/Animated/Animated.web.js b/Libraries/Animated/Animated.web.js index e91f85e..31e90c7 100644 --- a/Libraries/Animated/Animated.web.js +++ b/Libraries/Animated/Animated.web.js @@ -11,7 +11,7 @@ 'use strict'; import Animated from 'animated'; -import CSSPropertyOperations from 'react-dom/lib/CSSPropertyOperations'; +import setValueForStyles from '../Utilties/setValueForStyles.web'; import flattenStyle from 'ReactFlattenStyle'; import Image from 'ReactImage'; @@ -40,7 +40,7 @@ function ApplyAnimatedValues(instance, props) { if (instance.setNativeProps) { instance.setNativeProps(props); } else if (instance.nodeType && instance.setAttribute !== undefined) { - CSSPropertyOperations.setValueForStyles(instance, mapStyle(props.style)); + setValueForStyles(instance, mapStyle(props.style)); } else { return false; } diff --git a/Libraries/DrawerLayout/DrawerLayout.web.js b/Libraries/DrawerLayout/DrawerLayout.web.js index a54f43f..623599b 100644 --- a/Libraries/DrawerLayout/DrawerLayout.web.js +++ b/Libraries/DrawerLayout/DrawerLayout.web.js @@ -6,7 +6,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import StyleSheet from 'ReactStyleSheet'; import View from 'ReactView'; import Animated from 'ReactAnimated'; diff --git a/Libraries/Image/Image.web.js b/Libraries/Image/Image.web.js index e18a34a..412f515 100644 --- a/Libraries/Image/Image.web.js +++ b/Libraries/Image/Image.web.js @@ -6,7 +6,8 @@ */ 'use strict'; -import React, {Component, PropTypes} from 'react'; +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; import View from 'ReactView'; import { Mixin as LayoutMixin } from 'ReactLayoutMixin'; import ImageResizeMode from './ImageResizeMode'; @@ -34,7 +35,7 @@ class Image extends Component { } static contextTypes = { - isInAParentText: React.PropTypes.bool + isInAParentText: PropTypes.bool } static getSize = function( diff --git a/Libraries/ListView/ListView.web.js b/Libraries/ListView/ListView.web.js index b7cce7b..69b21fb 100644 --- a/Libraries/ListView/ListView.web.js +++ b/Libraries/ListView/ListView.web.js @@ -8,7 +8,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import ListViewDataSource from 'ReactListViewDataSource'; import ScrollView from 'ReactScrollView'; @@ -159,12 +160,12 @@ class ListView extends Component { * A function that returns the scrollable component in which the list rows * are rendered. Defaults to returning a ScrollView with the given props. */ - renderScrollComponent: React.PropTypes.func.isRequired, + renderScrollComponent: PropTypes.func.isRequired, /** * How early to start rendering rows before they come on screen, in * pixels. */ - scrollRenderAheadDistance: React.PropTypes.number, + scrollRenderAheadDistance: PropTypes.number, /** * (visibleRows, changedRows) => void * @@ -174,13 +175,13 @@ class ListView extends Component { * that have changed their visibility, with true indicating visible, and * false indicating the view has moved out of view. */ - onChangeVisibleRows: React.PropTypes.func, + onChangeVisibleRows: PropTypes.func, /** * A performance optimization for improving scroll perf of * large lists, used in conjunction with overflow: 'hidden' on the row * containers. This is enabled by default. */ - removeClippedSubviews: React.PropTypes.bool, + removeClippedSubviews: PropTypes.bool, /** * An array of child indices determining which children get docked to the * top of the screen when scrolling. For example, passing diff --git a/Libraries/ListView/StaticRenderer.web.js b/Libraries/ListView/StaticRenderer.web.js index 36af765..6d87be4 100644 --- a/Libraries/ListView/StaticRenderer.web.js +++ b/Libraries/ListView/StaticRenderer.web.js @@ -6,7 +6,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; class StaticRenderer extends Component { static propTypes = { diff --git a/Libraries/Modal/Modal.web.js b/Libraries/Modal/Modal.web.js index b98fcfa..82b8a01 100644 --- a/Libraries/Modal/Modal.web.js +++ b/Libraries/Modal/Modal.web.js @@ -6,7 +6,8 @@ */ 'use strict'; -import React, { PropTypes, Component } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import StyleSheet from 'ReactStyleSheet'; import View from 'ReactView'; diff --git a/Libraries/Navigator/Navigator.web.js b/Libraries/Navigator/Navigator.web.js index 3228139..cf3b063 100644 --- a/Libraries/Navigator/Navigator.web.js +++ b/Libraries/Navigator/Navigator.web.js @@ -9,7 +9,8 @@ /* eslint-disable no-extra-boolean-cast*/ 'use strict'; -import React, { PropTypes } from 'react'; +import React from 'react'; +import PropTypes from 'prop-types'; import Dimensions from 'ReactDimensions'; import InteractionMixin from 'ReactInteractionMixin'; import Map from 'core-js/library/fn/map'; diff --git a/Libraries/Navigator/NavigatorBreadcrumbNavigationBar.js b/Libraries/Navigator/NavigatorBreadcrumbNavigationBar.js index a791d16..d6aa1ce 100644 --- a/Libraries/Navigator/NavigatorBreadcrumbNavigationBar.js +++ b/Libraries/Navigator/NavigatorBreadcrumbNavigationBar.js @@ -9,7 +9,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import NavigatorBreadcrumbNavigationBarStyles from 'ReactNavigatorBreadcrumbNavigationBarStyles'; import NavigatorNavigationBarStylesAndroid from 'ReactNavigatorNavigationBarStylesAndroid'; import NavigatorNavigationBarStylesIOS from 'ReactNavigatorNavigationBarStylesIOS'; @@ -70,9 +71,9 @@ class NavigatorBreadcrumbNavigationBar extends Component { titleContentForRoute: PropTypes.func, iconForRoute: PropTypes.func, }), - navState: React.PropTypes.shape({ - routeStack: React.PropTypes.arrayOf(React.PropTypes.object), - presentedIndex: React.PropTypes.number, + navState: PropTypes.shape({ + routeStack: PropTypes.arrayOf(PropTypes.object), + presentedIndex: PropTypes.number, }), style: View.propTypes.style, } diff --git a/Libraries/Navigator/NavigatorNavigationBar.js b/Libraries/Navigator/NavigatorNavigationBar.js index eb91d99..95bed11 100644 --- a/Libraries/Navigator/NavigatorNavigationBar.js +++ b/Libraries/Navigator/NavigatorNavigationBar.js @@ -9,7 +9,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import NavigatorNavigationBarStylesAndroid from 'ReactNavigatorNavigationBarStylesAndroid'; import NavigatorNavigationBarStylesIOS from 'ReactNavigatorNavigationBarStylesIOS'; import Platform from 'ReactStyleSheet'; diff --git a/Libraries/Picker/Picker.web.js b/Libraries/Picker/Picker.web.js index e1d3d1b..68e1754 100644 --- a/Libraries/Picker/Picker.web.js +++ b/Libraries/Picker/Picker.web.js @@ -6,7 +6,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import autobind from 'autobind-decorator'; const PICKER = 'picker'; diff --git a/Libraries/ScrollView/ScrollView.web.js b/Libraries/ScrollView/ScrollView.web.js index 00303f5..53dbfd3 100644 --- a/Libraries/ScrollView/ScrollView.web.js +++ b/Libraries/ScrollView/ScrollView.web.js @@ -8,7 +8,8 @@ */ 'use strict'; -import React, { PropTypes, Component} from 'react'; +import React, { Component} from 'react'; +import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import ScrollResponder from 'ReactScrollResponder'; import StyleSheet from 'ReactStyleSheet'; diff --git a/Libraries/SegmentedControl/SegmentedControl.web.js b/Libraries/SegmentedControl/SegmentedControl.web.js index 144f731..e5c300e 100644 --- a/Libraries/SegmentedControl/SegmentedControl.web.js +++ b/Libraries/SegmentedControl/SegmentedControl.web.js @@ -8,7 +8,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import View from 'ReactView'; import Text from 'ReactText'; import StyleSheet from 'ReactStyleSheet'; diff --git a/Libraries/Slider/Slider.web.js b/Libraries/Slider/Slider.web.js index 97b3881..cec04a1 100644 --- a/Libraries/Slider/Slider.web.js +++ b/Libraries/Slider/Slider.web.js @@ -9,7 +9,8 @@ */ 'use strict'; -import React, { PropTypes, Component } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import StyleSheet from 'ReactStyleSheet'; import View from 'ReactView'; diff --git a/Libraries/Switch/Switch.web.js b/Libraries/Switch/Switch.web.js index 7b9c14c..d7e1d75 100644 --- a/Libraries/Switch/Switch.web.js +++ b/Libraries/Switch/Switch.web.js @@ -6,7 +6,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import { Mixin as NativeMethodsMixin } from 'NativeMethodsMixin'; import StyleSheet from 'ReactStyleSheet'; import mixin from 'react-mixin'; diff --git a/Libraries/TabBar/TabBar.web.js b/Libraries/TabBar/TabBar.web.js index b59c4b7..2d9c7ea 100644 --- a/Libraries/TabBar/TabBar.web.js +++ b/Libraries/TabBar/TabBar.web.js @@ -7,6 +7,7 @@ 'use strict'; import React from 'react'; +import PropTypes from 'prop-types'; import View from 'ReactView'; import TabBarItem from './TabBarItem.web'; import TabBarContents from './TabBarContents.web'; @@ -25,17 +26,17 @@ let TabBar = React.createClass({ }, propTypes: { - style: React.PropTypes.object, + style: PropTypes.object, /** * Color of the currently selected tab icon */ - tintColor: React.PropTypes.string, + tintColor: PropTypes.string, /** * Background color of the tab bar */ - barTintColor: React.PropTypes.string, + barTintColor: PropTypes.string, - clientHeight: React.PropTypes.number + clientHeight: PropTypes.number }, getStyles() { diff --git a/Libraries/TabBar/TabBarItem.web.js b/Libraries/TabBar/TabBarItem.web.js index 5eb59e1..28b8624 100644 --- a/Libraries/TabBar/TabBarItem.web.js +++ b/Libraries/TabBar/TabBarItem.web.js @@ -5,7 +5,8 @@ */ 'use strict'; -import React, { PropTypes } from 'react'; +import React from 'react'; +import PropTypes from 'prop-types'; import Image from 'ReactImage'; import Text from 'ReactText'; import View from 'ReactView'; diff --git a/Libraries/Text/Text.web.js b/Libraries/Text/Text.web.js index 2eb2bff..163820e 100644 --- a/Libraries/Text/Text.web.js +++ b/Libraries/Text/Text.web.js @@ -9,6 +9,7 @@ 'use strict'; import React from 'react'; +import PropTypes from 'prop-types'; import { Mixin as TouchableMixin } from 'ReactTouchable'; import { Mixin as LayoutMixin } from 'ReactLayoutMixin'; import { Mixin as NativeMethodsMixin } from 'NativeMethodsMixin'; @@ -56,31 +57,31 @@ let Text = React.createClass({ * layout, including line wrapping, such that the total number of lines * does not exceed this number. */ - numberOfLines: React.PropTypes.number, + numberOfLines: PropTypes.number, /** * Invoked on mount and layout changes with * * `{nativeEvent: {layout: {x, y, width, height}}}` */ - onLayout: React.PropTypes.func, + onLayout: PropTypes.func, /** * This function is called on press. */ - onPress: React.PropTypes.func, + onPress: PropTypes.func, /** * When true, no visual change is made when text is pressed down. By * default, a gray oval highlights the text on press down. * @platform ios */ - suppressHighlighting: React.PropTypes.bool, + suppressHighlighting: PropTypes.bool, /** * Used to locate this view in end-to-end tests. */ - testID: React.PropTypes.string, + testID: PropTypes.string, /** * Specifies should fonts scale to respect Text Size accessibility setting on iOS. */ - allowFontScaling: React.PropTypes.bool, + allowFontScaling: PropTypes.bool, }, getInitialState(): Object { @@ -177,11 +178,11 @@ let Text = React.createClass({ }, contextTypes: { - isInAParentText: React.PropTypes.bool + isInAParentText: PropTypes.bool }, childContextTypes: { - isInAParentText: React.PropTypes.bool + isInAParentText: PropTypes.bool }, render() { diff --git a/Libraries/TextInput/TextInput.web.js b/Libraries/TextInput/TextInput.web.js index 333eae1..127c88f 100644 --- a/Libraries/TextInput/TextInput.web.js +++ b/Libraries/TextInput/TextInput.web.js @@ -8,7 +8,8 @@ */ 'use strict'; -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import View from 'ReactView'; import autobind from 'autobind-decorator'; diff --git a/Libraries/Touchable/TouchableBounce.web.js b/Libraries/Touchable/TouchableBounce.web.js index 56a853a..f7e8c81 100644 --- a/Libraries/Touchable/TouchableBounce.web.js +++ b/Libraries/Touchable/TouchableBounce.web.js @@ -10,6 +10,7 @@ import Animated from 'ReactAnimated'; import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import { Mixin as TouchableMixin } from 'ReactTouchable'; import mixin from 'react-mixin'; import autobind from 'autobind-decorator'; @@ -36,15 +37,15 @@ var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; class TouchableBounce extends Component { static propTypes = { - onPress: React.PropTypes.func, - onPressIn: React.PropTypes.func, - onPressOut: React.PropTypes.func, + onPress: PropTypes.func, + onPressIn: PropTypes.func, + onPressOut: PropTypes.func, // The function passed takes a callback to start the animation which should // be run after this onPress handler is done. You can use this (for example) // to update UI before starting the animation. - onPressWithCompletion: React.PropTypes.func, + onPressWithCompletion: PropTypes.func, // the function passed is called after the animation is complete - onPressAnimationComplete: React.PropTypes.func, + onPressAnimationComplete: PropTypes.func, } state = { diff --git a/Libraries/Touchable/TouchableHighlight.web.js b/Libraries/Touchable/TouchableHighlight.web.js index a700e7e..b3b1714 100644 --- a/Libraries/Touchable/TouchableHighlight.web.js +++ b/Libraries/Touchable/TouchableHighlight.web.js @@ -9,6 +9,7 @@ 'use strict'; import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import View from 'ReactView'; import TimerMixin from 'react-timer-mixin'; import TouchableWithoutFeedback from 'ReactTouchableWithoutFeedback'; @@ -51,20 +52,20 @@ class TouchableHighlight extends Component { * Determines what the opacity of the wrapped view should be when touch is * active. */ - activeOpacity: React.PropTypes.number, + activeOpacity: PropTypes.number, /** * The color of the underlay that will show through when the touch is * active. */ - underlayColor: React.PropTypes.string, + underlayColor: PropTypes.string, /** * Called immediately after the underlay is shown */ - onShowUnderlay: React.PropTypes.func, + onShowUnderlay: PropTypes.func, /** * Called immediately after the underlay is hidden */ - onHideUnderlay: React.PropTypes.func, + onHideUnderlay: PropTypes.func, } static defaultProps = DEFAULT_PROPS diff --git a/Libraries/Touchable/TouchableOpacity.web.js b/Libraries/Touchable/TouchableOpacity.web.js index f6080c7..e17c074 100644 --- a/Libraries/Touchable/TouchableOpacity.web.js +++ b/Libraries/Touchable/TouchableOpacity.web.js @@ -10,6 +10,7 @@ import Animated from 'ReactAnimated'; import React from 'react'; +import PropTypes from 'prop-types'; import TimerMixin from 'react-timer-mixin'; import { Mixin as TouchableMixin } from 'ReactTouchable'; import TouchableWithoutFeedback from 'ReactTouchableWithoutFeedback'; @@ -60,7 +61,7 @@ class TouchableOpacity extends React.Component { * Determines what the opacity of the wrapped view should be when touch is * active. */ - activeOpacity: React.PropTypes.number, + activeOpacity: PropTypes.number, }; static defaultProps = DEFAULT_PROPS; diff --git a/Libraries/Touchable/TouchableWithoutFeedback.web.js b/Libraries/Touchable/TouchableWithoutFeedback.web.js index 8c372fb..22c7c70 100644 --- a/Libraries/Touchable/TouchableWithoutFeedback.web.js +++ b/Libraries/Touchable/TouchableWithoutFeedback.web.js @@ -10,6 +10,7 @@ import 'ReactPanResponder'; import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import Touchable from 'ReactTouchable'; import mixin from 'react-mixin'; import autobind from 'autobind-decorator'; @@ -40,24 +41,24 @@ class TouchableWithoutFeedback extends Component { * Called when the touch is released, but not if cancelled (e.g. by a scroll * that steals the responder lock). */ - onPress: React.PropTypes.func, - onPressIn: React.PropTypes.func, - onPressOut: React.PropTypes.func, + onPress: PropTypes.func, + onPressIn: PropTypes.func, + onPressOut: PropTypes.func, - onLongPress: React.PropTypes.func, + onLongPress: PropTypes.func, /** * Delay in ms, from the start of the touch, before onPressIn is called. */ - delayPressIn: React.PropTypes.number, + delayPressIn: PropTypes.number, /** * Delay in ms, from the release of the touch, before onPressOut is called. */ - delayPressOut: React.PropTypes.number, + delayPressOut: PropTypes.number, /** * Delay in ms, from onPressIn, before onLongPress is called. */ - delayLongPress: React.PropTypes.number, + delayLongPress: PropTypes.number, } state = this.touchableGetInitialState() diff --git a/Libraries/Utilties/setNativeProps.web.js b/Libraries/Utilties/setNativeProps.web.js index 1e5ac12..14f4eef 100644 --- a/Libraries/Utilties/setNativeProps.web.js +++ b/Libraries/Utilties/setNativeProps.web.js @@ -5,7 +5,7 @@ */ 'use strict'; -var CSSPropertyOperations = require('react-dom/lib/CSSPropertyOperations'); +import setValueForStyles from '../Utilties/setValueForStyles.web'; // some number that react not auto add px var numberTransformProperties = { @@ -82,7 +82,7 @@ function setNativeProps(node, props, component) { style = convertTransform(style); } - CSSPropertyOperations.setValueForStyles(node, style, component); + setValueForStyles(node, style, component); } else { node.setAttribute(name, props[name]); } diff --git a/Libraries/Utilties/setValueForStyles.web.js b/Libraries/Utilties/setValueForStyles.web.js new file mode 100644 index 0000000..3870d7c --- /dev/null +++ b/Libraries/Utilties/setValueForStyles.web.js @@ -0,0 +1,236 @@ +/** + * Copyright 2013-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. + * + */ + +'use strict'; + +import unitlessNumbers from './unitlessNumbers'; + +if (process.env.NODE_ENV !== 'production') { + var camelizeStyleName = require('fbjs/lib/camelizeStyleName'); + var warning = require('fbjs/lib/warning'); + + // 'msTransform' is correct, but the other prefixes should be capitalized + var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; + + // style values shouldn't contain a semicolon + var badStyleValueWithSemicolonPattern = /;\s*$/; + + var warnedStyleNames = {}; + var warnedStyleValues = {}; + var warnedForNaNValue = false; + + var warnHyphenatedStyleName = function(name, owner) { + if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { + return; + } + + warnedStyleNames[name] = true; + process.env.NODE_ENV !== 'production' + ? warning( + false, + 'Unsupported style property %s. Did you mean %s?%s', + name, + camelizeStyleName(name), + checkRenderMessage(owner) + ) + : void 0; + }; + + var warnBadVendoredStyleName = function(name, owner) { + if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { + return; + } + + warnedStyleNames[name] = true; + process.env.NODE_ENV !== 'production' + ? warning( + false, + 'Unsupported vendor-prefixed style property %s. Did you mean %s?%s', + name, + name.charAt(0).toUpperCase() + name.slice(1), + checkRenderMessage(owner) + ) + : void 0; + }; + + var warnStyleValueWithSemicolon = function(name, value, owner) { + if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { + return; + } + + warnedStyleValues[value] = true; + process.env.NODE_ENV !== 'production' + ? warning( + false, + "Style property values shouldn't contain a semicolon.%s " + 'Try "%s: %s" instead.', + checkRenderMessage(owner), + name, + value.replace(badStyleValueWithSemicolonPattern, '') + ) + : void 0; + }; + + var warnStyleValueIsNaN = function(name, value, owner) { + if (warnedForNaNValue) { + return; + } + + warnedForNaNValue = true; + process.env.NODE_ENV !== 'production' + ? warning( + false, + '`NaN` is an invalid value for the `%s` css style property.%s', + name, + checkRenderMessage(owner) + ) + : void 0; + }; + + var checkRenderMessage = function(owner) { + if (owner) { + var name = owner.getName(); + if (name) { + return ' Check the render method of `' + name + '`.'; + } + } + return ''; + }; + + /** + * @param {string} name + * @param {*} value + * @param {ReactDOMComponent} component + */ + var warnValidStyle = function(name, value, component) { + var owner; + if (component) { + owner = component._currentElement._owner; + } + if (name.indexOf('-') > -1) { + warnHyphenatedStyleName(name, owner); + } else if (badVendoredStyleNamePattern.test(name)) { + warnBadVendoredStyleName(name, owner); + } else if (badStyleValueWithSemicolonPattern.test(value)) { + warnStyleValueWithSemicolon(name, value, owner); + } + + if (typeof value === 'number' && isNaN(value)) { + warnStyleValueIsNaN(name, value, owner); + } + }; +} + +var styleWarnings = {}; + +/** + * Convert a value into the proper css writable value. The style name `name` + * should be logical (no hyphens) + * + * @param {string} name CSS property name such as `topMargin`. + * @param {*} value CSS property value such as `10px`. + * @param {ReactDOMComponent} component + * @return {string} Normalized style value with dimensions applied. + */ +function dangerousStyleValue(name, value, component) { + // Note that we've removed escapeTextForBrowser() calls here since the + // whole string will be escaped when the attribute is injected into + // the markup. If you provide unsafe user data here they can inject + // arbitrary CSS which may be problematic (I couldn't repro this): + // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ + // This is not an XSS hole but instead a potential CSS injection issue + // which has lead to a greater discussion about how we're going to + // trust URLs moving forward. See #2115901 + + var isEmpty = value == null || typeof value === 'boolean' || value === ''; + if (isEmpty) { + return ''; + } + + var isNonNumeric = isNaN(value); + if ( + isNonNumeric || + value === 0 || + (unitlessNumbers.hasOwnProperty(name) && unitlessNumbers[name]) + ) { + return '' + value; // cast to string + } + + if (typeof value === 'string') { + if (process.env.NODE_ENV !== 'production') { + var warning = require('fbjs/lib/warning'); + + // Allow '0' to pass through without warning. 0 is already special and + // doesn't require units, so we don't need to warn about it. + if (component && value !== '0') { + var owner = component._currentElement._owner; + var ownerName = owner ? owner.getName() : null; + if (ownerName && !styleWarnings[ownerName]) { + styleWarnings[ownerName] = {}; + } + var warned = false; + if (ownerName) { + var warnings = styleWarnings[ownerName]; + warned = warnings[name]; + if (!warned) { + warnings[name] = true; + } + } + if (!warned) { + process.env.NODE_ENV !== 'production' + ? warning( + false, + 'a `%s` tag (owner: `%s`) was passed a numeric string value ' + + 'for CSS property `%s` (value: `%s`) which will be treated ' + + 'as a unitless number in a future version of React.', + component._currentElement.type, + ownerName || 'unknown', + name, + value + ) + : void 0; + } + } + } + value = value.trim(); + } + return value + 'px'; +} + +/** + * Sets the value for multiple styles on a node. If a value is specified as + * '' (empty string), the corresponding style property will be unset. + * + * @param {DOMElement} node + * @param {object} styles + * @param {ReactDOMComponent} component + */ +const setValueForStyles = function(node, styles, component) { + var style = node.style; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + if (process.env.NODE_ENV !== 'production') { + // warnValidStyle(styleName, styles[styleName], component); + } + var styleValue = dangerousStyleValue(styleName, styles[styleName], component); + if (styleName === 'float' || styleName === 'cssFloat') { + styleName = 'cssFloat'; + } + if (styleValue) { + style[styleName] = styleValue; + } else { + style[styleName] = ''; + } + } +}; + +module.exports = setValueForStyles; diff --git a/Libraries/Utilties/unitlessNumbers.js b/Libraries/Utilties/unitlessNumbers.js new file mode 100644 index 0000000..4bc5316 --- /dev/null +++ b/Libraries/Utilties/unitlessNumbers.js @@ -0,0 +1,45 @@ +const unitlessNumbers = { + animationIterationCount: true, + borderImageOutset: true, + borderImageSlice: true, + borderImageWidth: true, + boxFlex: true, + boxFlexGroup: true, + boxOrdinalGroup: true, + columnCount: true, + flex: true, + flexGrow: true, + flexOrder: true, + flexPositive: true, + flexShrink: true, + flexNegative: true, + fontWeight: true, + gridRow: true, + gridColumn: true, + lineClamp: true, + opacity: true, + order: true, + orphans: true, + tabSize: true, + widows: true, + zIndex: true, + zoom: true, + // SVG-related + fillOpacity: true, + floodOpacity: true, + stopOpacity: true, + strokeDasharray: true, + strokeDashoffset: true, + strokeMiterlimit: true, + strokeOpacity: true, + strokeWidth: true, + // transform types + scale: true, + scaleX: true, + scaleY: true, + scaleZ: true, + // RN properties + shadowOpacity: true +}; + +module.exports = unitlessNumbers; diff --git a/Libraries/View/View.web.js b/Libraries/View/View.web.js index 76a4b8b..a74e7c8 100644 --- a/Libraries/View/View.web.js +++ b/Libraries/View/View.web.js @@ -8,7 +8,8 @@ */ 'use strict'; -import React, { PropTypes } from 'react'; +import React from 'react'; +import PropTypes from 'prop-types'; import StyleSheet from 'ReactStyleSheet'; import { Mixin as LayoutMixin } from 'ReactLayoutMixin'; import { Mixin as NativeMethodsMixin } from 'NativeMethodsMixin'; diff --git a/Libraries/ViewPager/ViewPager.web.js b/Libraries/ViewPager/ViewPager.web.js index 243fe1c..fe028a0 100644 --- a/Libraries/ViewPager/ViewPager.web.js +++ b/Libraries/ViewPager/ViewPager.web.js @@ -7,7 +7,8 @@ */ 'use strict'; -import React, { PropTypes, cloneElement } from 'react'; +import React, { cloneElement } from 'react'; +import PropTypes from 'prop-types'; import assign from 'object-assign'; import View from 'ReactView'; import Animated from 'ReactAnimated';