UNPKG

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