Last active
March 5, 2018 14:58
-
-
Save tusbar/2b59d321d9ab4be29582e6c2795fd8ab to your computer and use it in GitHub Desktop.
styled-jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var GLOBAL_ATTRIBUTE = exports.GLOBAL_ATTRIBUTE = 'global'; | |
var STYLE_ATTRIBUTE = exports.STYLE_ATTRIBUTE = 'jsx'; | |
var STYLE_COMPONENT = exports.STYLE_COMPONENT = '_JSXStyle'; | |
var STYLE_COMPONENT_CSS = exports.STYLE_COMPONENT_CSS = 'css'; | |
var STYLE_COMPONENT_DYNAMIC = exports.STYLE_COMPONENT_DYNAMIC = 'dynamic'; | |
var STYLE_COMPONENT_ID = exports.STYLE_COMPONENT_ID = 'styleId'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
exports.booleanOption = exports.processCss = exports.combinePlugins = exports.addSourceMaps = exports.makeSourceMapGenerator = exports.makeStyledJsxTag = exports.cssToBabelType = exports.templateLiteralFromPreprocessedCss = exports.computeClassNames = exports.getJSXStyleInfo = exports.validateExternalExpressions = exports.isDynamic = exports.validateExpressionVisitor = exports.findStyles = exports.isStyledJsx = exports.isGlobalEl = exports.getScope = exports.addClassName = exports.hashString = undefined; | |
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | |
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
var _babelTypes = require('babel-types'); | |
var t = _interopRequireWildcard(_babelTypes); | |
var _stringHash = require('string-hash'); | |
var _stringHash2 = _interopRequireDefault(_stringHash); | |
var _sourceMap = require('source-map'); | |
var _convertSourceMap = require('convert-source-map'); | |
var _convertSourceMap2 = _interopRequireDefault(_convertSourceMap); | |
var _styleTransform = require('./lib/style-transform'); | |
var _styleTransform2 = _interopRequireDefault(_styleTransform); | |
var _constants = require('./_constants'); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
var concat = function concat(a, b) { | |
return t.binaryExpression('+', a, b); | |
}; | |
var and = function and(a, b) { | |
return t.logicalExpression('&&', a, b); | |
}; | |
var or = function or(a, b) { | |
return t.logicalExpression('||', a, b); | |
}; | |
var joinSpreads = function joinSpreads(spreads) { | |
return spreads.reduce(function (acc, curr) { | |
return or(acc, curr); | |
}); | |
}; | |
var hashString = exports.hashString = function hashString(str) { | |
return String((0, _stringHash2.default)(str)); | |
}; | |
var addClassName = exports.addClassName = function addClassName(path, jsxId) { | |
var jsxIdWithSpace = concat(jsxId, t.stringLiteral(' ')); | |
var attributes = path.get('attributes'); | |
var spreads = []; | |
var className = null; | |
// Find className and collect spreads | |
for (var i = attributes.length - 1, attr; attr = attributes[i]; i--) { | |
var node = attr.node; | |
if (t.isJSXSpreadAttribute(attr)) { | |
var name = node.argument.name; | |
var attrNameDotClassName = t.memberExpression(t.isMemberExpression(node.argument) ? node.argument : t.identifier(name), t.identifier('className')); | |
spreads.push( | |
// `${name}.className != null && ${name}.className` | |
and(t.binaryExpression('!=', attrNameDotClassName, t.nullLiteral()), attrNameDotClassName)); | |
continue; | |
} | |
if (t.isJSXAttribute(attr) && node.name.name === 'className') { | |
className = attributes[i]; | |
// found className break the loop | |
break; | |
} | |
} | |
if (className) { | |
var newClassName = className.node.value.expression || className.node.value; | |
newClassName = t.isStringLiteral(newClassName) || t.isTemplateLiteral(newClassName) ? newClassName : or(newClassName, t.stringLiteral('')); | |
className.remove(); | |
className = t.jSXExpressionContainer(spreads.length === 0 ? concat(jsxIdWithSpace, newClassName) : concat(jsxIdWithSpace, or(joinSpreads(spreads), newClassName))); | |
} else { | |
className = t.jSXExpressionContainer(spreads.length === 0 ? jsxId : concat(jsxIdWithSpace, or(joinSpreads(spreads), t.stringLiteral('')))); | |
} | |
path.node.attributes.push(t.jSXAttribute(t.jSXIdentifier('className'), className)); | |
}; | |
var getScope = exports.getScope = function getScope(path) { | |
return (path.findParent(function (path) { | |
return path.isFunctionDeclaration() || path.isArrowFunctionExpression() || path.isClassMethod(); | |
}) || path).scope; | |
}; | |
var isGlobalEl = exports.isGlobalEl = function isGlobalEl(el) { | |
return el.attributes.some(function (_ref) { | |
var name = _ref.name; | |
return name && name.name === _constants.GLOBAL_ATTRIBUTE; | |
}); | |
}; | |
var isStyledJsx = exports.isStyledJsx = function isStyledJsx(_ref2) { | |
var el = _ref2.node; | |
return t.isJSXElement(el) && el.openingElement.name.name === 'style' && el.openingElement.attributes.some(function (attr) { | |
return attr.name.name === _constants.STYLE_ATTRIBUTE; | |
}); | |
}; | |
var findStyles = exports.findStyles = function findStyles(path) { | |
if (isStyledJsx(path)) { | |
var node = path.node; | |
return isGlobalEl(node.openingElement) ? [path] : []; | |
} | |
return path.get('children').filter(isStyledJsx); | |
}; | |
// The following visitor ensures that MemberExpressions and Identifiers | |
// are not in the scope of the current Method (render) or function (Component). | |
var validateExpressionVisitor = exports.validateExpressionVisitor = { | |
MemberExpression: function MemberExpression(path, scope) { | |
var node = path.node; | |
if (t.isIdentifier(node.property) && t.isThisExpression(node.object) && (node.property.name === 'props' || node.property.name === 'state' || node.property.name === 'context') || t.isIdentifier(node.object) && scope.hasOwnBinding(node.object.name)) { | |
throw path.buildCodeFrameError('Expected a constant ' + 'as part of the template literal expression ' + '(eg: <style jsx>{`p { color: ${myColor}`}</style>), ' + ('but got a MemberExpression: this.' + node.property.name)); | |
} | |
}, | |
Identifier: function Identifier(path, scope) { | |
var name = path.node.name; | |
if (t.isMemberExpression(path.parentPath) && scope.hasOwnBinding(name)) { | |
return; | |
} | |
var targetScope = path.scope; | |
var isDynamicBinding = false; | |
// Traversing scope chain in order to find current variable. | |
// If variable has no parent scope and it's `const` then we can interp. it | |
// as static in order to optimize styles. | |
// `let` and `var` can be changed during runtime. | |
while (targetScope) { | |
if (targetScope.hasOwnBinding(name)) { | |
var binding = targetScope.bindings[name]; | |
isDynamicBinding = binding.scope.parent !== null || binding.kind !== 'const'; | |
break; | |
} | |
targetScope = targetScope.parent; | |
} | |
if (isDynamicBinding) { | |
throw path.buildCodeFrameError('Expected `' + name + '` ' + 'to not come from the closest scope.\n' + 'Styled JSX encourages the use of constants ' + 'instead of `props` or dynamic values ' + 'which are better set via inline styles or `className` toggling. ' + 'See https://github.com/zeit/styled-jsx#dynamic-styles'); | |
} | |
} | |
}; | |
// Use `validateExpressionVisitor` to determine whether the `expr`ession has dynamic values. | |
var isDynamic = exports.isDynamic = function isDynamic(expr, scope) { | |
try { | |
expr.traverse(validateExpressionVisitor, scope); | |
return false; | |
} catch (err) {} | |
return true; | |
}; | |
var validateExternalExpressionsVisitor = { | |
Identifier: function Identifier(path) { | |
if (t.isMemberExpression(path.parentPath)) { | |
return; | |
} | |
var name = path.node.name; | |
if (!path.scope.hasBinding(name)) { | |
throw path.buildCodeFrameError(path.getSource()); | |
} | |
}, | |
MemberExpression: function MemberExpression(path) { | |
var node = path.node; | |
if (!t.isIdentifier(node.object)) { | |
return; | |
} | |
if (!path.scope.hasBinding(node.object.name)) { | |
throw path.buildCodeFrameError(path.getSource()); | |
} | |
}, | |
ThisExpression: function ThisExpression(path) { | |
throw new Error(path.parentPath.getSource()); | |
} | |
}; | |
var validateExternalExpressions = exports.validateExternalExpressions = function validateExternalExpressions(path) { | |
try { | |
path.traverse(validateExternalExpressionsVisitor); | |
} catch (err) { | |
throw path.buildCodeFrameError('\n Found an `undefined` or invalid value in your styles: `' + err.message + '`.\n\n If you are trying to use dynamic styles in external files this is unfortunately not possible yet.\n Please put the dynamic parts alongside the component. E.g.\n\n <button>\n <style jsx>{externalStylesReference}</style>\n <style jsx>{`\n button { background-color: ${' + err.message + '} }\n `}</style>\n </button>\n '); | |
} | |
}; | |
var getJSXStyleInfo = exports.getJSXStyleInfo = function getJSXStyleInfo(expr, scope) { | |
var node = expr.node; | |
var location = node.loc; | |
// Assume string literal | |
if (t.isStringLiteral(node)) { | |
return { | |
hash: hashString(node.value), | |
css: node.value, | |
expressions: [], | |
dynamic: false, | |
location: location | |
}; | |
} | |
// Simple template literal without expressions | |
if (node.expressions.length === 0) { | |
return { | |
hash: hashString(node.quasis[0].value.cooked), | |
css: node.quasis[0].value.cooked, | |
expressions: [], | |
dynamic: false, | |
location: location | |
}; | |
} | |
// Special treatment for template literals that contain expressions: | |
// | |
// Expressions are replaced with a placeholder | |
// so that the CSS compiler can parse and | |
// transform the css source string | |
// without having to know about js literal expressions. | |
// Later expressions are restored. | |
// | |
// e.g. | |
// p { color: ${myConstant}; } | |
// becomes | |
// p { color: %%styled-jsx-placeholder-${id}%%; } | |
var quasis = node.quasis, | |
expressions = node.expressions; | |
var hash = hashString(expr.getSource().slice(1, -1)); | |
var dynamic = scope ? isDynamic(expr, scope) : false; | |
var css = quasis.reduce(function (css, quasi, index) { | |
return '' + css + quasi.value.cooked + (quasis.length === index + 1 ? '' : '%%styled-jsx-placeholder-' + index + '%%'); | |
}, ''); | |
return { | |
hash: hash, | |
css: css, | |
expressions: expressions, | |
dynamic: dynamic, | |
location: location | |
}; | |
}; | |
var computeClassNames = exports.computeClassNames = function computeClassNames(styles, externalJsxId) { | |
if (styles.length === 0) { | |
return { | |
className: externalJsxId | |
}; | |
} | |
var hashes = styles.reduce(function (acc, styles) { | |
if (styles.dynamic === false) { | |
acc.static.push(styles.hash); | |
} else { | |
acc.dynamic.push(styles); | |
} | |
return acc; | |
}, { | |
static: [], | |
dynamic: [] | |
}); | |
var staticClassName = 'jsx-' + hashString(hashes.static.join(',')); | |
// Static and optionally external classes. E.g. | |
// '[jsx-externalClasses] jsx-staticClasses' | |
if (hashes.dynamic.length === 0) { | |
return { | |
staticClassName: staticClassName, | |
className: externalJsxId ? concat(t.stringLiteral(staticClassName + ' '), externalJsxId) : t.stringLiteral(staticClassName) | |
}; | |
} | |
// _JSXStyle.dynamic([ ['1234', [props.foo, bar, fn(props)]], ... ]) | |
var dynamic = t.callExpression( | |
// Callee: _JSXStyle.dynamic | |
t.memberExpression(t.identifier(_constants.STYLE_COMPONENT), t.identifier('dynamic')), | |
// Arguments | |
[t.arrayExpression(hashes.dynamic.map(function (styles) { | |
return t.arrayExpression([t.stringLiteral(hashString(styles.hash + staticClassName)), t.arrayExpression(styles.expressions)]); | |
}))]); | |
// Dynamic and optionally external classes. E.g. | |
// '[jsx-externalClasses] ' + _JSXStyle.dynamic([ ['1234', [props.foo, bar, fn(props)]], ... ]) | |
if (hashes.static.length === 0) { | |
return { | |
staticClassName: staticClassName, | |
className: externalJsxId ? concat(concat(externalJsxId, t.stringLiteral(' ')), dynamic) : dynamic | |
}; | |
} | |
// Static, dynamic and optionally external classes. E.g. | |
// '[jsx-externalClasses] jsx-staticClasses ' + _JSXStyle.dynamic([ ['5678', [props.foo, bar, fn(props)]], ... ]) | |
return { | |
staticClassName: staticClassName, | |
className: externalJsxId ? concat(concat(externalJsxId, t.stringLiteral(' ' + staticClassName + ' ')), dynamic) : concat(t.stringLiteral(staticClassName + ' '), dynamic) | |
}; | |
}; | |
var templateLiteralFromPreprocessedCss = exports.templateLiteralFromPreprocessedCss = function templateLiteralFromPreprocessedCss(css, expressions) { | |
var quasis = []; | |
var finalExpressions = []; | |
var parts = css.split(/(?:%%styled-jsx-placeholder-(\d+)%%)/g); | |
if (parts.length === 1) { | |
return t.stringLiteral(css); | |
} | |
parts.forEach(function (part, index) { | |
if (index % 2 > 0) { | |
// This is necessary because, after preprocessing, declarations might have been alterate. | |
// eg. properties are auto prefixed and therefore expressions need to match. | |
finalExpressions.push(expressions[part]); | |
} else { | |
quasis.push(part); | |
} | |
}); | |
return t.templateLiteral(quasis.map(function (quasi, index) { | |
return t.templateElement({ | |
raw: quasi, | |
cooked: quasi | |
}, quasis.length === index + 1); | |
}), finalExpressions); | |
}; | |
var cssToBabelType = exports.cssToBabelType = function cssToBabelType(css) { | |
if (typeof css === 'string') { | |
return t.stringLiteral(css); | |
} else if (Array.isArray(css)) { | |
return t.arrayExpression(css); | |
} | |
return css; | |
}; | |
var makeStyledJsxTag = exports.makeStyledJsxTag = function makeStyledJsxTag(id, transformedCss) { | |
var expressions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; | |
var css = cssToBabelType(transformedCss); | |
var attributes = [t.jSXAttribute(t.jSXIdentifier(_constants.STYLE_COMPONENT_ID), t.jSXExpressionContainer(typeof id === 'string' ? t.stringLiteral(id) : id)), t.jSXAttribute(t.jSXIdentifier(_constants.STYLE_COMPONENT_CSS), t.jSXExpressionContainer(css))]; | |
if (expressions.length > 0) { | |
attributes.push(t.jSXAttribute(t.jSXIdentifier(_constants.STYLE_COMPONENT_DYNAMIC), t.jSXExpressionContainer(t.arrayExpression(expressions)))); | |
} | |
return t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier(_constants.STYLE_COMPONENT), attributes, true), null, []); | |
}; | |
var makeSourceMapGenerator = exports.makeSourceMapGenerator = function makeSourceMapGenerator(file) { | |
var filename = file.opts.sourceFileName; | |
var generator = new _sourceMap.SourceMapGenerator({ | |
file: filename, | |
sourceRoot: file.opts.sourceRoot | |
}); | |
generator.setSourceContent(filename, file.code); | |
return generator; | |
}; | |
var addSourceMaps = exports.addSourceMaps = function addSourceMaps(code, generator, filename) { | |
var sourceMaps = [_convertSourceMap2.default.fromObject(generator).toComment({ multiline: true }), '/*@ sourceURL=' + filename + ' */']; | |
if (Array.isArray(code)) { | |
return code.concat(sourceMaps); | |
} | |
return [code].concat(sourceMaps).join('\n'); | |
}; | |
var combinePlugins = exports.combinePlugins = function combinePlugins(plugins) { | |
if (!plugins) { | |
return function (css) { | |
return css; | |
}; | |
} | |
if (!Array.isArray(plugins) || plugins.some(function (p) { | |
return !Array.isArray(p) && typeof p !== 'string'; | |
})) { | |
throw new Error('`plugins` must be an array of plugins names (string) or an array `[plugin-name, {options}]`'); | |
} | |
return plugins.map(function (plugin, i) { | |
var options = {}; | |
if (Array.isArray(plugin)) { | |
options = plugin[1] || {}; | |
plugin = plugin[0]; | |
if (Object.prototype.hasOwnProperty.call(options, 'babel')) { | |
throw new Error('\n Error while trying to register the styled-jsx plugin: ' + plugin + '\n The option name `babel` is reserved.\n '); | |
} | |
} | |
// eslint-disable-next-line import/no-dynamic-require | |
var p = require(plugin); | |
if (p.default) { | |
p = p.default; | |
} | |
var type = typeof p === 'undefined' ? 'undefined' : _typeof(p); | |
if (type !== 'function') { | |
throw new Error('Expected plugin ' + plugins[i] + ' to be a function but instead got ' + type); | |
} | |
return { | |
plugin: p, | |
options: options | |
}; | |
}).reduce(function (previous, _ref3) { | |
var plugin = _ref3.plugin, | |
options = _ref3.options; | |
return function (css, babelOptions) { | |
return plugin(previous ? previous(css, babelOptions) : css, _extends({}, options, { | |
babel: babelOptions | |
})); | |
}; | |
}, null); | |
}; | |
var getPrefix = function getPrefix(isDynamic, id) { | |
return isDynamic ? '.__jsx-style-dynamic-selector' : '.' + id; | |
}; | |
var processCss = exports.processCss = function processCss(stylesInfo, options) { | |
var hash = stylesInfo.hash, | |
css = stylesInfo.css, | |
expressions = stylesInfo.expressions, | |
dynamic = stylesInfo.dynamic, | |
location = stylesInfo.location, | |
fileInfo = stylesInfo.fileInfo, | |
isGlobal = stylesInfo.isGlobal, | |
plugins = stylesInfo.plugins, | |
vendorPrefixes = stylesInfo.vendorPrefixes; | |
var staticClassName = stylesInfo.staticClassName || 'jsx-' + hashString(hash); | |
var splitRules = options.splitRules; | |
var useSourceMaps = Boolean(fileInfo.sourceMaps) && !splitRules; | |
var pluginsOptions = { | |
location: { | |
start: _extends({}, location.start), | |
end: _extends({}, location.end) | |
}, | |
vendorPrefixes: vendorPrefixes, | |
sourceMaps: useSourceMaps, | |
isGlobal: isGlobal, | |
filename: fileInfo.filename | |
}; | |
var transformedCss = void 0; | |
if (useSourceMaps) { | |
var generator = makeSourceMapGenerator(fileInfo.file); | |
var filename = fileInfo.sourceFileName; | |
transformedCss = addSourceMaps((0, _styleTransform2.default)(isGlobal ? '' : getPrefix(dynamic, staticClassName), plugins(css, pluginsOptions), { | |
generator: generator, | |
offset: location.start, | |
filename: filename, | |
splitRules: splitRules, | |
vendorPrefixes: vendorPrefixes | |
}), generator, filename); | |
} else { | |
transformedCss = (0, _styleTransform2.default)(isGlobal ? '' : getPrefix(dynamic, staticClassName), plugins(css, pluginsOptions), { splitRules: splitRules, vendorPrefixes: vendorPrefixes }); | |
} | |
if (expressions.length > 0) { | |
if (typeof transformedCss === 'string') { | |
transformedCss = templateLiteralFromPreprocessedCss(transformedCss, expressions); | |
} else { | |
transformedCss = transformedCss.map(function (transformedCss) { | |
return templateLiteralFromPreprocessedCss(transformedCss, expressions); | |
}); | |
} | |
} else if (Array.isArray(transformedCss)) { | |
transformedCss = transformedCss.map(function (transformedCss) { | |
return t.stringLiteral(transformedCss); | |
}); | |
} | |
return { | |
hash: dynamic ? hashString(hash + staticClassName) : hashString(hash), | |
css: transformedCss, | |
expressions: dynamic && expressions | |
}; | |
}; | |
var booleanOption = exports.booleanOption = function booleanOption(opts) { | |
var ret = void 0; | |
opts.some(function (opt) { | |
if (typeof opt === 'boolean') { | |
ret = opt; | |
return true; | |
} | |
return false; | |
}); | |
return ret; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
exports.visitor = undefined; | |
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | |
exports.default = function () { | |
return _extends({ | |
Program: function Program(path, state) { | |
var vendorPrefix = (0, _utils.booleanOption)([state.opts.vendorPrefix, state.file.opts.vendorPrefix]); | |
state.opts.vendorPrefix = typeof vendorPrefix === 'boolean' ? vendorPrefix : true; | |
var sourceMaps = (0, _utils.booleanOption)([state.opts.sourceMaps, state.file.opts.sourceMaps]); | |
state.opts.sourceMaps = Boolean(sourceMaps); | |
if (!state.plugins) { | |
var _state$opts2 = state.opts, | |
_sourceMaps = _state$opts2.sourceMaps, | |
_vendorPrefix = _state$opts2.vendorPrefix; | |
state.plugins = (0, _utils.combinePlugins)(state.opts.plugins, { | |
sourceMaps: _sourceMaps || state.file.opts.sourceMaps, | |
vendorPrefix: typeof _vendorPrefix === 'boolean' ? _vendorPrefix : true | |
}); | |
} | |
} | |
}, visitor); | |
}; | |
var _babelTypes = require('babel-types'); | |
var t = _interopRequireWildcard(_babelTypes); | |
var _utils = require('./_utils'); | |
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
var isModuleExports = t.buildMatchMemberExpression('module.exports'); | |
function processTaggedTemplateExpression(_ref) { | |
var path = _ref.path, | |
fileInfo = _ref.fileInfo, | |
splitRules = _ref.splitRules, | |
plugins = _ref.plugins, | |
vendorPrefix = _ref.vendorPrefix; | |
var templateLiteral = path.get('quasi'); | |
// Check whether there are undefined references or references to this.something (e.g. props or state) | |
(0, _utils.validateExternalExpressions)(templateLiteral); | |
var stylesInfo = (0, _utils.getJSXStyleInfo)(templateLiteral); | |
var globalStyles = (0, _utils.processCss)(_extends({}, stylesInfo, { | |
hash: stylesInfo.hash + '0', | |
fileInfo: fileInfo, | |
isGlobal: true, | |
plugins: plugins, | |
vendorPrefix: vendorPrefix | |
}), { splitRules: splitRules }); | |
var scopedStyles = (0, _utils.processCss)(_extends({}, stylesInfo, { | |
hash: stylesInfo.hash + '1', | |
fileInfo: fileInfo, | |
isGlobal: false, | |
plugins: plugins, | |
vendorPrefix: vendorPrefix | |
}), { splitRules: splitRules }); | |
var id = path.parentPath.node.id; | |
var baseExportName = id ? id.name : 'default'; | |
var parentPath = baseExportName === 'default' ? path.parentPath : path.findParent(function (path) { | |
return path.isVariableDeclaration() || path.isAssignmentExpression() && isModuleExports(path.get('left').node); | |
}); | |
if (baseExportName !== 'default' && !parentPath.parentPath.isProgram()) { | |
parentPath = parentPath.parentPath; | |
} | |
var hashesAndScoped = { | |
hash: globalStyles.hash, | |
scoped: (0, _utils.cssToBabelType)(scopedStyles.css), | |
scopedHash: scopedStyles.hash | |
}; | |
var globalCss = (0, _utils.cssToBabelType)(globalStyles.css); | |
// default exports | |
if (baseExportName === 'default') { | |
var defaultExportIdentifier = path.scope.generateUidIdentifier('defaultExport'); | |
parentPath.insertBefore(t.variableDeclaration('const', [t.variableDeclarator(defaultExportIdentifier, t.isArrayExpression(globalCss) ? globalCss : t.newExpression(t.identifier('String'), [globalCss]))])); | |
parentPath.insertBefore(makeHashesAndScopedCssPaths(defaultExportIdentifier, hashesAndScoped)); | |
path.replaceWith(defaultExportIdentifier); | |
return; | |
} | |
// named exports | |
parentPath.insertAfter(makeHashesAndScopedCssPaths(t.identifier(baseExportName), hashesAndScoped)); | |
path.replaceWith(t.isArrayExpression(globalCss) ? globalCss : t.newExpression(t.identifier('String'), [globalCss])); | |
} | |
function makeHashesAndScopedCssPaths(exportIdentifier, data) { | |
return Object.keys(data).map(function (key) { | |
var value = typeof data[key] === 'string' ? t.stringLiteral(data[key]) : data[key]; | |
return t.expressionStatement(t.assignmentExpression('=', t.memberExpression(exportIdentifier, t.identifier('__' + key)), value)); | |
}); | |
} | |
var visitor = exports.visitor = { | |
ImportDeclaration: function ImportDeclaration(path, state) { | |
if (path.node.source.value !== 'styled-jsx/css') { | |
return; | |
} | |
var tagName = path.node.specifiers[0].local.name; | |
var binding = path.scope.getBinding(tagName); | |
if (!binding || !Array.isArray(binding.referencePaths)) { | |
return; | |
} | |
var taggedTemplateExpressions = binding.referencePaths.map(function (ref) { | |
return ref.parentPath; | |
}).filter(function (path) { | |
return path.isTaggedTemplateExpression(); | |
}); | |
if (taggedTemplateExpressions.length === 0) { | |
return; | |
} | |
var _state$opts = state.opts, | |
vendorPrefix = _state$opts.vendorPrefix, | |
sourceMaps = _state$opts.sourceMaps; | |
taggedTemplateExpressions.forEach(function (path) { | |
processTaggedTemplateExpression({ | |
path: path, | |
fileInfo: { | |
file: state.file, | |
sourceFileName: state.file.opts.sourceFileName, | |
sourceMaps: sourceMaps | |
}, | |
splitRules: typeof state.opts.optimizeForSpeed === 'boolean' ? state.opts.optimizeForSpeed : process.env.NODE_ENV === 'production', | |
plugins: state.plugins, | |
vendorPrefix: vendorPrefix | |
}); | |
}); | |
// Finally remove the import | |
path.remove(); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | |
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // Packages | |
exports.default = function (_ref) { | |
var t = _ref.types; | |
return { | |
inherits: _babelPluginSyntaxJsx2.default, | |
visitor: _extends({ | |
JSXOpeningElement: function JSXOpeningElement(path, state) { | |
var el = path.node; | |
var _ref2 = el.name || {}, | |
name = _ref2.name; | |
if (!state.hasJSXStyle) { | |
return; | |
} | |
if (state.ignoreClosing === null) { | |
// We keep a counter of elements inside so that we | |
// can keep track of when we exit the parent to reset state | |
// note: if we wished to add an option to turn off | |
// selectors to reach parent elements, it would suffice to | |
// set this to `1` and do an early return instead | |
state.ignoreClosing = 0; | |
} | |
if (name && name !== 'style' && name !== _constants.STYLE_COMPONENT && name.charAt(0) !== name.charAt(0).toUpperCase()) { | |
if (state.className) { | |
(0, _utils.addClassName)(path, state.className); | |
} | |
} | |
state.ignoreClosing++; | |
// Next visit will be: JSXElement exit() | |
}, | |
JSXElement: { | |
enter: function enter(path, state) { | |
if (state.hasJSXStyle !== null) { | |
return; | |
} | |
var styles = (0, _utils.findStyles)(path); | |
if (styles.length === 0) { | |
return; | |
} | |
state.styles = []; | |
state.externalStyles = []; | |
var scope = (0, _utils.getScope)(path); | |
var _iteratorNormalCompletion = true; | |
var _didIteratorError = false; | |
var _iteratorError = undefined; | |
try { | |
for (var _iterator = styles[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | |
var style = _step.value; | |
// Compute children excluding whitespace | |
var children = style.get('children').filter(function (c) { | |
return t.isJSXExpressionContainer(c.node) || | |
// Ignore whitespace around the expression container | |
t.isJSXText(c.node) && c.node.value.trim() !== ''; | |
}); | |
if (children.length !== 1) { | |
throw path.buildCodeFrameError('Expected one child under ' + ('JSX Style tag, but got ' + children.length + ' ') + '(eg: <style jsx>{`hi`}</style>)'); | |
} | |
var child = children[0]; | |
if (!t.isJSXExpressionContainer(child)) { | |
throw path.buildCodeFrameError('Expected a child of ' + 'type JSXExpressionContainer under JSX Style tag ' + ('(eg: <style jsx>{`hi`}</style>), got ' + child.type)); | |
} | |
var expression = child.get('expression'); | |
if (t.isIdentifier(expression)) { | |
var idName = expression.node.name; | |
if (expression.scope.hasBinding(idName)) { | |
var externalStylesIdentifier = t.identifier(idName); | |
var isGlobal = (0, _utils.isGlobalEl)(style.get('openingElement').node); | |
state.externalStyles.push([t.memberExpression(externalStylesIdentifier, t.identifier(isGlobal ? '__hash' : '__scopedHash')), externalStylesIdentifier, isGlobal]); | |
continue; | |
} | |
throw path.buildCodeFrameError('The Identifier ' + ('`' + expression.getSource() + '` is either `undefined` or ') + 'it is not an external StyleSheet reference i.e. ' + 'it doesn\'t come from an `import` or `require` statement'); | |
} | |
if (!t.isTemplateLiteral(expression) && !t.isStringLiteral(expression)) { | |
throw path.buildCodeFrameError('Expected a template ' + 'literal or String literal as the child of the ' + 'JSX Style tag (eg: <style jsx>{`some css`}</style>),' + (' but got ' + expression.type)); | |
} | |
state.styles.push((0, _utils.getJSXStyleInfo)(expression, scope)); | |
} | |
} catch (err) { | |
_didIteratorError = true; | |
_iteratorError = err; | |
} finally { | |
try { | |
if (!_iteratorNormalCompletion && _iterator.return) { | |
_iterator.return(); | |
} | |
} finally { | |
if (_didIteratorError) { | |
throw _iteratorError; | |
} | |
} | |
} | |
var externalJsxId = void 0; | |
if (state.externalStyles.length > 0) { | |
var expressions = state.externalStyles | |
// Remove globals | |
.filter(function (s) { | |
return !s[2]; | |
}).map(function (s) { | |
return s[0]; | |
}); | |
var expressionsLength = expressions.length; | |
if (expressionsLength === 0) { | |
externalJsxId = null; | |
} else { | |
// Construct a template literal of this form: | |
// `jsx-${styles.__scopedHash} jsx-${otherStyles.__scopedHash}` | |
externalJsxId = t.templateLiteral([t.templateElement({ raw: 'jsx-', cooked: 'jsx-' })].concat(_toConsumableArray([].concat(_toConsumableArray(new Array(expressionsLength - 1))).map(function () { | |
return t.templateElement({ raw: ' jsx-', cooked: ' jsx-' }); | |
})), [t.templateElement({ raw: '', cooked: '' }, true)]), expressions); | |
} | |
} | |
if (state.styles.length > 0 || externalJsxId) { | |
var _computeClassNames = (0, _utils.computeClassNames)(state.styles, externalJsxId), | |
staticClassName = _computeClassNames.staticClassName, | |
className = _computeClassNames.className; | |
state.className = className; | |
state.staticClassName = staticClassName; | |
} | |
state.hasJSXStyle = true; | |
state.file.hasJSXStyle = true; | |
// Next visit will be: JSXOpeningElement | |
}, | |
exit: function exit(path, state) { | |
var isGlobal = (0, _utils.isGlobalEl)(path.node.openingElement); | |
if (state.hasJSXStyle && ! --state.ignoreClosing && !isGlobal) { | |
state.hasJSXStyle = null; | |
state.className = null; | |
state.externalJsxId = null; | |
} | |
if (!state.hasJSXStyle || !(0, _utils.isStyledJsx)(path)) { | |
return; | |
} | |
if (state.ignoreClosing > 1) { | |
var styleTagSrc = void 0; | |
try { | |
styleTagSrc = path.getSource(); | |
} catch (err) {} | |
throw path.buildCodeFrameError('Detected nested style tag' + (styleTagSrc ? ': \n\n' + styleTagSrc + '\n\n' : ' ') + 'styled-jsx only allows style tags ' + 'to be direct descendants (children) of the outermost ' + 'JSX element i.e. the subtree root.'); | |
} | |
if (state.externalStyles.length > 0 && path.get('children').filter(function (child) { | |
if (!t.isJSXExpressionContainer(child)) { | |
return false; | |
} | |
var expression = child.get('expression'); | |
return expression && expression.isIdentifier(); | |
}).length === 1) { | |
var _state$externalStyles = state.externalStyles.shift(), | |
_state$externalStyles2 = _slicedToArray(_state$externalStyles, 3), | |
id = _state$externalStyles2[0], | |
_css = _state$externalStyles2[1], | |
_isGlobal = _state$externalStyles2[2]; | |
path.replaceWith((0, _utils.makeStyledJsxTag)(id, _isGlobal ? _css : t.memberExpression(t.identifier(_css.name), t.identifier('__scoped')))); | |
return; | |
} | |
var _state$opts = state.opts, | |
vendorPrefixes = _state$opts.vendorPrefixes, | |
sourceMaps = _state$opts.sourceMaps; | |
var stylesInfo = _extends({}, state.styles.shift(), { | |
fileInfo: { | |
file: state.file, | |
sourceFileName: state.file.opts.sourceFileName || state.file.sourceFileName, | |
sourceMaps: sourceMaps, | |
filename: state.file.opts.filename || state.file.filename | |
}, | |
staticClassName: state.staticClassName, | |
isGlobal: isGlobal, | |
plugins: state.plugins, | |
vendorPrefixes: vendorPrefixes | |
}); | |
var splitRules = typeof state.opts.optimizeForSpeed === 'boolean' ? state.opts.optimizeForSpeed : process.env.NODE_ENV === 'production'; | |
var _processCss = (0, _utils.processCss)(stylesInfo, { | |
splitRules: splitRules | |
}), | |
hash = _processCss.hash, | |
css = _processCss.css, | |
expressions = _processCss.expressions; | |
path.replaceWith((0, _utils.makeStyledJsxTag)(hash, css, expressions)); | |
} | |
}, | |
Program: { | |
enter: function enter(path, state) { | |
state.hasJSXStyle = null; | |
state.ignoreClosing = null; | |
state.file.hasJSXStyle = false; | |
var vendorPrefixes = (0, _utils.booleanOption)([state.opts.vendorPrefixes, state.file.opts.vendorPrefixes]); | |
state.opts.vendorPrefixes = typeof vendorPrefixes === 'boolean' ? vendorPrefixes : true; | |
var sourceMaps = (0, _utils.booleanOption)([state.opts.sourceMaps, state.file.opts.sourceMaps]); | |
state.opts.sourceMaps = Boolean(sourceMaps); | |
if (!state.plugins) { | |
state.plugins = (0, _utils.combinePlugins)(state.opts.plugins, { | |
sourceMaps: state.opts.sourceMaps, | |
vendorPrefixes: state.opts.vendorPrefixes | |
}); | |
} | |
}, | |
exit: function exit(_ref3, state) { | |
var node = _ref3.node, | |
scope = _ref3.scope; | |
if (!(state.file.hasJSXStyle && !scope.hasBinding(_constants.STYLE_COMPONENT))) { | |
return; | |
} | |
var importDeclaration = t.importDeclaration([t.importDefaultSpecifier(t.identifier(_constants.STYLE_COMPONENT))], t.stringLiteral('styled-jsx/style')); | |
node.body.unshift(importDeclaration); | |
} | |
} | |
}, _babelExternal.visitor) | |
}; | |
}; | |
var _babelPluginSyntaxJsx = require('babel-plugin-syntax-jsx'); | |
var _babelPluginSyntaxJsx2 = _interopRequireDefault(_babelPluginSyntaxJsx); | |
var _babelExternal = require('./babel-external'); | |
var _utils = require('./_utils'); | |
var _constants = require('./_constants'); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var Stylis = require('stylis'); | |
var stylisRuleSheet = require('stylis-rule-sheet'); | |
var stylis = new Stylis(); | |
function disableNestingPlugin() { | |
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
var context = args[0], | |
_args$ = args[3], | |
parent = _args$ === undefined ? [] : _args$, | |
line = args[4], | |
column = args[5]; | |
if (context === 2) { | |
// replace null characters and trim | |
parent = (parent[0] || '').replace(/\u0000/g, '').trim(); | |
if (parent.length > 0 && parent.charAt(0) !== '@') { | |
throw new Error('Nesting detected at ' + line + ':' + column + '. ' + 'Unfortunately nesting is not supported by styled-jsx.'); | |
} | |
} | |
} | |
var generator = void 0; | |
var filename = void 0; | |
var offset = void 0; | |
function sourceMapsPlugin() { | |
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | |
args[_key2] = arguments[_key2]; | |
} | |
var context = args[0], | |
line = args[4], | |
column = args[5], | |
length = args[6]; | |
// Pre-processed, init source map | |
if (context === -1 && generator !== undefined) { | |
generator.addMapping({ | |
generated: { | |
line: 1, | |
column: 0 | |
}, | |
source: filename, | |
original: offset | |
}); | |
return; | |
} | |
// Post-processed | |
if (context === -2 && generator !== undefined) { | |
generator = undefined; | |
offset = undefined; | |
filename = undefined; | |
return; | |
} | |
// Selector/property, update source map | |
if ((context === 1 || context === 2) && generator !== undefined) { | |
generator.addMapping({ | |
generated: { | |
line: 1, | |
column: length | |
}, | |
source: filename, | |
original: { | |
line: line + offset.line, | |
column: column + offset.column | |
} | |
}); | |
} | |
} | |
/** | |
* splitRulesPlugin | |
* Used to split a blob of css into an array of rules | |
* that can inserted via sheet.insertRule | |
*/ | |
var splitRules = []; | |
var splitRulesPlugin = stylisRuleSheet(function (rule) { | |
splitRules.push(rule); | |
}); | |
stylis.use(disableNestingPlugin); | |
stylis.use(sourceMapsPlugin); | |
stylis.use(splitRulesPlugin); | |
stylis.set({ | |
cascade: false, | |
compress: true | |
}); | |
/** | |
* Public transform function | |
* | |
* @param {String} hash | |
* @param {String} styles | |
* @param {Object} settings | |
* @return {string} | |
*/ | |
function transform(hash, styles) { | |
var settings = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | |
generator = settings.generator; | |
offset = settings.offset; | |
filename = settings.filename; | |
splitRules = []; | |
stylis.set({ | |
prefix: typeof settings.vendorPrefixes === 'boolean' ? settings.vendorPrefixes : true | |
}); | |
stylis(hash, styles); | |
if (settings.splitRules) { | |
return splitRules; | |
} | |
return splitRules.join(''); | |
} | |
module.exports = transform; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | |
/* | |
Based on Glamor's sheet | |
https://github.com/threepointone/glamor/blob/667b480d31b3721a905021b26e1290ce92ca2879/src/sheet.js | |
*/ | |
var isProd = process.env && process.env.NODE_ENV === 'production'; | |
var isString = function isString(o) { | |
return Object.prototype.toString.call(o) === '[object String]'; | |
}; | |
var StyleSheet = function () { | |
function StyleSheet() { | |
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | |
_ref$name = _ref.name, | |
name = _ref$name === undefined ? 'stylesheet' : _ref$name, | |
_ref$optimizeForSpeed = _ref.optimizeForSpeed, | |
optimizeForSpeed = _ref$optimizeForSpeed === undefined ? isProd : _ref$optimizeForSpeed, | |
_ref$isBrowser = _ref.isBrowser, | |
isBrowser = _ref$isBrowser === undefined ? typeof window !== 'undefined' : _ref$isBrowser; | |
_classCallCheck(this, StyleSheet); | |
invariant(isString(name), '`name` must be a string'); | |
this._name = name; | |
this._deletedRulePlaceholder = '#' + name + '-deleted-rule____{}'; | |
invariant(typeof optimizeForSpeed === 'boolean', '`optimizeForSpeed` must be a boolean'); | |
this._optimizeForSpeed = optimizeForSpeed; | |
this._isBrowser = isBrowser; | |
this._serverSheet = undefined; | |
this._tags = []; | |
this._injected = false; | |
this._rulesCount = 0; | |
} | |
_createClass(StyleSheet, [{ | |
key: 'setOptimizeForSpeed', | |
value: function setOptimizeForSpeed(bool) { | |
invariant(typeof bool === 'boolean', '`setOptimizeForSpeed` accepts a boolean'); | |
invariant(this._rulesCount === 0, 'optimizeForSpeed cannot be when rules have already been inserted'); | |
this.flush(); | |
this._optimizeForSpeed = bool; | |
this.inject(); | |
} | |
}, { | |
key: 'isOptimizeForSpeed', | |
value: function isOptimizeForSpeed() { | |
return this._optimizeForSpeed; | |
} | |
}, { | |
key: 'inject', | |
value: function inject() { | |
var _this = this; | |
invariant(!this._injected, 'sheet already injected'); | |
this._injected = true; | |
if (this._isBrowser && this._optimizeForSpeed) { | |
this._tags[0] = this.makeStyleTag(this._name); | |
this._optimizeForSpeed = 'insertRule' in this.getSheet(); | |
if (!this._optimizeForSpeed) { | |
if (!isProd) { | |
console.warn('StyleSheet: optimizeForSpeed mode not supported falling back to standard mode.'); // eslint-disable-line no-console | |
} | |
this.flush(); | |
this._injected = true; | |
} | |
return; | |
} | |
this._serverSheet = { | |
cssRules: [], | |
insertRule: function insertRule(rule, index) { | |
if (typeof index === 'number') { | |
_this._serverSheet.cssRules[index] = { cssText: rule }; | |
} else { | |
_this._serverSheet.cssRules.push({ cssText: rule }); | |
} | |
return index; | |
}, | |
deleteRule: function deleteRule(index) { | |
_this._serverSheet.cssRules[index] = null; | |
} | |
}; | |
} | |
}, { | |
key: 'getSheetForTag', | |
value: function getSheetForTag(tag) { | |
if (tag.sheet) { | |
return tag.sheet; | |
} | |
// this weirdness brought to you by firefox | |
for (var i = 0; i < document.styleSheets.length; i++) { | |
if (document.styleSheets[i].ownerNode === tag) { | |
return document.styleSheets[i]; | |
} | |
} | |
} | |
}, { | |
key: 'getSheet', | |
value: function getSheet() { | |
return this.getSheetForTag(this._tags[this._tags.length - 1]); | |
} | |
}, { | |
key: 'insertRule', | |
value: function insertRule(rule, index) { | |
invariant(isString(rule), '`insertRule` accepts only strings'); | |
if (!this._isBrowser) { | |
if (typeof index !== 'number') { | |
index = this._serverSheet.cssRules.length; | |
} | |
this._serverSheet.insertRule(rule, index); | |
return this._rulesCount++; | |
} | |
if (this._optimizeForSpeed) { | |
var sheet = this.getSheet(); | |
if (typeof index !== 'number') { | |
index = sheet.cssRules.length; | |
} | |
// this weirdness for perf, and chrome's weird bug | |
// https://stackoverflow.com/questions/20007992/chrome-suddenly-stopped-accepting-insertrule | |
try { | |
sheet.insertRule(rule, index); | |
} catch (err) { | |
if (!isProd) { | |
console.warn('StyleSheet: illegal rule: \n\n' + rule + '\n\nSee https://stackoverflow.com/q/20007992 for more info'); // eslint-disable-line no-console | |
} | |
return -1; | |
} | |
} else { | |
var insertionPoint = this._tags[index]; | |
this._tags.push(this.makeStyleTag(this._name, rule, insertionPoint)); | |
} | |
return this._rulesCount++; | |
} | |
}, { | |
key: 'replaceRule', | |
value: function replaceRule(index, rule) { | |
if (this._optimizeForSpeed || !this._isBrowser) { | |
var sheet = this._isBrowser ? this.getSheet() : this._serverSheet; | |
if (!rule.trim()) { | |
rule = this._deletedRulePlaceholder; | |
} | |
if (!sheet.cssRules[index]) { | |
// @TBD Should we throw an error? | |
return index; | |
} | |
sheet.deleteRule(index); | |
try { | |
sheet.insertRule(rule, index); | |
} catch (err) { | |
if (!isProd) { | |
console.warn('StyleSheet: illegal rule: \n\n' + rule + '\n\nSee https://stackoverflow.com/q/20007992 for more info'); // eslint-disable-line no-console | |
} | |
// In order to preserve the indices we insert a deleteRulePlaceholder | |
sheet.insertRule(this._deletedRulePlaceholder, index); | |
} | |
} else { | |
var tag = this._tags[index]; | |
invariant(tag, 'old rule at index `' + index + '` not found'); | |
tag.textContent = rule; | |
} | |
return index; | |
} | |
}, { | |
key: 'deleteRule', | |
value: function deleteRule(index) { | |
if (!this._isBrowser) { | |
this._serverSheet.deleteRule(index); | |
return; | |
} | |
if (this._optimizeForSpeed) { | |
this.replaceRule(index, ''); | |
} else { | |
var tag = this._tags[index]; | |
invariant(tag, 'rule at index `' + index + '` not found'); | |
tag.parentNode.removeChild(tag); | |
this._tags[index] = null; | |
} | |
} | |
}, { | |
key: 'flush', | |
value: function flush() { | |
this._injected = false; | |
this._rulesCount = 0; | |
if (this._isBrowser) { | |
this._tags.forEach(function (tag) { | |
return tag && tag.parentNode.removeChild(tag); | |
}); | |
this._tags = []; | |
} else { | |
// simpler on server | |
this._serverSheet.cssRules = []; | |
} | |
} | |
}, { | |
key: 'cssRules', | |
value: function cssRules() { | |
var _this2 = this; | |
if (!this._isBrowser) { | |
return this._serverSheet.cssRules; | |
} | |
return this._tags.reduce(function (rules, tag) { | |
if (tag) { | |
rules = rules.concat(_this2.getSheetForTag(tag).cssRules.map(function (rule) { | |
return rule.cssText === _this2._deletedRulePlaceholder ? null : rule; | |
})); | |
} else { | |
rules.push(null); | |
} | |
return rules; | |
}, []); | |
} | |
}, { | |
key: 'makeStyleTag', | |
value: function makeStyleTag(name, cssString, relativeToTag) { | |
if (cssString) { | |
invariant(isString(cssString), 'makeStyleTag acceps only strings as second parameter'); | |
} | |
var tag = document.createElement('style'); | |
tag.type = 'text/css'; | |
tag.setAttribute('data-' + name, ''); | |
if (cssString) { | |
tag.appendChild(document.createTextNode(cssString)); | |
} | |
var head = document.head || document.getElementsByTagName('head')[0]; | |
if (relativeToTag) { | |
head.insertBefore(tag, relativeToTag); | |
} else { | |
head.appendChild(tag); | |
} | |
return tag; | |
} | |
}, { | |
key: 'length', | |
get: function get() { | |
return this._rulesCount; | |
} | |
}]); | |
return StyleSheet; | |
}(); | |
exports.default = StyleSheet; | |
function invariant(condition, message) { | |
if (!condition) { | |
throw new Error('StyleSheet: ' + message + '.'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | |
exports.default = flushToReact; | |
exports.flushToHTML = flushToHTML; | |
var _react = require('react'); | |
var _react2 = _interopRequireDefault(_react); | |
var _style = require('./style'); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
function flushToReact() { | |
var mem = (0, _style.flush)(); | |
var arr = []; | |
var _iteratorNormalCompletion = true; | |
var _didIteratorError = false; | |
var _iteratorError = undefined; | |
try { | |
for (var _iterator = mem[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | |
var _ref = _step.value; | |
var _ref2 = _slicedToArray(_ref, 2); | |
var id = _ref2[0]; | |
var css = _ref2[1]; | |
arr.push(_react2.default.createElement('style', { | |
id: '__' + id, | |
// Avoid warnings upon render with a key | |
key: '__' + id, | |
dangerouslySetInnerHTML: { | |
__html: css | |
} | |
})); | |
} | |
} catch (err) { | |
_didIteratorError = true; | |
_iteratorError = err; | |
} finally { | |
try { | |
if (!_iteratorNormalCompletion && _iterator.return) { | |
_iterator.return(); | |
} | |
} finally { | |
if (_didIteratorError) { | |
throw _iteratorError; | |
} | |
} | |
} | |
return arr; | |
} | |
function flushToHTML() { | |
var mem = (0, _style.flush)(); | |
var html = ''; | |
var _iteratorNormalCompletion2 = true; | |
var _didIteratorError2 = false; | |
var _iteratorError2 = undefined; | |
try { | |
for (var _iterator2 = mem[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | |
var _ref3 = _step2.value; | |
var _ref4 = _slicedToArray(_ref3, 2); | |
var id = _ref4[0]; | |
var css = _ref4[1]; | |
html += '<style id="__' + id + '">' + css + '</style>'; | |
} | |
} catch (err) { | |
_didIteratorError2 = true; | |
_iteratorError2 = err; | |
} finally { | |
try { | |
if (!_iteratorNormalCompletion2 && _iterator2.return) { | |
_iterator2.return(); | |
} | |
} finally { | |
if (_didIteratorError2) { | |
throw _iteratorError2; | |
} | |
} | |
} | |
return html; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | |
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | |
exports.flush = flush; | |
var _react = require('react'); | |
var _stylesheetRegistry = require('./stylesheet-registry'); | |
var _stylesheetRegistry2 = _interopRequireDefault(_stylesheetRegistry); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | |
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | |
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | |
var styleSheetRegistry = new _stylesheetRegistry2.default(); | |
var JSXStyle = function (_Component) { | |
_inherits(JSXStyle, _Component); | |
function JSXStyle() { | |
_classCallCheck(this, JSXStyle); | |
return _possibleConstructorReturn(this, (JSXStyle.__proto__ || Object.getPrototypeOf(JSXStyle)).apply(this, arguments)); | |
} | |
_createClass(JSXStyle, [{ | |
key: 'componentWillMount', | |
value: function componentWillMount() { | |
styleSheetRegistry.add(this.props); | |
} | |
}, { | |
key: 'shouldComponentUpdate', | |
value: function shouldComponentUpdate(nextProps) { | |
return this.props.css !== nextProps.css; | |
} | |
// To avoid FOUC, we process new changes | |
// on `componentWillUpdate` rather than `componentDidUpdate`. | |
}, { | |
key: 'componentWillUpdate', | |
value: function componentWillUpdate(nextProps) { | |
styleSheetRegistry.update(this.props, nextProps); | |
} | |
}, { | |
key: 'componentWillUnmount', | |
value: function componentWillUnmount() { | |
styleSheetRegistry.remove(this.props); | |
} | |
}, { | |
key: 'render', | |
value: function render() { | |
return null; | |
} | |
}], [{ | |
key: 'dynamic', | |
value: function dynamic(info) { | |
return info.map(function (tagInfo) { | |
var _tagInfo = _slicedToArray(tagInfo, 2), | |
baseId = _tagInfo[0], | |
props = _tagInfo[1]; | |
return styleSheetRegistry.computeId(baseId, props); | |
}).join(' '); | |
} | |
}]); | |
return JSXStyle; | |
}(_react.Component); | |
exports.default = JSXStyle; | |
function flush() { | |
var cssRules = styleSheetRegistry.cssRules(); | |
styleSheetRegistry.flush(); | |
return new Map(cssRules); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | |
var _stringHash = require('string-hash'); | |
var _stringHash2 = _interopRequireDefault(_stringHash); | |
var _stylesheet = require('./lib/stylesheet'); | |
var _stylesheet2 = _interopRequireDefault(_stylesheet); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | |
var sanitize = function sanitize(rule) { | |
return rule.replace(/\/style/g, '\\/style'); | |
}; | |
var StyleSheetRegistry = function () { | |
function StyleSheetRegistry() { | |
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | |
_ref$styleSheet = _ref.styleSheet, | |
styleSheet = _ref$styleSheet === undefined ? null : _ref$styleSheet, | |
_ref$optimizeForSpeed = _ref.optimizeForSpeed, | |
optimizeForSpeed = _ref$optimizeForSpeed === undefined ? false : _ref$optimizeForSpeed, | |
_ref$isBrowser = _ref.isBrowser, | |
isBrowser = _ref$isBrowser === undefined ? typeof window !== 'undefined' : _ref$isBrowser; | |
_classCallCheck(this, StyleSheetRegistry); | |
this._sheet = styleSheet || new _stylesheet2.default({ | |
name: 'styled-jsx', | |
optimizeForSpeed: optimizeForSpeed | |
}); | |
this._sheet.inject(); | |
if (styleSheet && typeof optimizeForSpeed === 'boolean') { | |
this._sheet.setOptimizeForSpeed(optimizeForSpeed); | |
this._optimizeForSpeed = this._sheet.isOptimizeForSpeed(); | |
} | |
this._isBrowser = isBrowser; | |
this._fromServer = undefined; | |
this._indices = {}; | |
this._instancesCounts = {}; | |
this.computeId = this.createComputeId(); | |
this.computeSelector = this.createComputeSelector(); | |
} | |
_createClass(StyleSheetRegistry, [{ | |
key: 'add', | |
value: function add(props) { | |
var _this = this; | |
if (undefined === this._optimizeForSpeed) { | |
this._optimizeForSpeed = Array.isArray(props.css); | |
this._sheet.setOptimizeForSpeed(this._optimizeForSpeed); | |
this._optimizeForSpeed = this._sheet.isOptimizeForSpeed(); | |
} | |
if (this._isBrowser && !this._fromServer) { | |
this._fromServer = this.selectFromServer(); | |
this._instancesCounts = Object.keys(this._fromServer).reduce(function (acc, tagName) { | |
acc[tagName] = 0; | |
return acc; | |
}, {}); | |
} | |
var _getIdAndRules = this.getIdAndRules(props), | |
styleId = _getIdAndRules.styleId, | |
rules = _getIdAndRules.rules; | |
// Deduping: just increase the instances count. | |
if (styleId in this._instancesCounts) { | |
this._instancesCounts[styleId] += 1; | |
return; | |
} | |
var indices = rules.map(function (rule) { | |
return _this._sheet.insertRule(rule); | |
}) | |
// Filter out invalid rules | |
.filter(function (index) { | |
return index !== -1; | |
}); | |
if (indices.length > 0) { | |
this._indices[styleId] = indices; | |
this._instancesCounts[styleId] = 1; | |
} | |
} | |
}, { | |
key: 'remove', | |
value: function remove(props) { | |
var _this2 = this; | |
var _getIdAndRules2 = this.getIdAndRules(props), | |
styleId = _getIdAndRules2.styleId; | |
invariant(styleId in this._instancesCounts, 'styleId: `' + styleId + '` not found'); | |
this._instancesCounts[styleId] -= 1; | |
if (this._instancesCounts[styleId] < 1) { | |
var tagFromServer = this._fromServer && this._fromServer[styleId]; | |
if (tagFromServer) { | |
tagFromServer.parentNode.removeChild(tagFromServer); | |
delete this._fromServer[styleId]; | |
} else { | |
this._indices[styleId].forEach(function (index) { | |
return _this2._sheet.deleteRule(index); | |
}); | |
delete this._indices[styleId]; | |
} | |
delete this._instancesCounts[styleId]; | |
} | |
} | |
}, { | |
key: 'update', | |
value: function update(props, nextProps) { | |
this.add(nextProps); | |
this.remove(props); | |
} | |
}, { | |
key: 'flush', | |
value: function flush() { | |
this._sheet.flush(); | |
this._sheet.inject(); | |
this._fromServer = undefined; | |
this._indices = {}; | |
this._instancesCounts = {}; | |
this.computeId = this.createComputeId(); | |
this.computeSelector = this.createComputeSelector(); | |
} | |
}, { | |
key: 'cssRules', | |
value: function cssRules() { | |
var _this3 = this; | |
var fromServer = this._fromServer ? Object.keys(this._fromServer).map(function (styleId) { | |
return [styleId, _this3._fromServer[styleId]]; | |
}) : []; | |
var cssRules = this._sheet.cssRules(); | |
return fromServer.concat(Object.keys(this._indices).map(function (styleId) { | |
return [styleId, _this3._indices[styleId].map(function (index) { | |
return cssRules[index].cssText; | |
}).join('\n')]; | |
})); | |
} | |
/** | |
* createComputeId | |
* | |
* Creates a function to compute and memoize a jsx id from a basedId and optionally props. | |
*/ | |
}, { | |
key: 'createComputeId', | |
value: function createComputeId() { | |
var cache = {}; | |
return function (baseId, props) { | |
if (!props) { | |
return 'jsx-' + baseId; | |
} | |
var propsToString = String(props); | |
var key = baseId + propsToString; | |
// return `jsx-${hashString(`${baseId}-${propsToString}`)}` | |
if (!cache[key]) { | |
cache[key] = 'jsx-' + (0, _stringHash2.default)(baseId + '-' + propsToString); | |
} | |
return cache[key]; | |
}; | |
} | |
/** | |
* createComputeSelector | |
* | |
* Creates a function to compute and memoize dynamic selectors. | |
*/ | |
}, { | |
key: 'createComputeSelector', | |
value: function createComputeSelector() { | |
var selectoPlaceholderRegexp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : /__jsx-style-dynamic-selector/g; | |
var cache = {}; | |
return function (id, css) { | |
// Sanitize SSR-ed CSS. | |
// Client side code doesn't need to be sanitized since we use | |
// document.createTextNode (dev) and the CSSOM api sheet.insertRule (prod). | |
if (!this._isBrowser) { | |
css = sanitize(css); | |
} | |
var idcss = id + css; | |
if (!cache[idcss]) { | |
cache[idcss] = css.replace(selectoPlaceholderRegexp, id); | |
} | |
return cache[idcss]; | |
}; | |
} | |
}, { | |
key: 'getIdAndRules', | |
value: function getIdAndRules(props) { | |
var _this4 = this; | |
if (props.dynamic) { | |
var styleId = this.computeId(props.styleId, props.dynamic); | |
return { | |
styleId: styleId, | |
rules: Array.isArray(props.css) ? props.css.map(function (rule) { | |
return _this4.computeSelector(styleId, rule); | |
}) : [this.computeSelector(styleId, props.css)] | |
}; | |
} | |
return { | |
styleId: this.computeId(props.styleId), | |
rules: Array.isArray(props.css) ? props.css : [props.css] | |
}; | |
} | |
/** | |
* selectFromServer | |
* | |
* Collects style tags from the document with id __jsx-XXX | |
*/ | |
}, { | |
key: 'selectFromServer', | |
value: function selectFromServer() { | |
var elements = Array.prototype.slice.call(document.querySelectorAll('[id^="__jsx-"]')); | |
return elements.reduce(function (acc, element) { | |
var id = element.id.slice(2); | |
acc[id] = element; | |
return acc; | |
}, {}); | |
} | |
}]); | |
return StyleSheetRegistry; | |
}(); | |
exports.default = StyleSheetRegistry; | |
function invariant(condition, message) { | |
if (!condition) { | |
throw new Error('StyleSheetRegistry: ' + message + '.'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment