UNPKG

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