UNPKG

glam

Version:

inline css for your jsx

242 lines (212 loc) 6.61 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.cssLabels = cssLabels; exports.default = parse; var _flatten = require('./flatten'); var _flatten2 = _interopRequireDefault(_flatten); var _hash = require('./hash'); var _hash2 = _interopRequireDefault(_hash); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /**** labels ****/ // toggle for debug labels. // *shouldn't* have to mess with this manually // import clean from './clean'; var hasLabels = process.env.NODE_ENV !== 'production'; function cssLabels(bool) { hasLabels = !!bool; } var prefixedPseudoSelectors = { '::placeholder': ['::-webkit-input-placeholder', '::-moz-placeholder', '::-ms-input-placeholder'], ':fullscreen': [':-webkit-full-screen', ':-moz-full-screen', ':-ms-fullscreen'] }; function isSelector(key) { var possibles = [':', '.', '[', '>', ' '], found = false, ch = key.charAt(0); for (var i = 0; i < possibles.length; i++) { if (ch === possibles[i]) { found = true; break; } } return found || key.indexOf('&') >= 0; } // from https://github.com/j2css/j2c/blob/5d381c2d721d04b54fabe6a165d587247c3087cb/src/helpers.js#L28-L61 // "Tokenizes" the selectors into parts relevant for the next function. // Strings and comments are matched, but ignored afterwards. // This is not a full tokenizers. It only recognizes comas, parentheses, // strings and comments. // regexp generated by scripts/regexps.js then trimmed by hand var selectorTokenizer = /[(),]|"(?:\\.|[^"\n])*"|'(?:\\.|[^'\n])*'|\/\*[\s\S]*?\*\//g; /** * This will split a coma-separated selector list into individual selectors, * ignoring comas in strings, comments and in :pseudo-selectors(parameter, lists). * * @param {string} selector * @return {string[]} */ function splitSelector(selector) { if (selector.indexOf(',') === -1) { return [selector]; } var indices = [], res = [], inParen = 0, o; /*eslint-disable no-cond-assign*/ while (o = selectorTokenizer.exec(selector)) { /*eslint-enable no-cond-assign*/ switch (o[0]) { case '(': inParen++; break; case ')': inParen--; break; case ',': if (inParen) break; indices.push(o.index); } } for (o = indices.length; o--;) { res.unshift(selector.slice(indices[o] + 1)); selector = selector.slice(0, indices[o]); } res.unshift(selector); return res; } function joinSelectors(a, b) { var as = splitSelector(a).map(function (a) { return !(a.indexOf('&') >= 0) ? '&' + a : a; }); var bs = splitSelector(b).map(function (b) { return !(b.indexOf('&') >= 0) ? '&' + b : b; }); return bs.reduce(function (arr, b) { return arr.concat(as.map(function (a) { return b.replace(/\&/g, a); })); }, []).join(','); } function joinMediaQueries(a, b) { return a ? '@media ' + a.substring(6) + ' and ' + b.substring(6) : b; } function isMediaQuery(key) { return key.indexOf('@media') === 0; } function isSupports(key) { return key.indexOf('@supports') === 0; } function joinSupports(a, b) { return a ? '@supports ' + a.substring(9) + ' and ' + b.substring(9) : b; } // mutable! modifies dest. function construct(dest, _ref) { var _ref$selector = _ref.selector, selector = _ref$selector === undefined ? '' : _ref$selector, _ref$mq = _ref.mq, mq = _ref$mq === undefined ? '' : _ref$mq, _ref$supp = _ref.supp, supp = _ref$supp === undefined ? '' : _ref$supp, _ref$inputs = _ref.inputs, inputs = _ref$inputs === undefined ? {} : _ref$inputs; var inputArray = !Array.isArray(inputs) ? [inputs] : (0, _flatten2.default)(inputs); inputArray.filter(function (x) { return !!x; }).forEach(function (input) { var src = input; Object.keys(src || {}).forEach(function (key) { if (isSelector(key)) { // todo - regex test the string to look for prefixedpseudos if (prefixedPseudoSelectors[key]) { prefixedPseudoSelectors[key].forEach(function (p) { return construct(dest, { selector: joinSelectors(selector, p), mq: mq, supp: supp, inputs: src[key] }); }); } construct(dest, { selector: joinSelectors(selector, key), mq: mq, supp: supp, inputs: src[key] }); } else if (isMediaQuery(key)) { construct(dest, { selector: selector, mq: joinMediaQueries(mq, key), supp: supp, inputs: src[key] }); } else if (isSupports(key)) { construct(dest, { selector: selector, mq: mq, supp: joinSupports(supp, key), inputs: src[key] }); } else { var _dest = dest; if (supp) { _dest[supp] = _dest[supp] || {}; _dest = _dest[supp]; } if (mq) { _dest[mq] = _dest[mq] || {}; _dest = _dest[mq]; } if (selector) { _dest[selector] = _dest[selector] || {}; _dest = _dest[selector]; } if (key === 'label') { if (hasLabels) { // concat at root of object dest.label = dest.label.concat(src.label); } } else { _dest[key] = src[key]; } } }); }); return dest; } function groupByType(style) { // we can be sure it's not infinitely nested here var plain = void 0, selects = void 0, medias = void 0, supports = void 0; Object.keys(style).forEach(function (key) { if (key.indexOf('&') >= 0) { selects = selects || {}; selects[key] = style[key]; } else if (key.indexOf('@media') === 0) { medias = medias || {}; medias[key] = groupByType(style[key]); } else if (key.indexOf('@supports') === 0) { supports = supports || {}; supports[key] = groupByType(style[key]); } else if (key === 'label') { if (style.label.length > 0) { plain = plain || {}; plain.label = hasLabels ? style.label.join('.') : ''; } } else { plain = plain || {}; plain[key] = style[key]; } }); return { plain: plain, selects: selects, medias: medias, supports: supports }; } function parse(css) { var parsed = groupByType(construct({ label: [] }, { inputs: css })); var className = 'css-' + (0, _hash2.default)(parsed); return { className: className, parsed: parsed }; }