UNPKG

13.1 kBJavaScriptView Raw
1define('jsxstyle-utils', ['exports'], function(exports) {
2 'use strict';
3
4 var canUseDOM = !!(
5 typeof window !== 'undefined' &&
6 window.document &&
7 window.document.createElement
8 );
9 var styleElement;
10 if (
11 typeof module !== 'undefined' &&
12 module.hot &&
13 typeof module.hot.addDisposeHandler === 'function'
14 ) {
15 // gross
16 var hot = module.hot;
17 if (typeof hot.data === 'object') {
18 styleElement = hot.data.styleElement;
19 }
20 hot.addDisposeHandler(function(data) {
21 data.styleElement = styleElement;
22 });
23 }
24 if (canUseDOM && !styleElement) {
25 styleElement = document.createElement('style');
26 styleElement.type = 'text/css';
27 styleElement.appendChild(document.createTextNode('/* jsxstyle */'));
28 document.head.appendChild(styleElement);
29 }
30 function addStyleToHead(rule) {
31 if (styleElement) {
32 var sheet = styleElement.sheet;
33 try {
34 sheet.insertRule(rule, sheet.cssRules.length);
35 } catch (insertError) {
36 // insertRule will fail for rules with pseudoelements the browser doesn't support.
37 // see: https://github.com/smyte/jsxstyle/issues/75
38 if (process.env.NODE_ENV !== 'production') {
39 console.error(
40 '[jsxstyle] Could not insert rule at position ' +
41 sheet.cssRules.length +
42 ': `' +
43 rule +
44 '`'
45 );
46 }
47 }
48 }
49 }
50
51 var componentStyles = {
52 Block: { display: 'block' },
53 Box: null,
54 Col: { display: 'flex', flexDirection: 'column' },
55 Grid: { display: 'grid' },
56 Inline: { display: 'inline' },
57 InlineBlock: { display: 'inline-block' },
58 Row: { display: 'flex', flexDirection: 'row' },
59 };
60
61 /**
62 * Copyright 2013-present, Facebook, Inc.
63 * All rights reserved.
64 *
65 * This source code is licensed under the BSD-style license found in the
66 * LICENSE file in the root directory of this source tree. An additional grant
67 * of patent rights can be found in the PATENTS file in the same directory.
68 *
69 */
70 var isUnitlessNumber = {
71 animationIterationCount: true,
72 borderImageOutset: true,
73 borderImageSlice: true,
74 borderImageWidth: true,
75 boxFlex: true,
76 boxFlexGroup: true,
77 boxOrdinalGroup: true,
78 columnCount: true,
79 columns: true,
80 flex: true,
81 flexGrow: true,
82 flexNegative: true,
83 flexOrder: true,
84 flexPositive: true,
85 flexShrink: true,
86 fontWeight: true,
87 gridColumn: true,
88 gridColumnEnd: true,
89 gridColumnSpan: true,
90 gridColumnStart: true,
91 gridRow: true,
92 gridRowEnd: true,
93 gridRowSpan: true,
94 gridRowStart: true,
95 lineClamp: true,
96 lineHeight: true,
97 opacity: true,
98 order: true,
99 orphans: true,
100 tabSize: true,
101 widows: true,
102 zIndex: true,
103 zoom: true,
104 // SVG-related properties
105 fillOpacity: true,
106 floodOpacity: true,
107 stopOpacity: true,
108 strokeDasharray: true,
109 strokeDashoffset: true,
110 strokeMiterlimit: true,
111 strokeOpacity: true,
112 strokeWidth: true,
113 };
114 function prefixKey(prefix, key) {
115 return prefix + key.charAt(0).toUpperCase() + key.substring(1);
116 }
117 var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
118 Object.keys(isUnitlessNumber).forEach(function(prop) {
119 prefixes.forEach(function(prefix) {
120 isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
121 });
122 });
123 function dangerousStyleValue(name, value) {
124 var isEmpty = value == null || typeof value === 'boolean' || value === '';
125 if (isEmpty) {
126 return '';
127 }
128 if (
129 typeof value === 'number' &&
130 value !== 0 &&
131 !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])
132 ) {
133 if (value > -1 && value < 1) {
134 return Math.round(value * 1e6) / 1e4 + '%';
135 }
136 return value + 'px';
137 }
138 if (!value.toString) {
139 // values that lack a toString method on their prototype will throw a TypeError
140 // see https://github.com/smyte/jsxstyle/issues/112
141 if (process.env.NODE_ENV === 'development') {
142 console.error(
143 'Value for prop `%s` (`%o`) cannot be stringified.',
144 name,
145 value
146 );
147 }
148 return '';
149 }
150 return ('' + value).trim();
151 }
152
153 var uppercasePattern = /([A-Z])/g;
154 var msPattern = /^ms-/;
155 var hyphenateCache = {};
156 function hyphenateStyleName(styleName) {
157 if (hyphenateCache.hasOwnProperty(styleName)) {
158 return hyphenateCache[styleName];
159 }
160 var hyphenatedString = styleName
161 .replace(uppercasePattern, '-$1')
162 .toLowerCase()
163 .replace(msPattern, '-ms-');
164 hyphenateCache[styleName] = hyphenatedString;
165 return hyphenateCache[styleName];
166 }
167
168 // global flag makes subsequent calls of capRegex.test advance to the next match
169 var capRegex = /[A-Z]/g;
170 var pseudoelements = {
171 after: true,
172 before: true,
173 placeholder: true,
174 selection: true,
175 };
176 var pseudoclasses = {
177 active: true,
178 checked: true,
179 disabled: true,
180 empty: true,
181 enabled: true,
182 focus: true,
183 hover: true,
184 invalid: true,
185 required: true,
186 target: true,
187 valid: true,
188 };
189 var specialCaseProps = {
190 children: true,
191 class: true,
192 className: true,
193 component: true,
194 mediaQueries: true,
195 props: true,
196 style: true,
197 };
198 function getStyleKeysForProps(props, pretty) {
199 if (pretty === void 0) {
200 pretty = false;
201 }
202 if (typeof props !== 'object' || props === null) {
203 return null;
204 }
205 var propKeys = Object.keys(props).sort();
206 var keyCount = propKeys.length;
207 if (keyCount === 0) {
208 return null;
209 }
210 var mediaQueries = props.mediaQueries;
211 var hasMediaQueries = typeof mediaQueries === 'object';
212 var usesMediaQueries = false;
213 var styleKeyObj = {};
214 var classNameKey = '';
215 var seenMQs = {};
216 var mqSortKeys = {};
217 if (hasMediaQueries) {
218 var idx = -1;
219 for (var k in mediaQueries) {
220 mqSortKeys[k] = '@' + (1000 + ++idx);
221 }
222 }
223 for (var idx = -1; ++idx < keyCount; ) {
224 var originalPropName = propKeys[idx];
225 if (
226 specialCaseProps.hasOwnProperty(originalPropName) ||
227 !props.hasOwnProperty(originalPropName)
228 ) {
229 continue;
230 }
231 var propName = originalPropName;
232 var propSansMQ = void 0;
233 var pseudoelement = void 0;
234 var pseudoclass = void 0;
235 var mqKey = void 0;
236 capRegex.lastIndex = 0;
237 var splitIndex = 0;
238 var prefix =
239 capRegex.test(originalPropName) &&
240 capRegex.lastIndex > 1 &&
241 originalPropName.slice(0, capRegex.lastIndex - 1);
242 // check for media query prefix
243 if (prefix && hasMediaQueries && mediaQueries.hasOwnProperty(prefix)) {
244 usesMediaQueries = true;
245 mqKey = prefix;
246 splitIndex = capRegex.lastIndex - 1;
247 propSansMQ =
248 originalPropName[splitIndex].toLowerCase() +
249 originalPropName.slice(splitIndex + 1);
250 prefix =
251 capRegex.test(originalPropName) &&
252 propSansMQ.slice(0, capRegex.lastIndex - splitIndex - 1);
253 }
254 // check for pseudoelement prefix
255 if (prefix && pseudoelements.hasOwnProperty(prefix)) {
256 pseudoelement = prefix;
257 splitIndex = capRegex.lastIndex - 1;
258 prefix =
259 capRegex.test(originalPropName) &&
260 originalPropName[splitIndex].toLowerCase() +
261 originalPropName.slice(splitIndex + 1, capRegex.lastIndex - 1);
262 }
263 // check for pseudoclass prefix
264 if (prefix && pseudoclasses.hasOwnProperty(prefix)) {
265 pseudoclass = prefix;
266 splitIndex = capRegex.lastIndex - 1;
267 }
268 // trim prefixes off propName
269 if (splitIndex > 0) {
270 propName =
271 originalPropName[splitIndex].toLowerCase() +
272 originalPropName.slice(splitIndex + 1);
273 }
274 var styleValue = dangerousStyleValue(propName, props[originalPropName]);
275 if (styleValue === '') {
276 continue;
277 }
278 var mediaQuery = mqKey && mediaQueries[mqKey];
279 var mqSortKey = mqKey && mqSortKeys[mqKey];
280 var key =
281 '.' +
282 (mqSortKey || '') +
283 (pseudoclass ? ':' + pseudoclass : '') +
284 (pseudoelement ? '::' + pseudoelement : '');
285 if (!styleKeyObj.hasOwnProperty(key)) {
286 styleKeyObj[key] = { styles: pretty ? '\n' : '' };
287 if (mediaQuery) {
288 styleKeyObj[key].mediaQuery = mediaQuery;
289 }
290 if (pseudoclass) {
291 styleKeyObj[key].pseudoclass = pseudoclass;
292 }
293 if (pseudoelement) {
294 styleKeyObj[key].pseudoelement = pseudoelement;
295 }
296 }
297 if (mediaQuery) {
298 seenMQs[mediaQuery] = seenMQs[mediaQuery] || '';
299 seenMQs[mediaQuery] += propSansMQ + ':' + styleValue + ';';
300 } else {
301 classNameKey += originalPropName + ':' + styleValue + ';';
302 }
303 styleKeyObj[key].styles +=
304 (pretty ? ' ' : '') +
305 hyphenateStyleName(propName) +
306 (pretty ? ': ' : ':') +
307 styleValue +
308 (pretty ? ';\n' : ';');
309 }
310 // append media query key
311 if (usesMediaQueries) {
312 var mqKeys = Object.keys(seenMQs).sort();
313 for (var idx = -1, len = mqKeys.length; ++idx < len; ) {
314 var mediaQuery = mqKeys[idx];
315 classNameKey += '@' + mediaQuery + '~' + seenMQs[mediaQuery];
316 }
317 }
318 if (classNameKey === '') {
319 return null;
320 }
321 styleKeyObj.classNameKey = classNameKey;
322 return styleKeyObj;
323 }
324
325 /* tslint:disable no-bitwise */
326 // thx darksky: https://git.io/v9kWO
327 function stringHash(str) {
328 var hash = 5381;
329 var i = str.length;
330 while (i) {
331 hash = (hash * 33) ^ str.charCodeAt(--i);
332 }
333 /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
334 * integers. Since we want the results to be always positive, convert the
335 * signed int to an unsigned by doing an unsigned bitshift. */
336 return hash >>> 0;
337 }
338
339 function cannotInject() {
340 throw new Error(
341 'jsxstyle error: `injectOptions` must be called before any jsxstyle components mount.'
342 );
343 }
344 function alreadyInjected() {
345 throw new Error(
346 'jsxstyle error: `injectOptions` should be called once and only once.'
347 );
348 }
349 function getStringHash(key, props) {
350 return '_' + stringHash(key).toString(36);
351 }
352 function getStyleCache() {
353 var _classNameCache = {};
354 var getClassNameForKey = getStringHash;
355 var onInsertRule;
356 var pretty = false;
357 var styleCache = {
358 reset: function() {
359 _classNameCache = {};
360 },
361 injectOptions: function(options) {
362 if (options) {
363 if (options.getClassName) {
364 getClassNameForKey = options.getClassName;
365 }
366 if (options.onInsertRule) {
367 onInsertRule = options.onInsertRule;
368 }
369 if (options.pretty) {
370 pretty = options.pretty;
371 }
372 }
373 styleCache.injectOptions = alreadyInjected;
374 },
375 getClassName: function(props, classNameProp) {
376 styleCache.injectOptions = cannotInject;
377 var styleObj = getStyleKeysForProps(props, pretty);
378 if (typeof styleObj !== 'object' || styleObj === null) {
379 return classNameProp || null;
380 }
381 var key = styleObj.classNameKey;
382 if (key && !_classNameCache.hasOwnProperty(key)) {
383 _classNameCache[key] = getClassNameForKey(key, props);
384 delete styleObj.classNameKey;
385 Object.keys(styleObj)
386 .sort()
387 .forEach(function(k) {
388 var selector = '.' + _classNameCache[key];
389 // prettier-ignore
390 var _a = styleObj[k], pseudoclass = _a.pseudoclass, pseudoelement = _a.pseudoelement, mediaQuery = _a.mediaQuery, styles = _a.styles;
391 var rule =
392 selector +
393 (pseudoclass ? ':' + pseudoclass : '') +
394 (pseudoelement ? '::' + pseudoelement : '') +
395 (' {' + styles + '}');
396 if (mediaQuery) {
397 rule = '@media ' + mediaQuery + ' { ' + rule + ' }';
398 }
399 if (
400 onInsertRule &&
401 // if the function returns false, bail.
402 onInsertRule(rule, props) === false
403 ) {
404 return;
405 }
406 addStyleToHead(rule);
407 });
408 }
409 return _classNameCache[key] && classNameProp
410 ? classNameProp + ' ' + _classNameCache[key]
411 : _classNameCache[key] || classNameProp || null;
412 },
413 };
414 return styleCache;
415 }
416
417 exports.addStyleToHead = addStyleToHead;
418 exports.componentStyles = componentStyles;
419 exports.dangerousStyleValue = dangerousStyleValue;
420 exports.getStyleCache = getStyleCache;
421 exports.getStyleKeysForProps = getStyleKeysForProps;
422 exports.pseudoelements = pseudoelements;
423 exports.pseudoclasses = pseudoclasses;
424 exports.hyphenateStyleName = hyphenateStyleName;
425 exports.stringHash = stringHash;
426
427 Object.defineProperty(exports, '__esModule', { value: true });
428});