Repository: tkh44/emotion
Pull request #1 (2017-05-28 06:14:50)

Add glamor


Patch:
diff --git a/README.md b/README.md
index 89eaddcc..46fc2368 100644
--- a/README.md
+++ b/README.md
@@ -44,3 +44,31 @@ const Name = ({ color, name }) => <h1 className={css`color: ${color};`}>{name}</
 
 **Similar to importing React when using jsx, `import css from 'glam'` must be at the top of your source files.**
 
+## `emotion/glamor`
+
+```bash
+npm install -S glamor
+```
+
+**.babelrc**
+```json
+{
+  "plugins": [
+    "emotion/glamor",
+  ]
+}
+```
+
+```jsx harmony
+const Name = ({ color, name }) => <h1 css={{ color: 'red' }}>{name}</h1>
+```
+
+is converted to
+
+```jsx harmony
+const Name = ({ color, name }) => <h1 {...css({color: 'red' })}>{name}</h1>
+```
+
+
+**Similar to importing React when using jsx, `import {css} from 'glamor'` must be at the top of your source files.**
+
diff --git a/glamor.js b/glamor.js
new file mode 100644
index 00000000..d2cce17a
--- /dev/null
+++ b/glamor.js
@@ -0,0 +1,1 @@
+module.exports = require('./src/glamor/babel')
diff --git a/package.json b/package.json
index 0e1aa883..195760fc 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
     "babel-preset-react": "^6.24.1",
     "babel-preset-stage-0": "^6.24.1",
     "glam": "^4.0.3",
+    "glamor": "^2.20.25",
     "jest": "^20.0.1",
     "jest-glamor-react": "^1.3.0",
     "react": "^15.5.4",
diff --git a/src/glamor/babel.js b/src/glamor/babel.js
new file mode 100644
index 00000000..ceaa23b5
--- /dev/null
+++ b/src/glamor/babel.js
@@ -0,0 +1,37 @@
+module.exports = function (babel) {
+  const {types: t} = babel
+
+  return {
+    name: 'emotion-for-glam', // not required
+    inherits: require('babel-plugin-syntax-jsx'),
+    visitor: {
+      JSXOpeningElement (path, state) {
+        let cssPath
+
+        path.get('attributes').forEach(openElPath => {
+          const attrPath = openElPath.get('name')
+          const name = attrPath.node.name
+
+          if (name === 'css') {
+            cssPath = attrPath
+          }
+        })
+
+        if (!cssPath) return
+
+        let cssPropValue = cssPath.container && cssPath.container.value
+
+        if (t.isJSXExpressionContainer(cssPropValue)) {
+          cssPropValue = cssPropValue.expression
+        }
+
+        let glamorCssFunction = t.callExpression(t.identifier('css'), [
+          cssPropValue
+        ])
+
+        cssPath.parentPath.insertAfter(t.jSXSpreadAttribute(glamorCssFunction))
+        cssPath.parentPath.remove()
+      }
+    }
+  }
+}


