UNPKG

7.2 kBJavaScriptView Raw
1/**
2 * Copyright 2013-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11'use strict';
12
13var CSSProperty = require('./CSSProperty');
14var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
15var ReactInstrumentation = require('./ReactInstrumentation');
16
17var camelizeStyleName = require('fbjs/lib/camelizeStyleName');
18var dangerousStyleValue = require('./dangerousStyleValue');
19var hyphenateStyleName = require('fbjs/lib/hyphenateStyleName');
20var memoizeStringOnly = require('fbjs/lib/memoizeStringOnly');
21var warning = require('fbjs/lib/warning');
22
23var processStyleName = memoizeStringOnly(function (styleName) {
24 return hyphenateStyleName(styleName);
25});
26
27var hasShorthandPropertyBug = false;
28var styleFloatAccessor = 'cssFloat';
29if (ExecutionEnvironment.canUseDOM) {
30 var tempStyle = document.createElement('div').style;
31 try {
32 // IE8 throws "Invalid argument." if resetting shorthand style properties.
33 tempStyle.font = '';
34 } catch (e) {
35 hasShorthandPropertyBug = true;
36 }
37 // IE8 only supports accessing cssFloat (standard) as styleFloat
38 if (document.documentElement.style.cssFloat === undefined) {
39 styleFloatAccessor = 'styleFloat';
40 }
41}
42
43if (process.env.NODE_ENV !== 'production') {
44 // 'msTransform' is correct, but the other prefixes should be capitalized
45 var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/;
46
47 // style values shouldn't contain a semicolon
48 var badStyleValueWithSemicolonPattern = /;\s*$/;
49
50 var warnedStyleNames = {};
51 var warnedStyleValues = {};
52 var warnedForNaNValue = false;
53
54 var warnHyphenatedStyleName = function (name, owner) {
55 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
56 return;
57 }
58
59 warnedStyleNames[name] = true;
60 process.env.NODE_ENV !== 'production' ? warning(false, 'Unsupported style property %s. Did you mean %s?%s', name, camelizeStyleName(name), checkRenderMessage(owner)) : void 0;
61 };
62
63 var warnBadVendoredStyleName = function (name, owner) {
64 if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
65 return;
66 }
67
68 warnedStyleNames[name] = true;
69 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;
70 };
71
72 var warnStyleValueWithSemicolon = function (name, value, owner) {
73 if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {
74 return;
75 }
76
77 warnedStyleValues[value] = true;
78 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;
79 };
80
81 var warnStyleValueIsNaN = function (name, value, owner) {
82 if (warnedForNaNValue) {
83 return;
84 }
85
86 warnedForNaNValue = true;
87 process.env.NODE_ENV !== 'production' ? warning(false, '`NaN` is an invalid value for the `%s` css style property.%s', name, checkRenderMessage(owner)) : void 0;
88 };
89
90 var checkRenderMessage = function (owner) {
91 if (owner) {
92 var name = owner.getName();
93 if (name) {
94 return ' Check the render method of `' + name + '`.';
95 }
96 }
97 return '';
98 };
99
100 /**
101 * @param {string} name
102 * @param {*} value
103 * @param {ReactDOMComponent} component
104 */
105 var warnValidStyle = function (name, value, component) {
106 var owner;
107 if (component) {
108 owner = component._currentElement._owner;
109 }
110 if (name.indexOf('-') > -1) {
111 warnHyphenatedStyleName(name, owner);
112 } else if (badVendoredStyleNamePattern.test(name)) {
113 warnBadVendoredStyleName(name, owner);
114 } else if (badStyleValueWithSemicolonPattern.test(value)) {
115 warnStyleValueWithSemicolon(name, value, owner);
116 }
117
118 if (typeof value === 'number' && isNaN(value)) {
119 warnStyleValueIsNaN(name, value, owner);
120 }
121 };
122}
123
124/**
125 * Operations for dealing with CSS properties.
126 */
127var CSSPropertyOperations = {
128 /**
129 * Serializes a mapping of style properties for use as inline styles:
130 *
131 * > createMarkupForStyles({width: '200px', height: 0})
132 * "width:200px;height:0;"
133 *
134 * Undefined values are ignored so that declarative programming is easier.
135 * The result should be HTML-escaped before insertion into the DOM.
136 *
137 * @param {object} styles
138 * @param {ReactDOMComponent} component
139 * @return {?string}
140 */
141 createMarkupForStyles: function (styles, component) {
142 var serialized = '';
143 for (var styleName in styles) {
144 if (!styles.hasOwnProperty(styleName)) {
145 continue;
146 }
147 var isCustomProperty = styleName.indexOf('--') === 0;
148 var styleValue = styles[styleName];
149 if (process.env.NODE_ENV !== 'production') {
150 if (!isCustomProperty) {
151 warnValidStyle(styleName, styleValue, component);
152 }
153 }
154 if (styleValue != null) {
155 serialized += processStyleName(styleName) + ':';
156 serialized += dangerousStyleValue(styleName, styleValue, component, isCustomProperty) + ';';
157 }
158 }
159 return serialized || null;
160 },
161
162 /**
163 * Sets the value for multiple styles on a node. If a value is specified as
164 * '' (empty string), the corresponding style property will be unset.
165 *
166 * @param {DOMElement} node
167 * @param {object} styles
168 * @param {ReactDOMComponent} component
169 */
170 setValueForStyles: function (node, styles, component) {
171 if (process.env.NODE_ENV !== 'production') {
172 ReactInstrumentation.debugTool.onHostOperation({
173 instanceID: component._debugID,
174 type: 'update styles',
175 payload: styles
176 });
177 }
178
179 var style = node.style;
180 for (var styleName in styles) {
181 if (!styles.hasOwnProperty(styleName)) {
182 continue;
183 }
184 var isCustomProperty = styleName.indexOf('--') === 0;
185 if (process.env.NODE_ENV !== 'production') {
186 if (!isCustomProperty) {
187 warnValidStyle(styleName, styles[styleName], component);
188 }
189 }
190 var styleValue = dangerousStyleValue(styleName, styles[styleName], component, isCustomProperty);
191 if (styleName === 'float' || styleName === 'cssFloat') {
192 styleName = styleFloatAccessor;
193 }
194 if (isCustomProperty) {
195 style.setProperty(styleName, styleValue);
196 } else if (styleValue) {
197 style[styleName] = styleValue;
198 } else {
199 var expansion = hasShorthandPropertyBug && CSSProperty.shorthandPropertyExpansions[styleName];
200 if (expansion) {
201 // Shorthand property that IE8 won't like unsetting, so unset each
202 // component to placate it
203 for (var individualStyleName in expansion) {
204 style[individualStyleName] = '';
205 }
206 } else {
207 style[styleName] = '';
208 }
209 }
210 }
211 }
212};
213
214module.exports = CSSPropertyOperations;
\No newline at end of file