Comparing version 2.0.1 to 3.0.0
@@ -1,1 +0,1 @@ | ||
module.exports = require('./src/babel') | ||
module.exports = require('./lib/babel') |
{ | ||
"name": "emotion", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"description": "👩🎤 Glam + React", | ||
"jsnext:main": "dist/emotion.es.js", | ||
"module": "dist/emotion.es.js", | ||
"main": "dist/glam.js", | ||
"umd:main": "dist/emotion.umd.js", | ||
"module": "src/index.js", | ||
"main": "lib/index.js", | ||
"files": [ | ||
@@ -15,15 +13,18 @@ "babel.js", | ||
"scripts": { | ||
"build": "npm-run-all clean -p rollup -p minify:* -s size", | ||
"build": "babel src -d lib", | ||
"build:watch": "npm run build -- -w", | ||
"umd": "npm-run-all clean -p rollup -p minify:* -s size", | ||
"clean": "rimraf dist", | ||
"test": "standard src test && jest --coverage", | ||
"test:watch": "jest --watch", | ||
"test": "standard src test && jest --coverage --no-cache", | ||
"test:watch": "jest --watch --no-cache", | ||
"rollup": "rollup -c", | ||
"minify:cjs": "uglifyjs $npm_package_main -cm toplevel -o $npm_package_main -p relative --in-source-map ${npm_package_main}.map --source-map ${npm_package_main}.map", | ||
"minify:umd": "uglifyjs $npm_package_umd_main -cm -o $npm_package_umd_main -p relative --in-source-map ${npm_package_umd_main}.map --source-map ${npm_package_umd_main}.map", | ||
"size": "echo \"Gzipped Size: $(strip-json-comments --no-whitespace $npm_package_main | gzip-size)\"", | ||
"release": "npm run test && npm run build && npm version patch && npm publish && git push --tags" | ||
"size": "echo \"Gzipped Size: $(strip-json-comments --no-whitespace $npm_package_umd_main | gzip-size)\"", | ||
"release": "npm run test && npm run build && npm version patch && npm publish && git push --tags", | ||
"lint": "standard --fix", | ||
"format": "prettier-eslint --write \"src/**/*.js\" \"test/**/*.js\" \"example/**/*.js\" \"jest-utils/**/*.js\"" | ||
}, | ||
"dependencies": { | ||
"babel-plugin-syntax-jsx": "^6.18.0", | ||
"glam": "^4.0.5" | ||
"styled-components": "2.0.0" | ||
}, | ||
@@ -35,4 +36,5 @@ "devDependencies": { | ||
"babel-jest": "^20.0.3", | ||
"babel-loader": "^7.0.0", | ||
"babel-loader": "^7.1.0", | ||
"babel-preset-env": "^1.5.1", | ||
"babel-preset-flow": "^6.23.0", | ||
"babel-preset-react": "^6.24.1", | ||
@@ -43,4 +45,6 @@ "babel-preset-stage-0": "^6.24.1", | ||
"jest-cli": "^20.0.4", | ||
"jest-emotion-react": "^0.0.2", | ||
"jest-glamor-react": "^1.4.0", | ||
"npm-run-all": "^4.0.2", | ||
"prettier-eslint-cli": "^4.0.3", | ||
"pretty-bytes-cli": "^2.0.0", | ||
@@ -50,5 +54,5 @@ "react": "^15.5.4", | ||
"react-dom": "^15.5.4", | ||
"react-test-renderer": "^15.5.4", | ||
"react-test-renderer": "^15.6.1", | ||
"rimraf": "^2.6.1", | ||
"rollup": "^0.41.6", | ||
"rollup": "^0.43.0", | ||
"rollup-plugin-babel": "^2.7.1", | ||
@@ -55,0 +59,0 @@ "rollup-plugin-buble": "^0.15.0", |
@@ -1,5 +0,12 @@ | ||
# emotion | ||
<h1 align="center" style="color: #343a40"> | ||
<img src="https://cdn.rawgit.com/tkh44/emotion/master/emotion.png" alt="emotion" width="200"> | ||
<br> | ||
emotion | ||
<br> | ||
</h1> | ||
<p align="center" style="font-size: 1.2rem;">high performance js for your css</p> | ||
## 👩🎤 Glam + React | ||
[![npm version](https://badge.fury.io/js/emotion.svg)](https://badge.fury.io/js/emotion) | ||
@@ -16,3 +23,3 @@ [![Build Status](https://travis-ci.org/tkh44/emotion.svg?branch=master)](https://travis-ci.org/tkh44/emotion) | ||
```bash | ||
npm install -S emotion glam | ||
npm install -S emotion | ||
``` | ||
@@ -25,4 +32,3 @@ | ||
"plugins": [ | ||
"emotion/babel", | ||
"glam/babel" | ||
"emotion/babel" | ||
] | ||
@@ -112,17 +118,1 @@ } | ||
### css prop | ||
When using the emotion babel plugin, any `css` prop is converted to a class name via glam and appended to any existing class names. | ||
**Similar to importing React when using jsx, `import css from 'glam'` must be at the top of your source files.** | ||
```jsx harmony | ||
const Name = ({ color, name }) => <h1 css={`color: ${color};`}>{name}</h1> | ||
// is converted to | ||
const Name = ({ color, name }) => <h1 className={css`color: ${color};`}>{name}</h1> | ||
``` | ||
385
src/babel.js
@@ -1,112 +0,43 @@ | ||
module.exports = function (babel) { | ||
const { types: t } = babel | ||
import { parseKeyframes } from './parser' | ||
import { inline, keyframes } from './inline' | ||
import findAndReplaceAttrs from './attrs' | ||
function createClassNameAttr (expression) { | ||
return t.jSXAttribute( | ||
t.jSXIdentifier('className'), | ||
t.JSXExpressionContainer(expression) | ||
) | ||
} | ||
function parseDynamicValues (rules, t) { | ||
return rules.map(rule => { | ||
const re = /xxx(\S)xxx/gm | ||
let varMatch | ||
let matches = [] | ||
while ((varMatch = re.exec(rule)) !== null) { | ||
matches.push({ | ||
value: varMatch[0], | ||
p1: varMatch[1], | ||
index: varMatch.index | ||
}) | ||
} | ||
function createCssTemplateExpression (templateLiteral) { | ||
return t.taggedTemplateExpression(t.identifier('css'), templateLiteral) | ||
} | ||
function findAndReplaceAttrs (path) { | ||
let quasis = path.node.quasi.quasis | ||
let stubs = path.node.quasi.expressions | ||
let didFindAtLeastOneMatch = false | ||
let [nextQuasis, nextStubs] = quasis.reduce( | ||
(accum, quasi, i) => { | ||
const str = quasi.value.cooked | ||
const regex = /attr\(([\S]+)(?:\s*(em|ex|px|rem|vw|vh|vmin|vmax|mm|cm|in|pt|pc|%)?)(?:,\s*([\S^)]+))?\)/gm | ||
let attrMatch | ||
let matches = [] | ||
while ((attrMatch = regex.exec(str)) !== null) { | ||
didFindAtLeastOneMatch = true | ||
matches.push({ | ||
value: attrMatch[0], | ||
propName: attrMatch[1], | ||
valueType: attrMatch[2], | ||
defaultValue: attrMatch[3], | ||
index: attrMatch.index | ||
}) | ||
let cursor = 0 | ||
const [quasis, expressions] = matches.reduce( | ||
(accum, { value, p1, index }, i) => { | ||
const [quasis, expressions] = accum | ||
const preMatch = rule.substring(cursor, index) | ||
cursor = cursor + preMatch.length + value.length | ||
if (preMatch) { | ||
quasis.push(t.templateElement({ raw: preMatch, cooked: preMatch })) | ||
} | ||
let cursor = 0 | ||
for (let j = 0; j < matches.length; ++j) { | ||
const match = matches[j] | ||
const value = match.value | ||
const propName = match.propName | ||
const valueType = match.valueType | ||
const defaultValue = match.defaultValue | ||
const index = match.index | ||
const preAttr = `${str.slice(cursor, index)}` | ||
cursor = index + value.length | ||
const postAttr = `${str.slice(cursor)}` | ||
expressions.push(t.identifier(`x${p1}`)) | ||
if (preAttr) { | ||
accum[0].push( | ||
t.templateElement({ raw: preAttr, cooked: preAttr }, false) | ||
) | ||
} | ||
if (i === matches.length - 1 && cursor <= rule.length) { | ||
const postMatch = rule.substring(cursor) | ||
if (postAttr && j === matches.length - 1) { | ||
accum[0].push( | ||
t.templateElement( | ||
{ raw: postAttr, cooked: postAttr }, | ||
i === quasis.length - 1 | ||
) | ||
quasis.push( | ||
t.templateElement( | ||
{ | ||
raw: postMatch, | ||
cooked: postMatch | ||
}, | ||
true | ||
) | ||
} | ||
let createMemberExpression = () => | ||
t.memberExpression(t.identifier('props'), t.identifier(propName)) | ||
let returnValue = createMemberExpression() | ||
if (valueType) { | ||
returnValue = t.binaryExpression( | ||
'+', | ||
createMemberExpression(), | ||
t.stringLiteral(valueType) | ||
) | ||
} | ||
if (defaultValue) { | ||
returnValue = t.conditionalExpression( | ||
createMemberExpression(), | ||
createMemberExpression(), | ||
t.parenthesizedExpression( | ||
t.binaryExpression( | ||
'+', | ||
t.stringLiteral(defaultValue), | ||
t.stringLiteral(valueType || '') | ||
) | ||
) | ||
) | ||
} | ||
const body = t.blockStatement([t.returnStatement(returnValue)]) | ||
const expr = t.functionExpression( | ||
t.identifier( | ||
`get${propName.charAt(0).toUpperCase() + propName.slice(1)}` | ||
), | ||
[t.identifier('props')], | ||
body | ||
) | ||
accum[1].push(expr) | ||
} | ||
if (matches.length === 0) { | ||
accum[0].push(quasi) | ||
if (stubs[i]) { | ||
accum[1].push(stubs[i]) | ||
} | ||
} else if (stubs[i]) { | ||
accum[1].push(stubs[i]) | ||
} | ||
return accum | ||
@@ -117,124 +48,68 @@ }, | ||
if (didFindAtLeastOneMatch) { | ||
return t.templateLiteral(nextQuasis, nextStubs) | ||
if (!matches.length) { | ||
return t.templateLiteral( | ||
[t.templateElement({ raw: rule, cooked: rule }, true)], | ||
[] | ||
) | ||
} | ||
return path.node.quasi | ||
} | ||
return t.templateLiteral(quasis, expressions) | ||
}) | ||
} | ||
export default function (babel) { | ||
const { types: t } = babel | ||
return { | ||
name: 'emotion-for-glam', // not required | ||
name: 'emotion', // not required | ||
inherits: require('babel-plugin-syntax-jsx'), | ||
visitor: { | ||
CallExpression (path) { | ||
// styled("h1", ["css-8xpzga", [fontSize], function inlineCss(x0) { | ||
// return [`.css-8xpzga { font-size: ${x0}px; }`]; | ||
// }]); | ||
// -> | ||
// styled('h1', [css-12, [color], function inlineCss(x0...){}, ...]) | ||
if (path.node.callee.name === 'css') { | ||
const parentPath = path.parentPath | ||
if ( | ||
parentPath.isCallExpression() && | ||
parentPath.node.callee && | ||
parentPath.node.callee.name === 'styled' | ||
) { | ||
path.replaceWithMultiple(t.arrayExpression(path.node.arguments)) | ||
} | ||
} | ||
}, | ||
JSXOpeningElement (path, state) { | ||
let cssPath | ||
let classNamesPath | ||
TaggedTemplateExpression (path) { | ||
// in: | ||
// styled.h1`color:${color};` | ||
// | ||
// out: | ||
// styled('h1', "css-r1aqtk", [colorVar, heightVar], function inlineCss(x0, x1) { | ||
// return [`.css-r1aqtk { | ||
// margin: 12px; | ||
// color: ${x0}; | ||
// height: ${x1}; }`]; | ||
// }); | ||
path.get('attributes').forEach(openElPath => { | ||
if (t.isJSXSpreadAttribute(openElPath.node)) { | ||
return | ||
} | ||
const parent = path.findParent(p => p.isVariableDeclarator()) | ||
const identifierName = parent && t.isIdentifier(parent.node.id) | ||
? parent.node.id.name | ||
: '' | ||
const attrPath = openElPath.get('name') | ||
const name = attrPath.node.name | ||
function buildCallExpression (identifier, tag, path) { | ||
const built = findAndReplaceAttrs(path, t) | ||
if (name === 'css') { | ||
cssPath = attrPath | ||
} | ||
let { hash, rules, name } = inline(built, identifierName, 'css') | ||
if (name === 'className') { | ||
classNamesPath = attrPath | ||
// hash will be '0' when no styles are passed so we can just return the original tag | ||
if (hash === '0') { | ||
return tag | ||
} | ||
}) | ||
if (!cssPath) return | ||
let arrayValues = parseDynamicValues(rules, t) | ||
let cssPropValue = cssPath.container && cssPath.container.value | ||
let classNamesValue = | ||
classNamesPath && | ||
classNamesPath.container && | ||
classNamesPath.container.value | ||
if (t.isJSXExpressionContainer(cssPropValue)) { | ||
cssPropValue = cssPropValue.expression | ||
} | ||
let cssTemplateExpression | ||
if (t.isTemplateLiteral(cssPropValue)) { | ||
cssTemplateExpression = createCssTemplateExpression(cssPropValue) | ||
} else if (t.isStringLiteral(cssPropValue)) { | ||
cssTemplateExpression = createCssTemplateExpression( | ||
t.templateLiteral( | ||
[ | ||
t.templateElement({ | ||
raw: cssPropValue.value, | ||
cooked: cssPropValue.value | ||
}) | ||
], | ||
[] | ||
) | ||
const inlineContentExpr = t.functionExpression( | ||
t.identifier('createEmotionStyledRules'), | ||
built.expressions.map((x, i) => t.identifier(`x${i}`)), | ||
t.blockStatement([ | ||
t.returnStatement(t.arrayExpression(arrayValues)) | ||
]) | ||
) | ||
} else { | ||
throw path.buildCodeFrameError( | ||
`${cssPropValue.value} is not a string or template literal` | ||
) | ||
} | ||
const args = [ | ||
tag, | ||
t.stringLiteral(`${name}-${hash}`), | ||
t.arrayExpression(built.expressions), | ||
inlineContentExpr | ||
] | ||
if (!classNamesValue) { | ||
cssPath.parentPath.replaceWith( | ||
createClassNameAttr(cssTemplateExpression) | ||
) | ||
return | ||
return t.callExpression(identifier, args) | ||
} | ||
cssPath.parentPath.remove() | ||
if (t.isJSXExpressionContainer(classNamesValue)) { | ||
classNamesPath.parentPath.replaceWith( | ||
createClassNameAttr( | ||
t.binaryExpression( | ||
'+', | ||
t.binaryExpression( | ||
'+', | ||
classNamesValue.expression, | ||
t.stringLiteral(' ') | ||
), | ||
cssTemplateExpression | ||
) | ||
) | ||
) | ||
} else { | ||
classNamesPath.parentPath.replaceWith( | ||
createClassNameAttr( | ||
t.binaryExpression( | ||
'+', | ||
t.binaryExpression( | ||
'+', | ||
t.stringLiteral(classNamesValue.value || ''), | ||
t.stringLiteral(' ') | ||
), | ||
cssTemplateExpression | ||
) | ||
) | ||
) | ||
} | ||
}, | ||
TaggedTemplateExpression (path) { | ||
if ( | ||
// styled.h1`color:${color};` -> styled('h1', css`color:${color};`) | ||
// styled.h1`color:${color};` | ||
t.isMemberExpression(path.node.tag) && | ||
@@ -244,12 +119,11 @@ path.node.tag.object.name === 'styled' && | ||
) { | ||
const built = findAndReplaceAttrs(path) | ||
path.replaceWith( | ||
t.callExpression(path.node.tag.object, [ | ||
buildCallExpression( | ||
path.node.tag.object, | ||
t.stringLiteral(path.node.tag.property.name), | ||
t.taggedTemplateExpression(t.identifier('css'), built) | ||
]) | ||
path | ||
) | ||
) | ||
} else if ( | ||
// styled('h1')`color:${color};` -> styled('h1', css`color:${color};`) | ||
// styled('h1')`color:${color};` | ||
t.isCallExpression(path.node.tag) && | ||
@@ -259,9 +133,88 @@ path.node.tag.callee.name === 'styled' && | ||
) { | ||
const built = findAndReplaceAttrs(path) | ||
path.replaceWith( | ||
t.callExpression(path.node.tag.callee, [ | ||
buildCallExpression( | ||
path.node.tag.callee, | ||
path.node.tag.arguments[0], | ||
t.taggedTemplateExpression(t.identifier('css'), built) | ||
path | ||
) | ||
) | ||
} else if ( | ||
t.isIdentifier(path.node.tag) && | ||
path.node.tag.name === 'fragment' | ||
) { | ||
const { hash, name, rules } = inline( | ||
path.node.quasi, | ||
identifierName, | ||
'frag' | ||
) | ||
path.replaceWith( | ||
t.callExpression(t.identifier('fragment'), [ | ||
t.stringLiteral(`${name}-${hash}`), | ||
t.arrayExpression(path.node.quasi.expressions), | ||
t.functionExpression( | ||
t.identifier('createEmotionFragment'), | ||
path.node.quasi.expressions.map((x, i) => | ||
t.identifier(`x${i}`) | ||
), | ||
t.blockStatement([ | ||
t.returnStatement( | ||
t.arrayExpression(parseDynamicValues(rules, t)) | ||
) | ||
]) | ||
) | ||
]) | ||
) | ||
} else if ( | ||
t.isIdentifier(path.node.tag) && | ||
path.node.tag.name === 'css' | ||
) { | ||
const { hash, name, rules } = inline( | ||
path.node.quasi, | ||
identifierName, | ||
'css' | ||
) | ||
path.replaceWith( | ||
t.callExpression(t.identifier('css'), [ | ||
t.stringLiteral(`${name}-${hash}`), | ||
t.arrayExpression(path.node.quasi.expressions), | ||
t.functionExpression( | ||
t.identifier('createEmotionRules'), | ||
path.node.quasi.expressions.map((x, i) => | ||
t.identifier(`x${i}`) | ||
), | ||
t.blockStatement([ | ||
t.returnStatement( | ||
t.arrayExpression(parseDynamicValues(rules, t)) | ||
) | ||
]) | ||
) | ||
]) | ||
) | ||
} else if ( | ||
t.isIdentifier(path.node.tag) && | ||
path.node.tag.name === 'keyframes' | ||
) { | ||
const { hash, name, rules } = keyframes( | ||
path.node.quasi, | ||
identifierName, | ||
'animation' | ||
) | ||
path.replaceWith( | ||
t.callExpression(t.identifier('keyframes'), [ | ||
t.stringLiteral(`${name}-${hash}`), | ||
t.arrayExpression(path.node.quasi.expressions), | ||
t.functionExpression( | ||
t.identifier('createEmotionKeyframe'), | ||
path.node.quasi.expressions.map((x, i) => | ||
t.identifier(`x${i}`) | ||
), | ||
t.blockStatement([ | ||
t.returnStatement( | ||
t.arrayExpression(rules.map(r => t.stringLiteral(r))) | ||
) | ||
]) | ||
) | ||
]) | ||
) | ||
} | ||
@@ -268,0 +221,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 2 instances in 1 package
1
0
27316
30
12
703
116
1
+ Addedstyled-components@2.0.0
- Removedbabel-plugin-syntax-jsx@^6.18.0
- Removedglam@^4.0.5
- Removedabbrev@1.1.1(transitive)
- Removedansi-styles@3.2.1(transitive)
- Removedautoprefixer@7.2.6(transitive)
- Removedbabel-plugin-syntax-jsx@6.18.0(transitive)
- Removedbabylon@6.18.0(transitive)
- Removedbrowserslist@2.11.3(transitive)
- Removedcaniuse-lite@1.0.30001679(transitive)
- Removedchalk@2.4.2(transitive)
- Removedcolor-convert@1.9.3(transitive)
- Removedcolor-name@1.1.3(transitive)
- Removedelectron-to-chromium@1.5.55(transitive)
- Removedescape-string-regexp@1.0.5(transitive)
- Removedglam@4.0.5(transitive)
- Removedhas-flag@3.0.0(transitive)
- Removednopt@1.0.10(transitive)
- Removednormalize-range@0.1.2(transitive)
- Removednum2fraction@1.2.2(transitive)
- Removedpostcss@6.0.23(transitive)
- Removedsource-map@0.6.1(transitive)
- Removedsupports-color@5.5.0(transitive)
- Removedtouch@1.0.0(transitive)