Test patch:
diff --git a/src/glamor/__tests__/.babelrc b/src/glamor/__tests__/.babelrc
new file mode 100644
index 00000000..1f68b4d6
--- /dev/null
+++ b/src/glamor/__tests__/.babelrc
@@ -0,0 +1,10 @@
+{
+  "presets": [
+    "env",
+    "stage-0",
+    "react"
+  ],
+  "plugins": [
+    ["../babel.js"],
+  ]
+}
diff --git a/src/glamor/__tests__/__snapshots__/index.js.snap b/src/glamor/__tests__/__snapshots__/index.js.snap
new file mode 100644
index 00000000..2e03eb77
--- /dev/null
+++ b/src/glamor/__tests__/__snapshots__/index.js.snap
@@ -0,0 +1,91 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`emotion/glamor babel basic 1`] = `"<div className=\\"a\\" {...css({ color: 'brown' })}></div>;"`;
+
+exports[`emotion/glamor babel className as expression 1`] = `"<div className={props.className} {...css({ color: 'brown' })}></div>;"`;
+
+exports[`emotion/glamor babel className as expression string 1`] = `"<div className={\`test__class\`} {...css({ color: 'brown' })} this={\`hello\`}></div>;"`;
+
+exports[`emotion/glamor babel css empty 1`] = `"<div {...css({})}></div>;"`;
+
+exports[`emotion/glamor babel emptyClassName 1`] = `"<div className=\\"\\" {...css({ color: 'brown' })}></div>;"`;
+
+exports[`emotion/glamor babel no className 1`] = `"<div {...css({ color: 'brown' })}></div>;"`;
+
+exports[`emotion/glamor babel no css attr 1`] = `"<div></div>;"`;
+
+exports[`emotion/glamor babel wrong value type 1`] = `"<div {...css(5)}></div>;"`;
+
+exports[`emotion/glamor real basic 1`] = `
+.css-1ezp9xe,
+[data-css-1ezp9xe] {
+  color: red;
+}
+
+<p
+  data-css-1ezp9xe=""
+>
+  hello world
+</p>
+`;
+
+exports[`emotion/glamor real kitchen sink 1`] = `
+.css-icjsl7,
+[data-css-icjsl7] {
+  color: blue;
+}
+
+.css-gvvg5g,
+[data-css-gvvg5g] {
+  color: gray;
+}
+
+.css-16ywyew,
+[data-css-16ywyew] {
+  border: 1px solid blue;
+}
+
+.css-1cqgl9p,
+[data-css-1cqgl9p] {
+  display: -webkit-box;
+  display: -moz-box;
+  display: -ms-flexbox;
+  display: -webkit-flex;
+  display: flex;
+}
+
+@media (min-width: 420px) {
+  .css-198yaui,
+  [data-css-198yaui] {
+    font-size: 48px;
+  }
+}
+
+<div
+  className="css__legacy-stuff"
+  data-css-icjsl7=""
+>
+  <h1
+    data-css-198yaui=""
+  >
+    BOOM
+  </h1>
+  <p
+    className="test_class1"
+    data-css-gvvg5g=""
+  >
+    Hello
+  </p>
+  <p
+    className="test_class1 test___class45"
+    data-css-16ywyew=""
+  >
+    World
+  </p>
+  <p
+    data-css-1cqgl9p=""
+  >
+    hello world
+  </p>
+</div>
+`;
diff --git a/src/glamor/__tests__/index.js b/src/glamor/__tests__/index.js
new file mode 100644
index 00000000..d750cffb
--- /dev/null
+++ b/src/glamor/__tests__/index.js
@@ -0,0 +1,104 @@
+/* eslint-disable jsx-quotes,no-useless-escape */
+/* eslint-env jest */
+import React from 'react'
+import renderer from 'react-test-renderer'
+import plugin from '../babel'
+import { matcher, serializer } from 'jest-glamor-react'
+import { css } from 'glamor'
+
+expect.addSnapshotSerializer(serializer)
+expect.extend(matcher)
+
+const babel = require('babel-core')
+
+describe('emotion/glamor', () => {
+  describe('babel', () => {
+    test('basic', () => {
+      const basic = `(<div className="a" css={{ color: 'brown' }}></div>)`
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+
+    test('no css attr', () => {
+      const basic = '(<div></div>)'
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+
+    test('css empty', () => {
+      const basic = '(<div css={{}}></div>)'
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+
+    test('wrong value type', () => {
+      const basic = '(<div css={5}></div>)'
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+
+    test('no className', () => {
+      const basic = `(<div css={{ color: 'brown' }}></div>)`
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+
+    test('emptyClassName', () => {
+      const basic = `(<div className="" css={{ color: 'brown' }}></div>)`
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+
+    test('className as expression', () => {
+      const basic = `(<div className={props.className} css={{ color: 'brown' }}></div>)`
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+
+    test('className as expression string', () => {
+      const basic =
+        "(<div className={`test__class\`} css={{ color: 'brown'}} this={`hello\`}></div>)"
+      const {code} = babel.transform(basic, {plugins: [plugin]})
+      expect(code).toMatchSnapshot()
+    })
+  })
+
+  describe('real', () => {
+    test('basic', () => {
+      const tree = renderer
+        .create(
+          <p css={{color: 'red'}}>
+            hello world
+          </p>
+        )
+        .toJSON()
+
+      expect(tree).toMatchSnapshotWithGlamor()
+    })
+
+    test('kitchen sink', () => {
+      const tree = renderer
+        .create(
+          <div className="css__legacy-stuff" css={{color: 'blue'}}>
+            <h1 css={{'@media(min-width: 420px)': {fontSize: 48}}}>
+              BOOM
+            </h1>
+            <p className="test_class1" css={{color: 'gray'}}>Hello</p>
+            <p
+              className="test_class1 test___class45"
+              css={{border: '1px solid blue'}}
+            >
+              World
+            </p>
+            <p css={{display: 'flex'}}>
+              hello world
+            </p>
+
+          </div>
+        )
+        .toJSON()
+
+      expect(tree).toMatchSnapshotWithGlamor()
+    })
+  })
+})