├── .yarnrc ├── docs ├── _config.yml ├── benchmarks.md ├── with-props.md ├── webpack.md ├── inject-global.md ├── instances.md ├── theming.md ├── nested.md ├── keyframes.md ├── install.md ├── source-maps.md ├── composition.md ├── extract-static.md ├── media-queries.md ├── object-styles.md ├── index.md ├── README.md ├── testing.md ├── css.md ├── babel.md └── ssr.md ├── emotion.png ├── packages ├── emotion │ ├── macro.js │ ├── test │ │ ├── no-babel │ │ │ └── .babelrc │ │ ├── auto-label │ │ │ ├── .babelrc │ │ │ ├── auto-label.test.js │ │ │ └── __snapshots__ │ │ │ │ └── auto-label.test.js.snap │ │ ├── extract │ │ │ ├── .babelrc │ │ │ ├── extract.test.emotion.css │ │ │ ├── __snapshots__ │ │ │ │ └── extract.test.js.snap │ │ │ └── extract.test.js │ │ ├── source-map │ │ │ ├── .babelrc │ │ │ └── source-map.test.js │ │ ├── prod-mode │ │ │ ├── .babelrc │ │ │ ├── __snapshots__ │ │ │ │ └── prod-mode.test.js.snap │ │ │ └── prod-mode.test.js │ │ ├── __snapshots__ │ │ │ ├── label-pattern.test.js.snap │ │ │ ├── sheet.dom.test.js.snap │ │ │ ├── component-selector.test.js.snap │ │ │ ├── cx.test.js.snap │ │ │ ├── inject-global.test.js.snap │ │ │ ├── selectivity.test.js.snap │ │ │ └── css-prop.test.js.snap │ │ ├── label-pattern.test.js │ │ ├── component-selector.test.js │ │ ├── sheet.dom.test.js │ │ ├── keyframes.test.js │ │ └── inject-global.test.js │ ├── types │ │ ├── tslint.json │ │ ├── tsconfig.json │ │ ├── tests.tsx │ │ └── index.d.ts │ ├── src │ │ └── index.js │ └── package.json ├── emotion-theming │ ├── src │ │ ├── channel.js │ │ ├── index.js │ │ ├── utils.js │ │ ├── create-broadcast.js │ │ └── with-theme.js │ ├── types │ │ ├── tslint.json │ │ ├── tsconfig.json │ │ ├── index.d.ts │ │ └── tests.tsx │ ├── package.json │ └── test │ │ ├── test-helpers.js │ │ └── __snapshots__ │ │ └── index.test.js.snap ├── preact-emotion │ ├── macro.js │ ├── src │ │ └── index.js │ └── package.json ├── react-emotion │ ├── macro.js │ ├── types │ │ ├── tslint.json │ │ └── tsconfig.json │ ├── test │ │ ├── component-selectors │ │ │ ├── .babelrc │ │ │ └── component-selector.test.js │ │ └── auto-label │ │ │ └── .babelrc │ ├── src │ │ └── index.js │ └── package.json ├── babel-plugin-emotion │ ├── test │ │ ├── styled │ │ │ └── macro.js │ │ ├── .babelrc │ │ ├── macro │ │ │ ├── .babelrc │ │ │ ├── __snapshots__ │ │ │ │ └── inject-global.test.js.snap │ │ │ ├── babel-macros-register.js │ │ │ ├── inject-global.test.js │ │ │ └── keyframes.test.js │ │ ├── __snapshots__ │ │ │ └── fs.test.js.snap │ │ ├── keyframes.test.js │ │ ├── fs.test.js │ │ ├── source-map.test.js │ │ └── inject-global.test.js │ ├── src │ │ ├── source-map.js │ │ ├── macro.js │ │ ├── macro-styled.js │ │ └── ast-object.js │ └── package.json ├── site │ ├── favicon.ico │ ├── README.md │ ├── src │ │ ├── blocks │ │ │ ├── intro.example │ │ │ ├── styled-with-object.example │ │ │ ├── named.example │ │ │ ├── nested.example │ │ │ ├── styled-with-component.example │ │ │ ├── media-queries.example │ │ │ ├── composition.example │ │ │ ├── .eslintrc │ │ │ ├── styled.example │ │ │ ├── theming.example │ │ │ ├── keyframes.example │ │ │ ├── css.example │ │ │ └── object-styles.example │ │ └── index.tpl.html │ ├── .babelrc │ ├── package.json │ └── webpack.config.js ├── benchmarks │ ├── src │ │ ├── glamorous.js │ │ ├── emotion-css.js │ │ ├── emotion-obj.js │ │ ├── styled-components.js │ │ ├── css-modules.js │ │ ├── glamor.js │ │ ├── emotion.js │ │ └── components │ │ │ ├── Wrapper │ │ │ ├── emotion.js │ │ │ └── glamor.js │ │ │ ├── View │ │ │ ├── styles.css │ │ │ ├── css-modules.js │ │ │ ├── emotion.js │ │ │ ├── styled-components.js │ │ │ ├── glamorous.js │ │ │ ├── emotion-obj.js │ │ │ ├── emotion-css.js │ │ │ └── glamor.js │ │ │ ├── Dot │ │ │ ├── emotion.js │ │ │ └── glamor.js │ │ │ ├── Box │ │ │ ├── styles.css │ │ │ ├── css-modules.js │ │ │ ├── glamorous.js │ │ │ ├── emotion-obj.js │ │ │ ├── emotion.js │ │ │ ├── styled-components.js │ │ │ ├── glamor.js │ │ │ └── emotion-css.js │ │ │ ├── NestedTree.js │ │ │ └── SierpinskiTriangle.js │ ├── index.html │ ├── README.md │ ├── tests │ │ ├── renderDeepTree.js │ │ ├── renderWideTree.js │ │ └── renderSierpinskiTriangle.js │ ├── createRenderBenchmark.js │ ├── send-results.js │ ├── package.json │ ├── webpack.config.js │ ├── run-headless.js │ ├── index.js │ └── benchmark.js ├── emotion-server │ ├── test │ │ ├── auto-label │ │ │ └── .babelrc │ │ ├── index.test.js │ │ ├── inline.test.js │ │ └── stream.test.js │ ├── src │ │ └── index.js │ └── package.json ├── create-emotion │ ├── test │ │ ├── __snapshots__ │ │ │ └── instance.test.js.snap │ │ ├── .babelrc │ │ ├── instance.test.js │ │ ├── emotion-instance.js │ │ ├── inline.test.js │ │ └── stream.test.js │ ├── package.json │ └── src │ │ └── utils.js ├── create-emotion-server │ ├── src │ │ ├── index.js │ │ ├── extract-critical.js │ │ ├── stream.js │ │ └── inline.js │ ├── README.md │ └── package.json ├── create-emotion-styled │ ├── README.md │ ├── package.json │ └── src │ │ └── utils.js ├── jest-emotion │ ├── package.json │ ├── src │ │ └── replace-class-names.js │ └── README.md └── emotion-utils │ ├── package.json │ └── src │ ├── index.js │ └── hash.js ├── .eslintignore ├── .gitignore ├── netlify.toml ├── babel-plugin-emotion-test.js ├── jest.dist.js ├── codecov.yml ├── test ├── styleTransform.js ├── pretty-css.js └── testSetup.js ├── jest.config.js ├── lerna.json ├── .travis.yml ├── .babelrc ├── CONTRIBUTING.md ├── flow-typed └── npm │ ├── jest-glamor-react_vx.x.x.js │ └── react-test-renderer_vx.x.x.js ├── .flowconfig ├── LICENSE ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md └── rollup.config.js /.yarnrc: -------------------------------------------------------------------------------- 1 | workspaces-experimental true 2 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /emotion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stereobooster/emotion/master/emotion.png -------------------------------------------------------------------------------- /packages/emotion/macro.js: -------------------------------------------------------------------------------- 1 | module.exports = require('babel-plugin-emotion/lib/macro') 2 | -------------------------------------------------------------------------------- /packages/emotion-theming/src/channel.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export default '__EMOTION_THEMING__' 3 | -------------------------------------------------------------------------------- /packages/preact-emotion/macro.js: -------------------------------------------------------------------------------- 1 | module.exports = require('babel-plugin-emotion/lib/macro-styled') 2 | -------------------------------------------------------------------------------- /packages/react-emotion/macro.js: -------------------------------------------------------------------------------- 1 | module.exports = require('babel-plugin-emotion/lib/macro-styled') 2 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/test/styled/macro.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../src/macro-styled') 2 | -------------------------------------------------------------------------------- /packages/site/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stereobooster/emotion/master/packages/site/favicon.ico -------------------------------------------------------------------------------- /docs/benchmarks.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | https://github.com/A-gambit/CSS-IN-JS-Benchmarks/blob/master/RESULT.md 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | dist/ 3 | coverage/ 4 | node_modules/ 5 | stylis.js 6 | /demo/dist 7 | /packages/site/build 8 | flow-typed/ -------------------------------------------------------------------------------- /packages/emotion/test/no-babel/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": ["codegen"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/site/README.md: -------------------------------------------------------------------------------- 1 | # emotion example project 2 | 3 | ## Start 4 | 5 | `npm install` 6 | 7 | `npm start` 8 | 9 | Go to `localhost:3000` 10 | -------------------------------------------------------------------------------- /packages/emotion/types/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "dtslint/dtslint.json", 3 | "rules": { 4 | "no-relative-import-in-test": false 5 | } 6 | } -------------------------------------------------------------------------------- /packages/react-emotion/types/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "dtslint/dtslint.json", 3 | "rules": { 4 | "no-relative-import-in-test": false 5 | } 6 | } -------------------------------------------------------------------------------- /packages/emotion-theming/types/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "dtslint/dtslint.json", 3 | "rules": { 4 | "no-relative-import-in-test": false 5 | } 6 | } -------------------------------------------------------------------------------- /packages/site/src/blocks/intro.example: -------------------------------------------------------------------------------- 1 | const Avatar = styled.img` 2 | width: 96px; 3 | height: 96px; 4 | border-radius: 50%; 5 | ` 6 | 7 | render() 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /demo/dist 3 | dist/ 4 | lib/ 5 | node_modules/ 6 | *.log 7 | .idea 8 | packages/site/build 9 | package-lock.json 10 | .DS_Store 11 | .cache 12 | public/ -------------------------------------------------------------------------------- /packages/benchmarks/src/glamorous.js: -------------------------------------------------------------------------------- 1 | import Box from './components/Box/glamorous' 2 | import View from './components/View/glamorous' 3 | 4 | export default { 5 | Box, 6 | View 7 | } 8 | -------------------------------------------------------------------------------- /packages/benchmarks/src/emotion-css.js: -------------------------------------------------------------------------------- 1 | import Box from './components/Box/emotion-css' 2 | import View from './components/View/emotion-css' 3 | 4 | export default { 5 | Box, 6 | View 7 | } 8 | -------------------------------------------------------------------------------- /packages/benchmarks/src/emotion-obj.js: -------------------------------------------------------------------------------- 1 | import Box from './components/Box/emotion-obj' 2 | import View from './components/View/emotion-obj' 3 | 4 | export default { 5 | Box, 6 | View 7 | } 8 | -------------------------------------------------------------------------------- /packages/site/src/blocks/styled-with-object.example: -------------------------------------------------------------------------------- 1 | const Avatar = styled('img')({ 2 | width: 96, 3 | height: 96, 4 | borderRadius: '50%' 5 | }) 6 | 7 | render() 8 | -------------------------------------------------------------------------------- /packages/site/src/blocks/named.example: -------------------------------------------------------------------------------- 1 | const Avatar = styled('img')` 2 | name: emotion-avatar; 3 | width: 96px; 4 | height: 96px; 5 | border-radius: 50%; 6 | ` 7 | 8 | render() 9 | -------------------------------------------------------------------------------- /packages/benchmarks/src/styled-components.js: -------------------------------------------------------------------------------- 1 | import Box from './components/Box/styled-components' 2 | import View from './components/View/styled-components' 3 | 4 | export default { 5 | Box, 6 | View 7 | } 8 | -------------------------------------------------------------------------------- /packages/react-emotion/test/component-selectors/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": [["../../../../babel-plugin-emotion-test"], "codegen"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/emotion-theming/src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export { default as ThemeProvider } from './theme-provider' 3 | export { default as withTheme } from './with-theme' 4 | export { channel, contextTypes } from './utils' 5 | -------------------------------------------------------------------------------- /packages/emotion/test/auto-label/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": [["../../../../babel-plugin-emotion-test", {"autoLabel": true}], "codegen"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/emotion/test/extract/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": [["../../../../babel-plugin-emotion-test", {"extractStatic": true}], "codegen"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/emotion/test/source-map/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": [["../../../../babel-plugin-emotion-test", {"sourceMap": true}], "codegen"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/emotion-server/test/auto-label/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": [["../../../../babel-plugin-emotion-test", {"autoLabel": true}], "codegen"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/react-emotion/test/auto-label/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": [["../../../../babel-plugin-emotion-test", {"autoLabel": true}], "codegen"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/benchmarks/src/css-modules.js: -------------------------------------------------------------------------------- 1 | import Box from './components/Box/css-modules' 2 | import View from './components/View/css-modules' 3 | 4 | const api = { 5 | Box, 6 | View 7 | } 8 | 9 | export default api 10 | -------------------------------------------------------------------------------- /packages/benchmarks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Performance tests 7 | 8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /packages/preact-emotion/src/index.js: -------------------------------------------------------------------------------- 1 | import preact from 'preact' 2 | import * as emotion from 'emotion' 3 | import createEmotionStyled from 'create-emotion-styled' 4 | 5 | export default createEmotionStyled(emotion, preact) 6 | 7 | export * from 'emotion' 8 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "rm -rf /opt/buildhome/.yarn && curl -o- -L https://yarnpkg.com/install.sh | bash && export PATH=\"$HOME/.yarn/bin:$PATH\" && yarn && npm run bootstrap && npm run build && npm run build:site" 3 | publish = "packages/site/build" -------------------------------------------------------------------------------- /packages/react-emotion/src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import * as emotion from 'emotion' 4 | import createEmotionStyled from 'create-emotion-styled' 5 | 6 | export default createEmotionStyled(emotion, React) 7 | 8 | export * from 'emotion' 9 | -------------------------------------------------------------------------------- /packages/site/src/blocks/nested.example: -------------------------------------------------------------------------------- 1 | const Avatar = styled('div')` 2 | & img { 3 | width: 96px; 4 | height: 96px; 5 | border-radius: 50%; 6 | } 7 | ` 8 | 9 | render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /packages/site/src/blocks/styled-with-component.example: -------------------------------------------------------------------------------- 1 | const Circle = styled('span')` 2 | width: 96px; 3 | height: 96px; 4 | border-radius: 50%; 5 | ` 6 | 7 | const Avatar = Circle.withComponent('img') 8 | 9 | render() 10 | -------------------------------------------------------------------------------- /packages/create-emotion/test/__snapshots__/instance.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`general instance tests throws with invalid key 1`] = `"Emotion key must only contain lower case alphabetical characters and - but \\"css1\\" was passed"`; 4 | -------------------------------------------------------------------------------- /babel-plugin-emotion-test.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | const path = require('path') 3 | require('module-alias').addAliases({ 4 | 'emotion-utils': path.resolve(__dirname, './packages/emotion-utils/src') 5 | }) 6 | 7 | module.exports = require('./packages/babel-plugin-emotion/src') 8 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/test/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "loose": true, 7 | "exclude": ["transform-es2015-typeof-symbol"] 8 | } 9 | ], 10 | "stage-0", 11 | "react", 12 | "flow" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/emotion-server/src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import createEmotionServer from 'create-emotion-server' 3 | import * as emotion from 'emotion' 4 | 5 | export const { 6 | extractCritical, 7 | renderStylesToString, 8 | renderStylesToNodeStream 9 | } = createEmotionServer(emotion) 10 | -------------------------------------------------------------------------------- /packages/site/src/blocks/media-queries.example: -------------------------------------------------------------------------------- 1 | const Avatar = styled('img')` 2 | width: 32px; 3 | height: 32px; 4 | border-radius: 50%; 5 | 6 | @media (min-width: 420px) { 7 | width: 96px; 8 | height: 96px; 9 | } 10 | ` 11 | 12 | render() 13 | -------------------------------------------------------------------------------- /packages/benchmarks/src/glamor.js: -------------------------------------------------------------------------------- 1 | import Box from './components/Box/glamor' 2 | import View from './components/View/glamor' 3 | import Dot from './components/Dot/glamor' 4 | import Wrapper from './components/Wrapper/glamor' 5 | 6 | export default { 7 | Box, 8 | View, 9 | Wrapper, 10 | Dot 11 | } 12 | -------------------------------------------------------------------------------- /packages/benchmarks/src/emotion.js: -------------------------------------------------------------------------------- 1 | import Box from './components/Box/emotion' 2 | import View from './components/View/emotion' 3 | import Dot from './components/Dot/emotion' 4 | import Wrapper from './components/Wrapper/emotion' 5 | 6 | export default { 7 | Box, 8 | View, 9 | Dot, 10 | Wrapper 11 | } 12 | -------------------------------------------------------------------------------- /packages/emotion-theming/src/utils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import PropTypes from 'prop-types' 3 | import channel from './channel' 4 | 5 | export const contextTypes = { 6 | [channel]: PropTypes.object 7 | } 8 | 9 | export { default as channel } from './channel' 10 | 11 | export type Theme = Object | ((theme: Object) => Object) 12 | -------------------------------------------------------------------------------- /packages/emotion/test/prod-mode/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "env", 5 | "react" 6 | ], 7 | "plugins": [ 8 | [ 9 | "transform-define", 10 | { 11 | "process.env.NODE_ENV": "production" 12 | } 13 | ], ["../../../../babel-plugin-emotion-test"], "codegen"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/site/src/blocks/composition.example: -------------------------------------------------------------------------------- 1 | const imageBase = css` 2 | width: 32px; 3 | height: 32px; 4 | border-radius: 50%; 5 | ` 6 | 7 | const Avatar = styled('img')` 8 | ${imageBase}; 9 | 10 | @media (min-width: 420px) { 11 | width: 96px; 12 | height: 96px; 13 | } 14 | ` 15 | 16 | render() 17 | -------------------------------------------------------------------------------- /packages/site/src/blocks/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "React": false, 4 | "css": false, 5 | "styled": false, 6 | "colors": false, 7 | "render": false, 8 | "ReactMarkdown": false, 9 | "docMarkdown": false 10 | }, 11 | "rules": { 12 | max-len: [ 13 | "error", 14 | 50 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jest.dist.js: -------------------------------------------------------------------------------- 1 | const { jest: lernaAliases } = require('lerna-alias') 2 | const baseConfig = require('./jest.config.js') 3 | 4 | module.exports = Object.assign({}, baseConfig, { 5 | moduleNameMapper: lernaAliases({ sourceDirectory: false }), 6 | transformIgnorePatterns: ['dist', 'node_modules'], 7 | testPathIgnorePatterns: ['babel-plugin-emotion'] 8 | }) 9 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/test/macro/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "loose": true, 7 | "exclude": ["transform-es2015-typeof-symbol"] 8 | } 9 | ], 10 | "stage-0", 11 | "react", 12 | "flow" 13 | ], 14 | "plugins": ["codegen", "./babel-macros-register"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/test/macro/__snapshots__/inject-global.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`injectGlobal 1`] = ` 4 | "html { 5 | background: pink; 6 | } 7 | 8 | html.active { 9 | background: red; 10 | } 11 | 12 | body { 13 | color: yellow; 14 | margin: 0; 15 | padding: 0; 16 | }" 17 | `; 18 | -------------------------------------------------------------------------------- /packages/emotion/test/extract/extract.test.emotion.css: -------------------------------------------------------------------------------- 1 | .css-dae0kw{font-size:12px;} 2 | .css-s9f816{font-size:20px;}.css-s9f816 span{color:blue;}.css-s9f816 span:hover{color:green;}.css-s9f816 span:hover:after{content:'after';} 3 | .css-mdajr1{font-size:20px;} 4 | html{background:pink;} 5 | .css-14yvnlz{font-family:sans-serif;color:yellow;background-color:purple;} -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: # https://docs.codecov.io/docs/pull-request-comments 2 | layout: "files" 3 | behavior: once 4 | require_changes: true # if true: only post the comment if coverage changes 5 | require_base: no # [yes :: must have a base report to post] 6 | require_head: yes # [yes :: must have a head report to post] 7 | branches: null 8 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Wrapper/emotion.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion/macro' 2 | 3 | const Wrapper = styled('div')` 4 | position: absolute; 5 | transform-origin: 0 0; 6 | left: 50%; 7 | top: 50%; 8 | width: 10px; 9 | height: 10px; 10 | background: #eee; 11 | transform: scale(0.33); 12 | ` 13 | 14 | export default Wrapper 15 | -------------------------------------------------------------------------------- /packages/emotion/src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import createEmotion from 'create-emotion' 3 | 4 | const context = typeof global !== 'undefined' ? global : {} 5 | 6 | export const { 7 | flush, 8 | hydrate, 9 | cx, 10 | merge, 11 | getRegisteredStyles, 12 | injectGlobal, 13 | keyframes, 14 | css, 15 | sheet, 16 | caches 17 | } = createEmotion(context) 18 | -------------------------------------------------------------------------------- /test/styleTransform.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const path = require('path') 3 | 4 | module.exports = { 5 | process(src: string, filename: string) { 6 | return ` 7 | if (!global.stylesMocked) global.mockedCssImports = {} 8 | global.mockedCssImports[${JSON.stringify( 9 | path.basename(filename) 10 | )}] = ${JSON.stringify(src)} 11 | ` 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/styles.css: -------------------------------------------------------------------------------- 1 | .initial { 2 | align-items: stretch; 3 | border-width: 0; 4 | border-style: solid; 5 | box-sizing: border-box; 6 | display: flex; 7 | flex-basis: auto; 8 | flex-direction: column; 9 | flex-shrink: 0; 10 | margin: 0; 11 | padding: 0; 12 | position: relative; 13 | min-height: 0; 14 | min-width: 0; 15 | } 16 | -------------------------------------------------------------------------------- /packages/site/src/blocks/styled.example: -------------------------------------------------------------------------------- 1 | const Image = ({ className, src }) => 2 | 3 | const Avatar = styled(Image)` 4 | width: 96px; 5 | height: 96px; 6 | border-radius: 50%; 7 | transition: transform 400ms ease-in-out; 8 | 9 | &:hover { 10 | transform: scale(1.2); 11 | } 12 | ` 13 | 14 | render() 15 | -------------------------------------------------------------------------------- /packages/emotion/test/__snapshots__/label-pattern.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`label pattern input + label styled 1`] = ` 4 | .emotion-0 + label::after { 5 | color: pink; 6 | background: orange; 7 | } 8 | 9 |
10 | 13 | 16 |
17 | `; 18 | -------------------------------------------------------------------------------- /packages/site/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false, 7 | "loose": true, 8 | "targets": { 9 | "uglify": true 10 | } 11 | } 12 | ], 13 | "stage-0", 14 | "react" 15 | ], 16 | "plugins": [ 17 | ["emotion", { "sourceMap": true }], 18 | "transform-class-properties" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/create-emotion/test/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | [ 5 | "env", 6 | { 7 | "loose": true, 8 | "exclude": ["transform-es2015-typeof-symbol"] 9 | } 10 | ], 11 | "react", 12 | "stage-2" 13 | ], 14 | "plugins": [["../../../babel-plugin-emotion-test", {"paths": ["./packages/create-emotion/test/emotion-instance"]}], "codegen"] 15 | } -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const { jest: lernaAliases } = require('lerna-alias') 2 | 3 | module.exports = { 4 | transform: { 5 | '\\.css$': '/test/styleTransform.js', 6 | '^.+\\.js?$': 'babel-jest' 7 | }, 8 | moduleNameMapper: lernaAliases(), 9 | setupTestFrameworkScriptFile: '/test/testSetup.js', 10 | coveragePathIgnorePatterns: ['/packages/emotion-utils/src/stylis.js'] 11 | } 12 | -------------------------------------------------------------------------------- /test/pretty-css.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { parse, stringify } from 'css' 3 | import typeof { sheet as StyleSheet } from 'emotion' 4 | 5 | export default { 6 | test: (val: any) => val.tags !== undefined && Array.isArray(val.tags), 7 | print(val: StyleSheet, printer: Function) { 8 | return printer( 9 | stringify(parse(val.tags.map(tag => tag.textContent || '').join(''))) 10 | ) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Wrapper/glamor.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { css } from 'glamor' 3 | 4 | const styles = { 5 | position: 'absolute', 6 | transformOrigin: '0 0', 7 | left: '50%', 8 | top: '50%', 9 | width: '10px', 10 | height: '10px', 11 | background: '#eee', 12 | transform: 'scale(0.5)' 13 | } 14 | 15 | export default props =>
{props.children}
16 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/test/macro/babel-macros-register.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | const path = require('path') 3 | require('module-alias').addAliases({ 4 | 'emotion-utils': path.join(__dirname, '../../../emotion-utils/src'), 5 | 'react-emotion/macro': path.join(__dirname, '../../src/macro-styled'), 6 | 'emotion/macro': path.join(__dirname, '../../src/macro') 7 | }) 8 | 9 | module.exports = require('babel-macros') 10 | -------------------------------------------------------------------------------- /test/testSetup.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* eslint-env jest */ 3 | import { createSerializer } from 'jest-emotion' 4 | import * as emotion from 'emotion' 5 | import Enzyme from 'enzyme' 6 | import Adapter from 'enzyme-adapter-react-16' 7 | import prettyCSS from './pretty-css' 8 | 9 | expect.addSnapshotSerializer(createSerializer(emotion)) 10 | 11 | expect.addSnapshotSerializer(prettyCSS) 12 | 13 | Enzyme.configure({ adapter: new Adapter() }) 14 | -------------------------------------------------------------------------------- /packages/site/src/blocks/theming.example: -------------------------------------------------------------------------------- 1 | const theme = { 2 | borderRadius: '50%', 3 | borderColor: '#BF67AD' 4 | } 5 | 6 | const Avatar = styled('img')` 7 | width: 96px; 8 | height: 96px; 9 | border-radius: ${props => props.theme.borderRadius}; 10 | border: 1px solid ${props => props.theme.borderColor}; 11 | ` 12 | 13 | render( 14 | 15 | 16 | 17 | ) 18 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/css-modules.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import classnames from 'classnames' 3 | import React from 'react' 4 | import styles from './styles.css' 5 | 6 | class View extends React.Component { 7 | render() { 8 | const props = this.props 9 | return ( 10 |
11 | ) 12 | } 13 | } 14 | 15 | export default View 16 | -------------------------------------------------------------------------------- /docs/with-props.md: -------------------------------------------------------------------------------- 1 | ## Usage with recompose's withProps 2 | 3 | You can pass additional props to your components using recompose's `withProps` higher-order component. 4 | 5 | **[`withProps` documentation](https://github.com/acdlite/recompose/blob/master/docs/API.md#withprops)** 6 | 7 | ```js 8 | import withProps from 'recompose/withProps' 9 | 10 | const RedPasswordInput = withProps({ type: 'password' })(styled('input')` 11 | background-color: red; 12 | `); 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/emotion.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion/macro' 2 | 3 | const View = styled('div')` 4 | align-items: stretch; 5 | border-width: 0; 6 | border-style: solid; 7 | box-sizing: border-box; 8 | display: flex; 9 | flex-basis: auto; 10 | flex-direction: column; 11 | flex-shrink: 0; 12 | margin: 0; 13 | padding: 0; 14 | position: relative; 15 | min-height: 0; 16 | min-width: 0; 17 | ` 18 | 19 | export default View 20 | -------------------------------------------------------------------------------- /packages/emotion/test/__snapshots__/sheet.dom.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`sheet .speedy throws when a rule has already been inserted 1`] = `"cannot change speedy now"`; 4 | 5 | exports[`sheet inject method throws if the sheet is already injected 1`] = `"already injected!"`; 6 | 7 | exports[`sheet tags 1`] = ` 8 | Array [ 9 | , 15 | ] 16 | `; 17 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.2.0", 3 | "changelog": { 4 | "repo": "emotion-js/emotion", 5 | "labels": { 6 | "Tag: Breaking Change": ":boom: Breaking Change", 7 | "Tag: Enhancement": ":rocket: Enhancement", 8 | "Tag: Bug Fix": ":bug: Bug Fix", 9 | "Tag: Documentation": ":memo: Documentation", 10 | "Tag: Internal": ":house: Internal" 11 | } 12 | }, 13 | "version": "9.0.0-1", 14 | "npmClient": "yarn", 15 | "useWorkspaces": true 16 | } 17 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/styled-components.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const View = styled.div` 4 | align-items: stretch; 5 | border-width: 0; 6 | border-style: solid; 7 | box-sizing: border-box; 8 | display: flex; 9 | flex-basis: auto; 10 | flex-direction: column; 11 | flex-shrink: 0; 12 | margin: 0; 13 | padding: 0; 14 | position: relative; 15 | min-height: 0; 16 | min-width: 0; 17 | ` 18 | 19 | export default View 20 | -------------------------------------------------------------------------------- /packages/emotion/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es2015", 5 | "strict": true, 6 | "allowSyntheticDefaultImports": true, 7 | "moduleResolution": "node", 8 | "jsx": "react", 9 | "lib": ["es6"], 10 | "noImplicitAny": true, 11 | "noImplicitThis": true, 12 | "strictNullChecks": true, 13 | "strictFunctionTypes": true 14 | }, 15 | "include": [ 16 | "./*.ts", 17 | "./*.tsx" 18 | ] 19 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "8" 5 | 6 | script: npm run test 7 | 8 | before_install: 9 | - curl -o- -L https://yarnpkg.com/install.sh | bash 10 | - export PATH="$HOME/.yarn/bin:$PATH" 11 | 12 | install: yarn install --frozen-lockfile 13 | 14 | before_script: 15 | - npm run bootstrap 16 | 17 | after_success: 18 | - cat ./coverage/lcov.info | ./node_modules/codecov/bin/codecov 19 | 20 | cache: 21 | yarn: true 22 | directories: 23 | - node_modules 24 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/glamorous.js: -------------------------------------------------------------------------------- 1 | import glamorous from 'glamorous' 2 | 3 | const View = glamorous.div({ 4 | alignItems: 'stretch', 5 | borderWidth: 0, 6 | borderStyle: 'solid', 7 | boxSizing: 'border-box', 8 | display: 'flex', 9 | flexBasis: 'auto', 10 | flexDirection: 'column', 11 | flexShrink: 0, 12 | margin: 0, 13 | padding: 0, 14 | position: 'relative', 15 | // fix flexbox bugs 16 | minHeight: 0, 17 | minWidth: 0 18 | }) 19 | 20 | export default View 21 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/emotion-obj.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion/macro' 2 | 3 | const View = styled.div({ 4 | alignItems: 'stretch', 5 | borderWidth: 0, 6 | borderStyle: 'solid', 7 | boxSizing: 'border-box', 8 | display: 'flex', 9 | flexBasis: 'auto', 10 | flexDirection: 'column', 11 | flexShrink: 0, 12 | margin: 0, 13 | padding: 0, 14 | position: 'relative', 15 | // fix flexbox bugs 16 | minHeight: 0, 17 | minWidth: 0 18 | }) 19 | 20 | export default View 21 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/test/macro/inject-global.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { injectGlobal, sheet } from 'emotion/macro' 3 | 4 | test('injectGlobal', () => { 5 | injectGlobal` 6 | html { 7 | background: pink; 8 | } 9 | html.active { 10 | background: red; 11 | } 12 | ` 13 | 14 | const color = 'yellow' 15 | injectGlobal` 16 | body { 17 | color: ${color}; 18 | margin: 0; 19 | padding: 0; 20 | } 21 | ` 22 | expect(sheet).toMatchSnapshot() 23 | }) 24 | -------------------------------------------------------------------------------- /packages/react-emotion/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strict": true, 7 | "allowSyntheticDefaultImports": true, 8 | "moduleResolution": "node", 9 | "jsx": "react", 10 | "lib": ["es6"], 11 | "noImplicitAny": true, 12 | "noImplicitThis": true, 13 | "strictNullChecks": true, 14 | "strictFunctionTypes": true 15 | }, 16 | "include": [ 17 | "./*.ts", 18 | "./*.tsx" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/emotion-theming/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es2015", 5 | "declaration": true, 6 | "strict": true, 7 | "allowSyntheticDefaultImports": true, 8 | "moduleResolution": "node", 9 | "jsx": "react", 10 | "lib": ["es6"], 11 | "noImplicitAny": true, 12 | "noImplicitThis": true, 13 | "strictNullChecks": true, 14 | "strictFunctionTypes": true 15 | }, 16 | "include": [ 17 | "./*.ts", 18 | "./*.tsx" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Dot/emotion.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion/macro' 2 | 3 | const Dot = styled('div')` 4 | position: absolute; 5 | text-align: center; 6 | cursor: pointer; 7 | width: 0; 8 | height: 0; 9 | left: ${p => p.x + 'px'}; 10 | top: ${p => p.y + 'px'}; 11 | border-style: solid; 12 | border-width: ${({ size: s }) => `0 ${s / 2}px ${s / 2}px ${s / 2}px`}; 13 | border-color: ${({ color }) => 14 | `transparent transparent ${color} transparent`}; 15 | ` 16 | 17 | export default Dot 18 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/styles.css: -------------------------------------------------------------------------------- 1 | .outer { 2 | padding: 4px; 3 | } 4 | 5 | .row { 6 | flex-direction: row; 7 | } 8 | 9 | .color0 { 10 | background-color: #222; 11 | } 12 | 13 | .color1 { 14 | background-color: #666; 15 | } 16 | 17 | .color2 { 18 | background-color: #999; 19 | } 20 | 21 | .color3 { 22 | background-color: blue; 23 | } 24 | 25 | .color4 { 26 | background-color: orange; 27 | } 28 | 29 | .color5 { 30 | background-color: red; 31 | } 32 | 33 | .fixed { 34 | width: 20px; 35 | height: 20px; 36 | } 37 | -------------------------------------------------------------------------------- /packages/benchmarks/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | These benchmarks test how fast various css-in-js libraries render with react components. They do not necessarily represent how fast a css-in-js library will be in the real world and are used by emotion to stop performance regressions in render performance/caching. 4 | 5 | To run these benchmarks run `npm run benchmark` in the root directory. These benchmarks should generally be run on Travis and not locally. 6 | 7 | These benchmarks are a modified version of [react-native-web's benchmarks](https://github.com/necolas/react-native-web/tree/master/benchmarks). -------------------------------------------------------------------------------- /packages/benchmarks/tests/renderDeepTree.js: -------------------------------------------------------------------------------- 1 | import createRenderBenchmark from '../createRenderBenchmark' 2 | import NestedTree from '../src/components/NestedTree' 3 | import React from 'react' 4 | 5 | const renderDeepTree = (label, components) => 6 | createRenderBenchmark({ 7 | name: `Deep tree [${label}]`, 8 | runs: 20, 9 | getElement() { 10 | return ( 11 | 18 | ) 19 | } 20 | }) 21 | 22 | export default renderDeepTree 23 | -------------------------------------------------------------------------------- /packages/site/src/blocks/keyframes.example: -------------------------------------------------------------------------------- 1 | const bounce = keyframes` 2 | from, 20%, 53%, 80%, to { 3 | transform: translate3d(0,0,0); 4 | } 5 | 6 | 40%, 43% { 7 | transform: translate3d(0, -30px, 0); 8 | } 9 | 10 | 70% { 11 | transform: translate3d(0, -15px, 0); 12 | } 13 | 14 | 90% { 15 | transform: translate3d(0,-4px,0); 16 | } 17 | ` 18 | 19 | const Avatar = styled('img')` 20 | width: 96px; 21 | height: 96px; 22 | border-radius: 50%; 23 | animation: ${bounce} 1s ease infinite; 24 | transform-origin: center bottom; 25 | ` 26 | 27 | render() 28 | -------------------------------------------------------------------------------- /packages/site/src/index.tpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | emotion - The Next Generation of CSS-in-JS 8 | 9 | 10 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /packages/benchmarks/tests/renderWideTree.js: -------------------------------------------------------------------------------- 1 | import createRenderBenchmark from '../createRenderBenchmark' 2 | import NestedTree from '../src/components/NestedTree' 3 | import React from 'react' 4 | 5 | const renderWideTree = (label, components) => 6 | createRenderBenchmark({ 7 | name: `Wide tree [${label}]`, 8 | runs: 20, 9 | getElement() { 10 | return ( 11 | 18 | ) 19 | } 20 | }) 21 | 22 | export default renderWideTree 23 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/css-modules.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import classnames from 'classnames' 3 | import React from 'react' 4 | import View from '../View/css-modules' 5 | import styles from './styles.css' 6 | 7 | const Box = ({ 8 | color, 9 | fixed = false, 10 | layout = 'column', 11 | outer = false, 12 | ...other 13 | }) => ( 14 | 22 | ) 23 | 24 | export default Box 25 | -------------------------------------------------------------------------------- /packages/site/src/blocks/css.example: -------------------------------------------------------------------------------- 1 | const flexCenter = css` 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | ` 6 | 7 | render( 8 |
28 | 29 |
30 | ) 31 | -------------------------------------------------------------------------------- /docs/webpack.md: -------------------------------------------------------------------------------- 1 | ## Usage with Webpack 2 | 3 | #### Bundling [extracted CSS](https://github.com/emotion-js/emotion/blob/master/docs/extract-static.md) 4 | 5 | ```javascript 6 | { 7 | test: /emotion\.css$/, 8 | // extract a css bundle file for production 9 | use: PROD 10 | ? ExtractTextPlugin.extract({ 11 | fallback: 'style-loader', 12 | use: { 13 | loader: 'css-loader', 14 | options: { 15 | sourceMap: true, 16 | modules: true 17 | } 18 | } 19 | }) 20 | // extract css into a style tag 21 | : ['style-loader', 'css-loader'] 22 | }, 23 | ``` 24 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Dot/glamor.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { css } from 'glamor' 3 | 4 | export default ({ size, x, y, children, color }) => ( 5 |
21 | {children} 22 |
23 | ) 24 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "loose": true, 7 | "exclude": ["transform-es2015-typeof-symbol"] 8 | } 9 | ], 10 | "stage-0", 11 | "react", 12 | "flow" 13 | ], 14 | "plugins": ["codegen"], 15 | "env": { 16 | "test": { 17 | "presets": [ 18 | "flow", 19 | [ 20 | "env", 21 | { 22 | "loose": true, 23 | "exclude": ["transform-es2015-typeof-symbol"] 24 | } 25 | ], 26 | "react", 27 | "stage-2" 28 | ], 29 | "plugins": ["./babel-plugin-emotion-test", "codegen"] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/benchmarks/createRenderBenchmark.js: -------------------------------------------------------------------------------- 1 | import benchmark from './benchmark' 2 | import ReactDOM from 'react-dom' 3 | 4 | const node = document.querySelector('.root') 5 | 6 | const createRenderBenchmark = ({ 7 | description, 8 | getElement, 9 | name, 10 | runs, 11 | flush 12 | }) => () => { 13 | const setup = () => {} 14 | const teardown = () => { 15 | ReactDOM.unmountComponentAtNode(node) 16 | } 17 | 18 | return benchmark({ 19 | name, 20 | description, 21 | runs, 22 | setup, 23 | teardown, 24 | task: () => { 25 | ReactDOM.render(getElement(), node) 26 | } 27 | }) 28 | } 29 | 30 | export default createRenderBenchmark 31 | -------------------------------------------------------------------------------- /packages/create-emotion-server/src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Emotion } from 'create-emotion' 3 | import createExtractCritical from './extract-critical' 4 | import createRenderStylesToString from './inline' 5 | import createRenderStylesToStream from './stream' 6 | 7 | module.exports = function(emotion: Emotion) { 8 | const nonceString = 9 | emotion.caches.nonce !== undefined ? ` nonce="${emotion.caches.nonce}"` : '' 10 | return { 11 | extractCritical: createExtractCritical(emotion), 12 | renderStylesToString: createRenderStylesToString(emotion, nonceString), 13 | renderStylesToNodeStream: createRenderStylesToStream(emotion, nonceString) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/emotion/test/label-pattern.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'react-emotion' 3 | import renderer from 'react-test-renderer' 4 | import { flush } from 'emotion' 5 | 6 | describe('label pattern', () => { 7 | afterEach(() => flush()) 8 | 9 | test('input + label styled', () => { 10 | const Input = styled.input` 11 | & + label::after { 12 | color: pink; 13 | background: orange; 14 | } 15 | ` 16 | 17 | const tree = renderer 18 | .create( 19 |
20 | 21 | 22 |
23 | ) 24 | .toJSON() 25 | 26 | expect(tree).toMatchSnapshot() 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /docs/inject-global.md: -------------------------------------------------------------------------------- 1 | ## Inject Global 2 | 3 | Sometimes it's useful to insert global css like resets or font faces. `injectGlobal` can be used for this. 4 | 5 | ```jsx 6 | import { injectGlobal } from 'emotion' 7 | 8 | injectGlobal` 9 | * { 10 | box-sizing: border-box; 11 | } 12 | @font-face { 13 | font-family: 'Patrick Hand SC'; 14 | font-style: normal; 15 | font-weight: 400; 16 | src: local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2'); 17 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; 18 | } 19 | ` 20 | ``` 21 | -------------------------------------------------------------------------------- /packages/create-emotion/test/instance.test.js: -------------------------------------------------------------------------------- 1 | import createEmotion from 'create-emotion' 2 | import { container, css, sheet } from './emotion-instance' 3 | 4 | describe('general instance tests', () => { 5 | test('inserts style tags into container', () => { 6 | css` 7 | display: flex; 8 | ` 9 | sheet.tags.forEach(tag => { 10 | expect(tag.getAttribute('data-emotion')).toBe('some-key') 11 | expect(tag.getAttribute('nonce')).toBe('some-nonce') 12 | expect(tag.parentNode).toBe(container) 13 | }) 14 | }) 15 | test('throws with invalid key', () => { 16 | expect(() => { 17 | createEmotion({}, { key: 'css1' }) 18 | }).toThrowErrorMatchingSnapshot() 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | - [Node.js](http://nodejs.org/) >= v7 must be installed. 4 | 5 | - [Yarn](https://yarnpkg.com/en/docs/install) 6 | 7 | ## Installation 8 | 9 | - Running `yarn` in the module's root directory will install everything you need for development. 10 | - Run `lerna bootstrap` in the module's root directory 11 | 12 | ## Running Tests 13 | 14 | - `yarn test` will run the tests once. 15 | 16 | - `yarn test:coverage` will run the tests and produce a coverage report in `coverage/`. 17 | 18 | - `yarn test:watch` will run the tests on every change. 19 | 20 | ## Building 21 | 22 | - `yarn build` will build the module for publishing to npm. 23 | 24 | - `yarn clean` will delete built resources. 25 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/emotion-css.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import { css } from 'emotion' 3 | import React from 'react' 4 | 5 | class View extends React.Component { 6 | render() { 7 | const { style, ...other } = this.props 8 | return
9 | } 10 | } 11 | 12 | const viewStyle = { 13 | alignItems: 'stretch', 14 | borderWidth: 0, 15 | borderStyle: 'solid', 16 | boxSizing: 'border-box', 17 | display: 'flex', 18 | flexBasis: 'auto', 19 | flexDirection: 'column', 20 | flexShrink: 0, 21 | margin: 0, 22 | padding: 0, 23 | position: 'relative', 24 | // fix flexbox bugs 25 | minHeight: 0, 26 | minWidth: 0 27 | } 28 | 29 | export default View 30 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/View/glamor.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import { css } from 'glamor' 3 | import React from 'react' 4 | 5 | class View extends React.Component { 6 | render() { 7 | const { style, ...other } = this.props 8 | return
9 | } 10 | } 11 | 12 | const viewStyle = { 13 | alignItems: 'stretch', 14 | borderWidth: 0, 15 | borderStyle: 'solid', 16 | boxSizing: 'border-box', 17 | display: 'flex', 18 | flexBasis: 'auto', 19 | flexDirection: 'column', 20 | flexShrink: 0, 21 | margin: 0, 22 | padding: 0, 23 | position: 'relative', 24 | // fix flexbox bugs 25 | minHeight: 0, 26 | minWidth: 0 27 | } 28 | 29 | export default View 30 | -------------------------------------------------------------------------------- /packages/site/src/blocks/object-styles.example: -------------------------------------------------------------------------------- 1 | const imageStyles = css({ 2 | width: 96, 3 | height: 96 4 | }) 5 | 6 | const fakeBlue = css([ 7 | { 8 | color: 'blue' 9 | } 10 | ]) 11 | 12 | const red = css([ 13 | { 14 | color: 'red' 15 | } 16 | ]) 17 | 18 | const blue = css([ 19 | red, 20 | { 21 | color: 'blue' 22 | } 23 | ]) 24 | 25 | const prettyStyles = css([ 26 | { 27 | borderRadius: '50%', 28 | transition: 'transform 400ms ease-in-out', 29 | ':hover': { 30 | transform: 'scale(1.2)' 31 | } 32 | }, 33 | { border: '3px solid currentColor' } 34 | ]) 35 | 36 | const Avatar = styled('img')` 37 | ${prettyStyles}; 38 | ${imageStyles}; 39 | ${blue}; 40 | ` 41 | 42 | render() 43 | -------------------------------------------------------------------------------- /packages/create-emotion-server/README.md: -------------------------------------------------------------------------------- 1 | # create-emotion-server 2 | 3 | > Create Server-Side-Rendering APIs for emotion instances 4 | 5 | `create-emotion-styled` allows you create various APIs for Server-Side Rendering with instances of emotion. This is **only** needed if you use a custom instance of emotion from `create-emotion` and you want to do Server-Side Rendering. 6 | 7 | ```jsx 8 | import createEmotionServer from 'create-emotion-server' 9 | import * as emotion from 'my-emotion-instance' 10 | 11 | export const { 12 | extractCritical, 13 | renderStylesToString, 14 | renderStylesToNodeStream 15 | } = createEmotionServer(emotion) 16 | ``` 17 | 18 | [All of emotion's SSR APIs are documented in their own doc.](https://github.com/emotion-js/emotion/blob/master/docs/ssr.md) -------------------------------------------------------------------------------- /packages/create-emotion-styled/README.md: -------------------------------------------------------------------------------- 1 | # create-emotion-styled 2 | 3 | > Create the styled API with emotion for React-like libraries 4 | 5 | `create-emotion-styled` allows you to use the `styled` API with instances of emotion. This is **only** needed if you use a custom instance of emotion from `create-emotion` and you want to use the `styled` API. `create-emotion-styled` accepts an instance of emotion from `create-emotion` and a React-like view library. 6 | 7 | 8 | ```jsx 9 | import React from 'react' 10 | import * as emotion from 'my-emotion-instance' 11 | import createEmotionStyled from 'create-emotion-styled' 12 | 13 | export default createEmotionStyled(emotion, React) 14 | 15 | // Exporting emotion isn't required but generally recommended 16 | export * from 'my-emotion-instance' 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/glamorous.js: -------------------------------------------------------------------------------- 1 | import glamorous from 'glamorous' 2 | import View from '../View/glamorous' 3 | 4 | const getColor = color => { 5 | switch (color) { 6 | case 0: 7 | return '#222' 8 | case 1: 9 | return '#666' 10 | case 2: 11 | return '#999' 12 | case 3: 13 | return 'blue' 14 | case 4: 15 | return 'orange' 16 | case 5: 17 | return 'red' 18 | default: 19 | return 'transparent' 20 | } 21 | } 22 | 23 | const Box = glamorous(View)(props => ({ 24 | flexDirection: props.layout === 'column' ? 'column' : 'row', 25 | padding: props.outer ? 4 : 0, 26 | height: props.fixed ? 20 : 'auto', 27 | width: props.fixed ? 20 : 'auto', 28 | backgroundColor: getColor(props.color) 29 | })) 30 | 31 | export default Box 32 | -------------------------------------------------------------------------------- /flow-typed/npm/jest-glamor-react_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 22afe792d07ce86b99954c5d2a83c46e 2 | // flow-typed version: <>/jest-glamor-react_v^3.1.1/flow_v0.59.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'jest-glamor-react' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | import type {JestSnapshotSerializer} from 'jest' 17 | 18 | 19 | interface GlamorStyleSheet { 20 | tags: Array; 21 | } 22 | declare module 'jest-glamor-react' { 23 | declare module.exports: JestSnapshotSerializer & (sheet: GlamorStyleSheet) => JestSnapshotSerializer 24 | } 25 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/emotion-obj.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion/macro' 2 | import View from '../View/emotion-obj' 3 | 4 | const getColor = color => { 5 | switch (color) { 6 | case 0: 7 | return '#222' 8 | case 1: 9 | return '#666' 10 | case 2: 11 | return '#999' 12 | case 3: 13 | return 'blue' 14 | case 4: 15 | return 'orange' 16 | case 5: 17 | return 'red' 18 | default: 19 | return 'transparent' 20 | } 21 | } 22 | 23 | const Box = styled(View)(props => ({ 24 | flexDirection: props.layout === 'column' ? 'column' : 'row', 25 | padding: props.outer ? 4 : 0, 26 | height: props.fixed ? 20 : 'auto', 27 | width: props.fixed ? 20 : 'auto', 28 | backgroundColor: getColor(props.color) 29 | })) 30 | 31 | export default Box 32 | -------------------------------------------------------------------------------- /packages/emotion/test/__snapshots__/component-selector.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`component selector should be converted to use the emotion target className 1`] = ` 4 | .emotion-2 .emotion-1 { 5 | color: red; 6 | } 7 | 8 | .emotion-0 { 9 | color: blue; 10 | } 11 | 12 |
15 |
18 |
19 | `; 20 | 21 | exports[`component selector should be converted to use the emotion target className 2`] = ` 22 | ".css-jww4zs .e42j9n60 { 23 | color: red; 24 | } 25 | 26 | .css-14ksm7b { 27 | color: blue; 28 | }" 29 | `; 30 | 31 | exports[`component selector should throw if the missing the static targeting property 1`] = `"Component selectors can only be used in conjunction with babel-plugin-emotion."`; 32 | -------------------------------------------------------------------------------- /docs/instances.md: -------------------------------------------------------------------------------- 1 | # Instances 2 | 3 | emotion allows creating custom instances of emotion to provide special options. Instances are created with the [`create-emotion`](https://github.com/emotion-js/emotion/tree/master/packages/create-emotion), [`create-emotion-styled`](https://github.com/emotion-js/emotion/tree/master/packages/create-emotion-styled) and [`create-emotion-server`](https://github.com/emotion-js/emotion/tree/master/packages/create-emotion-server) packages which create instances of `emotion`, `react-emotion`/`preact-emotion` and `emotion-server` respectively. They are documented in their own respective READMEs linked above. 4 | 5 | The instances' and primary instance's paths should be added as options to `babel-plugin-emotion` [as shown in `babel-plugin-emotion`'s README](https://github.com/emotion-js/emotion/tree/master/packages/babel-plugin-emotion#instances). -------------------------------------------------------------------------------- /docs/theming.md: -------------------------------------------------------------------------------- 1 | ## Theming 2 | 3 | Themes are provided by the library [`emotion-theming`](https://github.com/emotion-js/emotion/tree/master/packages/emotion-theming). 4 | 5 | 6 | ```bash 7 | npm install -S emotion-theming 8 | ``` 9 | 10 | Add `ThemeProvider` to the top level of your app and access the theme with `props.theme` in a styled component. The api is laid out in detail [in the documentation](https://github.com/emotion-js/emotion/tree/master/packages/emotion-theming/README.md#api). 11 | 12 | ```jsx 13 | import styled from 'react-emotion' 14 | import { ThemeProvider } from 'emotion-theming' 15 | 16 | const H1 = styled(Heading)` 17 | color: ${p => p.theme.purple}; 18 | ` 19 | 20 | 21 | const App = () => ( 22 | 23 |

24 | emotion 25 |

26 |
27 | ) 28 | ``` 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/emotion.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion/macro' 2 | import View from '../View/emotion' 3 | 4 | const getColor = color => { 5 | switch (color) { 6 | case 0: 7 | return '#222' 8 | case 1: 9 | return '#666' 10 | case 2: 11 | return '#999' 12 | case 3: 13 | return 'blue' 14 | case 4: 15 | return 'orange' 16 | case 5: 17 | return 'red' 18 | default: 19 | return 'transparent' 20 | } 21 | } 22 | 23 | const Box = styled(View)` 24 | flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')}; 25 | padding: ${props => (props.outer ? '4px' : '0')}; 26 | height: ${props => (props.fixed ? '20px' : 'auto')}; 27 | width: ${props => (props.fixed ? '20px' : 'auto')}; 28 | background-color: ${props => getColor(props.color)}; 29 | ` 30 | 31 | export default Box 32 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/styled-components.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | import View from '../View/styled-components' 3 | 4 | const getColor = color => { 5 | switch (color) { 6 | case 0: 7 | return '#222' 8 | case 1: 9 | return '#666' 10 | case 2: 11 | return '#999' 12 | case 3: 13 | return 'blue' 14 | case 4: 15 | return 'orange' 16 | case 5: 17 | return 'red' 18 | default: 19 | return 'transparent' 20 | } 21 | } 22 | 23 | const Box = styled(View)` 24 | flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')}; 25 | padding: ${props => (props.outer ? '4px' : '0')}; 26 | height: ${props => (props.fixed ? '20px' : 'auto')}; 27 | width: ${props => (props.fixed ? '20px' : 'auto')}; 28 | background-color: ${props => getColor(props.color)}; 29 | ` 30 | 31 | export default Box 32 | -------------------------------------------------------------------------------- /packages/emotion/test/extract/__snapshots__/extract.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`styled basic render nested 1`] = ` 4 |

7 | hello world 8 |

9 | `; 10 | 11 | exports[`styled className prop on styled 1`] = ` 12 |

15 | hello world 16 |

17 | `; 18 | 19 | exports[`styled no dynamic 1`] = ` 20 |

23 | hello world 24 |

25 | `; 26 | 27 | exports[`styled writes the correct css 1`] = ` 28 | ".css-dae0kw{font-size:12px;} 29 | .css-s9f816{font-size:20px;}.css-s9f816 span{color:blue;}.css-s9f816 span:hover{color:green;}.css-s9f816 span:hover:after{content:'after';} 30 | .css-mdajr1{font-size:20px;} 31 | html{background:pink;} 32 | .css-14yvnlz{font-family:sans-serif;color:yellow;background-color:purple;}" 33 | `; 34 | -------------------------------------------------------------------------------- /packages/emotion-theming/types/index.d.ts: -------------------------------------------------------------------------------- 1 | // TypeScript Version: 2.3 2 | import { ComponentClass, SFC } from "react"; 3 | 4 | export type OptionalThemeProps = Props & { theme?: Theme }; 5 | 6 | export interface ThemeProviderProps { 7 | theme: Partial | ((theme: Theme) => Theme); 8 | } 9 | 10 | export type ThemeProviderComponent = ComponentClass>; 11 | export const ThemeProvider: ThemeProviderComponent; 12 | 13 | /** 14 | * Inject theme into component 15 | */ 16 | // tslint:disable-next-line:no-unnecessary-generics 17 | export function withTheme(component: ComponentClass | SFC): ComponentClass>; 18 | 19 | export interface EmotionThemingModule { 20 | ThemeProvider: ThemeProviderComponent; 21 | withTheme(component: ComponentClass | SFC): ComponentClass>; 22 | } 23 | -------------------------------------------------------------------------------- /packages/create-emotion-server/src/extract-critical.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Emotion } from 'create-emotion' 3 | 4 | const createExtractCritical = (emotion: Emotion) => (html: string) => { 5 | // parse out ids from html 6 | // reconstruct css/rules/cache to pass 7 | let RGX = new RegExp(`${emotion.caches.key}-([a-zA-Z0-9-]+)`, 'gm') 8 | 9 | let o = { html, ids: [], css: '' } 10 | let match 11 | let ids = {} 12 | while ((match = RGX.exec(html)) !== null) { 13 | if (ids[match[1]] === undefined) { 14 | ids[match[1]] = true 15 | } 16 | } 17 | 18 | o.ids = Object.keys(emotion.caches.inserted).filter(id => { 19 | if ( 20 | (ids[id] === true || 21 | emotion.caches.registered[`${emotion.caches.key}-${id}`] === 22 | undefined) && 23 | emotion.caches.inserted[id] !== true 24 | ) { 25 | o.css += emotion.caches.inserted[id] 26 | return true 27 | } 28 | }) 29 | 30 | return o 31 | } 32 | 33 | export default createExtractCritical 34 | -------------------------------------------------------------------------------- /packages/emotion-theming/src/create-broadcast.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // https://github.com/styled-components/styled-components/blob/e05b3fe247e9d956bcde786cec376e32afb85bca/src/utils/create-broadcast.js 3 | const createBroadcast = (initialState: any) => { 4 | const listeners: { [number]: Function | void } = {} 5 | let id = 0 6 | let state = initialState 7 | 8 | function publish(nextState: any) { 9 | state = nextState 10 | 11 | for (const key in listeners) { 12 | // $FlowFixMe 13 | const listener = listeners[key] 14 | if (listener === undefined) { 15 | continue 16 | } 17 | 18 | listener(state) 19 | } 20 | } 21 | 22 | function subscribe(listener: any) { 23 | const currentId = id 24 | listeners[currentId] = listener 25 | id += 1 26 | listener(state) 27 | return currentId 28 | } 29 | 30 | function unsubscribe(unsubID: number) { 31 | listeners[unsubID] = undefined 32 | } 33 | 34 | return { publish, subscribe, unsubscribe } 35 | } 36 | 37 | export default createBroadcast 38 | -------------------------------------------------------------------------------- /packages/jest-emotion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jest-emotion", 3 | "version": "9.0.0-1", 4 | "description": "Jest utilities for emotion", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "scripts": { 11 | "build": "npm-run-all clean babel", 12 | "babel": "babel src -d lib", 13 | "watch": "babel src -d lib --watch", 14 | "clean": "rimraf lib" 15 | }, 16 | "dependencies": { 17 | "css": "^2.2.1" 18 | }, 19 | "devDependencies": { 20 | "babel-cli": "^6.24.1", 21 | "npm-run-all": "^4.0.2", 22 | "rimraf": "^2.6.1" 23 | }, 24 | "author": "Kye Hohenberger", 25 | "homepage": "https://emotion.sh", 26 | "license": "MIT", 27 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/jest-emotion-react", 28 | "keywords": [ 29 | "styles", 30 | "emotion", 31 | "react", 32 | "css", 33 | "css-in-js", 34 | "jest", 35 | "snapshot" 36 | ], 37 | "bugs": { 38 | "url": "https://github.com/emotion-js/emotion/issues" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/emotion-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emotion-utils", 3 | "version": "9.0.0-0", 4 | "description": "Shared utilities used by emotion, The Next Generation of CSS-in-JS.", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "files": [ 8 | "src", 9 | "dist" 10 | ], 11 | "scripts": { 12 | "build": "npm-run-all clean rollup", 13 | "clean": "rimraf dist", 14 | "watch": "rollup -c ../../rollup.config.js --watch", 15 | "rollup": "rollup -c ../../rollup.config.js" 16 | }, 17 | "author": "Kye Hohenberger", 18 | "homepage": "https://emotion.sh", 19 | "license": "MIT", 20 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/emotion-utils", 21 | "keywords": [ 22 | "styles", 23 | "emotion", 24 | "react", 25 | "css", 26 | "css-in-js" 27 | ], 28 | "bugs": { 29 | "url": "https://github.com/emotion-js/emotion/issues" 30 | }, 31 | "devDependencies": { 32 | "npm-run-all": "^4.0.2", 33 | "rimraf": "^2.6.1", 34 | "rollup": "^0.51.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/glamor.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import React from 'react' 3 | import View from '../View/glamor' 4 | 5 | const Box = ({ 6 | color, 7 | fixed = false, 8 | layout = 'column', 9 | outer = false, 10 | ...other 11 | }) => ( 12 | 21 | ) 22 | 23 | const styles = { 24 | outer: { 25 | padding: 4 26 | }, 27 | row: { 28 | flexDirection: 'row' 29 | }, 30 | color0: { 31 | backgroundColor: '#222' 32 | }, 33 | color1: { 34 | backgroundColor: '#666' 35 | }, 36 | color2: { 37 | backgroundColor: '#999' 38 | }, 39 | color3: { 40 | backgroundColor: 'blue' 41 | }, 42 | color4: { 43 | backgroundColor: 'orange' 44 | }, 45 | color5: { 46 | backgroundColor: 'red' 47 | }, 48 | fixed: { 49 | width: 20, 50 | height: 20 51 | } 52 | } 53 | 54 | export default Box 55 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/Box/emotion-css.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import React from 'react' 3 | import View from '../View/emotion-css' 4 | 5 | const Box = ({ 6 | color, 7 | fixed = false, 8 | layout = 'column', 9 | outer = false, 10 | ...other 11 | }) => ( 12 | 21 | ) 22 | 23 | const styles = { 24 | outer: { 25 | padding: 4 26 | }, 27 | row: { 28 | flexDirection: 'row' 29 | }, 30 | color0: { 31 | backgroundColor: '#222' 32 | }, 33 | color1: { 34 | backgroundColor: '#666' 35 | }, 36 | color2: { 37 | backgroundColor: '#999' 38 | }, 39 | color3: { 40 | backgroundColor: 'blue' 41 | }, 42 | color4: { 43 | backgroundColor: 'orange' 44 | }, 45 | color5: { 46 | backgroundColor: 'red' 47 | }, 48 | fixed: { 49 | width: 20, 50 | height: 20 51 | } 52 | } 53 | 54 | export default Box 55 | -------------------------------------------------------------------------------- /packages/jest-emotion/src/replace-class-names.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | function defaultClassNameReplacer(className, index) { 3 | return `emotion-${index}` 4 | } 5 | 6 | export type ClassNameReplacer = (className: string, index: number) => string 7 | 8 | const componentSelectorClassNamePattern = /\.e[a-zA-Z0-9-]+[0-9]+/ 9 | 10 | export const replaceClassNames = ( 11 | selectors: Array, 12 | styles: string, 13 | code: string, 14 | key: string, 15 | replacer: ClassNameReplacer = defaultClassNameReplacer 16 | ) => { 17 | let index = 0 18 | const classRegex = new RegExp(`^\\.${key}-([a-zA-Z0-9-]+)`) 19 | 20 | return selectors.reduce((acc, className) => { 21 | if ( 22 | classRegex.test(className) || 23 | componentSelectorClassNamePattern.test(className) 24 | ) { 25 | const escapedRegex = new RegExp( 26 | className.replace('.', '').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'), 27 | 'g' 28 | ) 29 | return acc.replace(escapedRegex, replacer(className, index++)) 30 | } 31 | return acc 32 | }, `${styles}${styles ? '\n\n' : ''}${code}`) 33 | } 34 | -------------------------------------------------------------------------------- /packages/benchmarks/src/components/NestedTree.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | class DeepTree extends Component { 4 | render() { 5 | const { breadth, components, depth, id, wrap } = this.props 6 | const { Box } = components 7 | 8 | let result = ( 9 | 15 | {depth === 0 && ( 16 | 17 | )} 18 | {depth !== 0 && 19 | Array.from({ length: breadth }).map((el, i) => ( 20 | 28 | ))} 29 | 30 | ) 31 | for (let i = 0; i < wrap; i++) { 32 | result = {result} 33 | } 34 | return result 35 | } 36 | } 37 | 38 | export default DeepTree 39 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [version] 2 | 0.61.0 3 | 4 | [ignore] 5 | .*/node_modules/styled-components/.* 6 | 7 | 8 | [include] 9 | 10 | [libs] 11 | 12 | [options] 13 | suppress_comment=.*\\$FlowFixMe 14 | module.name_mapper='^\(emotion-utils\)$' -> '/packages/\1/src' 15 | module.name_mapper='^\(create-emotion\)$' -> '/packages/\1/src' 16 | module.name_mapper='^\(create-emotion-styled\)$' -> '/packages/\1/src' 17 | module.name_mapper='^\(react-emotion\)$' -> '/packages/\1/src' 18 | module.name_mapper='^\(preact-emotion\)$' -> '/packages/\1/src' 19 | module.name_mapper='^\(emotion\)$' -> '/packages/\1/src' 20 | module.name_mapper='^\(babel-plugin-emotion\)$' -> '/packages/\1/src' 21 | module.name_mapper='^\(emotion-theming\)$' -> '/packages/\1/src' 22 | module.name_mapper='^\(emotion-server\)$' -> '/packages/\1/src' 23 | module.name_mapper='^\(create-emotion-server\)$' -> '/packages/\1/src' 24 | module.name_mapper='^\(jest-emotion\)$' -> '/packages/\1/src' 25 | unsafe.enable_getters_and_setters=true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Kye Hohenberger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/nested.md: -------------------------------------------------------------------------------- 1 | ## Nested Selectors 2 | 3 | Sometimes you will want to nest selectors to target only elements inside the current class or React component. Here is an example of a simple element selector nested in the class generated with `css`: 4 | 5 | ```jsx 6 | import { css } from 'emotion'; 7 | 8 | const paragraph = css` 9 | color: gray; 10 | 11 | a { 12 | border-bottom: 1px solid currentColor; 13 | } 14 | ` 15 | ``` 16 | 17 | You can use `&` to select the current class nested in another element: 18 | 19 | ```jsx 20 | const paragraph = css` 21 | color: gray; 22 | 23 | header & { 24 | color: black; 25 | } 26 | ` 27 | ``` 28 | 29 | To nest a class selector using the class generated with `css` you can interpolate it but be aware than emotion merges styles from `css` together when composing so that class name may not always be there: 30 | 31 | ```jsx 32 | const link = css` 33 | color: hotpink; 34 | ` 35 | 36 | const paragraph = css` 37 | color: gray; 38 | 39 | .${link} { 40 | border-bottom: 1px solid currentColor; 41 | } 42 | ` 43 | ``` 44 | 45 | The result of `css` is a class name _without_ the dot (`.`), so we prepended it. 46 | -------------------------------------------------------------------------------- /packages/benchmarks/send-results.js: -------------------------------------------------------------------------------- 1 | const { createApolloFetch } = require('apollo-fetch') 2 | 3 | const { GRAPH_TOKEN } = process.env 4 | 5 | const client = createApolloFetch({ 6 | uri: 'https://api.graph.cool/simple/v1/cj83urcdm0u420180bqw9w4mu' 7 | }) 8 | 9 | client.use(({ request, options }, next) => { 10 | if (!options.headers) { 11 | options.headers = {} // Create the headers object if needed. 12 | } 13 | options.headers['Authorization'] = 'Bearer ' + GRAPH_TOKEN || '' 14 | 15 | next() 16 | }) 17 | 18 | module.exports = function sendResult(vars) { 19 | return client({ 20 | query: ` 21 | mutation createRunAndResults($branch: String, $pr: String, $commit: String, $commitMessage: String, $results: [RunresultsResult!]) { 22 | createRun(results: $results, branch: $branch, pr: $pr, commit: $commit, commitMessage: $commitMessage) { 23 | createdAt 24 | branch 25 | pr 26 | commit 27 | commitMessage 28 | results { 29 | name 30 | duration 31 | type 32 | } 33 | } 34 | } 35 | `, 36 | variables: vars 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /packages/benchmarks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "benchmarks", 3 | "private": true, 4 | "dependencies": { 5 | "apollo-fetch": "^0.6.0", 6 | "classnames": "^2.2.5", 7 | "d3-scale-chromatic": "^1.1.1", 8 | "emotion": "^9.0.0-1", 9 | "glamor": "^2.20.37", 10 | "glamorous": "^4.1.0", 11 | "marky": "^1.2.0", 12 | "postcss": "^6.0.8", 13 | "react": "^16.0.0", 14 | "react-dom": "^16.0.0", 15 | "react-emotion": "^9.0.0-1", 16 | "styled-components": "^2.2.1" 17 | }, 18 | "devDependencies": { 19 | "babel-loader": "^7.1.1", 20 | "babel-macros": "^1.0.2", 21 | "babel-polyfill": "^6.26.0", 22 | "cli-chart": "^0.3.1", 23 | "cli-table": "^0.3.1", 24 | "css-loader": "^0.28.4", 25 | "html-webpack-plugin": "^2.30.1", 26 | "puppeteer": "^0.10.1", 27 | "react-addons-perf": "^15.6.0-rc.1", 28 | "serve": "^6.0.6", 29 | "style-loader": "^0.18.2", 30 | "webpack": "^3.4.1", 31 | "webpack-bundle-analyzer": "^2.9.0" 32 | }, 33 | "scripts": { 34 | "build:benchmark": "webpack", 35 | "benchmark": "npm run build:benchmark && node run-headless.js" 36 | }, 37 | "version": "9.0.0-1" 38 | } 39 | -------------------------------------------------------------------------------- /docs/keyframes.md: -------------------------------------------------------------------------------- 1 | ## Keyframes 2 | 3 | If you need more control over an animation, you can use `keyframes` with the same JS interpolation as `css`. 4 | The `keyframes` function takes in the css keyframes definition and returns the animation name so that you can include it in other styles. This is similar to how `css` takes in styles and returns the className that you can use to apply the styles. 5 | 6 | ```jsx 7 | import { keyframes, css } from 'emotion' 8 | import styled from 'react-emotion' 9 | 10 | const bounceHeight = 30; 11 | 12 | // This returns a animation 13 | const bounce = keyframes` 14 | from, 20%, 53%, 80%, to { 15 | transform: translate3d(0,0,0); 16 | } 17 | 18 | 40%, 43% { 19 | transform: translate3d(0, -${bounceHeight}px, 0); 20 | } 21 | 22 | 70% { 23 | transform: translate3d(0, -${bounceHeight / 2}px, 0); 24 | } 25 | 26 | 90% { 27 | transform: translate3d(0, -${bounceHeight / 4}px, 0); 28 | } 29 | ` 30 | 31 | // You can use them in styled components or anything else 32 | const AnimatedDiv = styled.div` 33 | animation: ${bounce} 1s ease infinite; 34 | ` 35 | 36 | const slowBounce = css` 37 | animation: ${bounce} 5s ease 1; 38 | ` 39 | ``` 40 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/test/__snapshots__/fs.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`babel plugin fs creates and writes to the css file when it does not exist 1`] = `".css-1yfv4zm{margin:12px 48px;color:#ffffff;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;color:blue;name:class;}"`; 4 | 5 | exports[`babel plugin fs creates and writes to the css file when it does not exist 2`] = ` 6 | "require(\\"./fs.test.emotion.css\\"); 7 | 8 | \\"css-1yfv4zm\\";" 9 | `; 10 | 11 | exports[`babel plugin fs does not write to the css file when it is the same as is already written 1`] = ` 12 | "require(\\"./fs.test.emotion.css\\"); 13 | 14 | \\"css-1yfv4zm\\";" 15 | `; 16 | 17 | exports[`babel plugin fs writes to the css file when it does exist 1`] = `".css-1yfv4zm{margin:12px 48px;color:#ffffff;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;color:blue;name:class;}"`; 18 | 19 | exports[`babel plugin fs writes to the css file when it does exist 2`] = ` 20 | "require(\\"./fs.test.emotion.css\\"); 21 | 22 | \\"css-1yfv4zm\\";" 23 | `; 24 | -------------------------------------------------------------------------------- /packages/emotion/test/component-selector.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'react-emotion' 3 | import renderer from 'react-test-renderer' 4 | import { css, flush, sheet } from 'emotion' 5 | import { TARGET_KEY } from 'emotion-utils' 6 | 7 | describe('component selector', () => { 8 | afterEach(() => flush()) 9 | 10 | test('should be converted to use the emotion target className', () => { 11 | const FakeComponent = styled.div` 12 | color: blue; 13 | ` 14 | 15 | const cls2 = css` 16 | ${FakeComponent} { 17 | color: red; 18 | } 19 | ` 20 | const tree = renderer 21 | .create( 22 |
23 | 24 |
25 | ) 26 | .toJSON() 27 | expect(tree).toMatchSnapshot() 28 | expect(sheet).toMatchSnapshot() 29 | }) 30 | 31 | test('should throw if the missing the static targeting property', () => { 32 | const FakeComponent = styled.div` 33 | color: blue; 34 | ` 35 | 36 | delete FakeComponent[TARGET_KEY] 37 | 38 | expect(() => { 39 | css` 40 | ${FakeComponent} { 41 | color: red; 42 | } 43 | ` 44 | }).toThrowErrorMatchingSnapshot() 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /packages/create-emotion-styled/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-emotion-styled", 3 | "version": "9.0.0-0", 4 | "description": "The styled API for emotion", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "types": "types/index.d.ts", 8 | "files": [ 9 | "src", 10 | "dist" 11 | ], 12 | "scripts": { 13 | "build": "npm-run-all clean rollup", 14 | "clean": "rimraf dist", 15 | "rollup": "rollup -c ../../rollup.config.js", 16 | "watch": "rollup -c ../../rollup.config.js --watch" 17 | }, 18 | "dependencies": { 19 | "emotion-utils": "^9.0.0-0" 20 | }, 21 | "peerDependencies": { 22 | "prop-types": ">= 15" 23 | }, 24 | "devDependencies": { 25 | "npm-run-all": "^4.0.2", 26 | "prop-types": "^15.6.0", 27 | "rimraf": "^2.6.1", 28 | "rollup": "^0.51.3" 29 | }, 30 | "author": "Kye Hohenberger", 31 | "homepage": "https://emotion.sh", 32 | "license": "MIT", 33 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/create-emotion-styled", 34 | "keywords": [ 35 | "styles", 36 | "emotion", 37 | "react", 38 | "css", 39 | "css-in-js" 40 | ], 41 | "bugs": { 42 | "url": "https://github.com/emotion-js/emotion/issues" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/emotion-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emotion-server", 3 | "version": "9.0.0-1", 4 | "description": "SSR and style extraction tooling for emotion, The Next Generation of CSS-in-JS.", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "scripts": { 11 | "build": "npm-run-all clean babel", 12 | "babel": "babel src -d lib", 13 | "watch": "babel src -d lib --watch", 14 | "clean": "rimraf lib" 15 | }, 16 | "dependencies": { 17 | "create-emotion-server": "^9.0.0-1" 18 | }, 19 | "peerDependencies": { 20 | "emotion": "^9.0.0-1" 21 | }, 22 | "devDependencies": { 23 | "babel-cli": "^6.24.1", 24 | "emotion": "^9.0.0-1", 25 | "npm-run-all": "^4.0.2", 26 | "react-emotion": "^9.0.0-1", 27 | "rimraf": "^2.6.1" 28 | }, 29 | "author": "Kye Hohenberger", 30 | "homepage": "https://emotion.sh", 31 | "license": "MIT", 32 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/emotion-server", 33 | "keywords": [ 34 | "styles", 35 | "emotion", 36 | "react", 37 | "css", 38 | "css-in-js", 39 | "ssr", 40 | "server-side-rendering" 41 | ], 42 | "bugs": { 43 | "url": "https://github.com/emotion-js/emotion/issues" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | **What**: 19 | 20 | 21 | **Why**: 22 | 23 | 24 | **How**: 25 | 26 | 27 | **Checklist**: 28 | 29 | 30 | - [ ] Documentation 31 | - [ ] Tests 32 | - [ ] Code complete 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | ## Install 2 | 3 | ```bash 4 | npm install --save emotion react-emotion babel-plugin-emotion 5 | ``` 6 | 7 | All `emotion` APIs are available from the `react-emotion` package. 8 | 9 | ```javascript 10 | import styled, { css, injectGlobal } from 'react-emotion'; 11 | ``` 12 | 13 | ### .babelrc 14 | 15 | [More information on the babel plugin](babel.md) 16 | 17 | _`"emotion"` must be the **first plugin** in your babel config `plugins` list._ 18 | 19 | Takes optional configs: 20 | - [extractStatic](babel.md#Static-Extraction) _{boolean}_ 21 | - [sourceMap](babel.md#Static-Extraction) _{boolean}_ 22 | ```json 23 | { 24 | "plugins": [ 25 | ["emotion"] 26 | ] 27 | } 28 | ``` 29 | If using Babel's env option emotion must also be first for each environment. 30 | ```json 31 | { 32 | "env": { 33 | "production": { 34 | "plugins": [ 35 | "emotion", 36 | [...all other babel plugins...] 37 | ] 38 | } 39 | }, 40 | "plugins": ["emotion"] 41 | } 42 | ``` 43 | ### Preact 44 | 45 | Import `preact-emotion` instead of `react-emotion` and use it the same way you would with React. 46 | 47 | ```jsx 48 | import styled from 'preact-emotion' 49 | 50 | const SomeComponent = styled.div` 51 | display: flex; 52 | ` 53 | ``` 54 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/src/source-map.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { SourceMapGenerator } from 'source-map' 3 | import convert from 'convert-source-map' 4 | import type { EmotionBabelPluginPass } from './index' 5 | import type { BabelFile } from 'babel-flow-types' 6 | 7 | function getGeneratorOpts(file) { 8 | return file.opts.generatorOpts ? file.opts.generatorOpts : file.opts 9 | } 10 | 11 | export function makeSourceMapGenerator(file: BabelFile) { 12 | const generatorOpts = getGeneratorOpts(file) 13 | const filename = generatorOpts.sourceFileName 14 | const generator = new SourceMapGenerator({ 15 | file: filename, 16 | sourceRoot: generatorOpts.sourceRoot 17 | }) 18 | 19 | generator.setSourceContent(filename, file.code) 20 | return generator 21 | } 22 | 23 | export function addSourceMaps( 24 | offset: { line: number, column: number }, 25 | state: EmotionBabelPluginPass 26 | ) { 27 | const generator = makeSourceMapGenerator(state.file) 28 | const generatorOpts = getGeneratorOpts(state.file) 29 | generator.addMapping({ 30 | generated: { 31 | line: 1, 32 | column: 0 33 | }, 34 | source: generatorOpts.sourceFileName, 35 | original: offset 36 | }) 37 | return '\n' + convert.fromObject(generator).toComment({ multiline: true }) 38 | } 39 | -------------------------------------------------------------------------------- /docs/source-maps.md: -------------------------------------------------------------------------------- 1 | ## Source Maps 2 | 3 | **babel plugin required** 4 | 5 | emotion supports source maps for styles authored in javascript. 6 | 7 |
8 | 9 | ![source-map-demo](https://user-images.githubusercontent.com/662750/30778580-78fbeae4-a096-11e7-82e1-120b6984e875.gif) 10 | 11 |
12 | 13 | Required For Source Maps: 14 | 1. `babel-plugin-emotion` must be in your Babel setup. [[documentation]](https://github.com/emotion-js/emotion/blob/master/docs/install.md) 15 | 2. `process.env.NODE_ENV` must be any value except `"production"` 16 | 17 | --- 18 | 19 | **We do not advise using sourceMaps in production. The source maps can add significant size to your bundle.** 20 | 21 | **Babel setup** 22 | 23 | **.babelrc** 24 | ```json 25 | { 26 | "plugins": [ 27 | ["emotion", { "sourceMap": true }] 28 | ] 29 | } 30 | ``` 31 | 32 | **Recommended Setup** 33 | 34 | Use [Babel's `env` property](https://babeljs.io/docs/usage/babelrc/#env-option) and only set source maps in your development environment. 35 | 36 | **.babelrc** 37 | ```json 38 | { 39 | "env": { 40 | "production": { 41 | "plugins": [["emotion", { "sourceMap": false }]] 42 | }, 43 | "development": { 44 | "plugins": [["emotion", { "sourceMap": true }]] 45 | } 46 | } 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /packages/create-emotion-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-emotion-server", 3 | "version": "9.0.0-1", 4 | "description": "SSR and style extraction tooling for emotion, The Next Generation of CSS-in-JS.", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "scripts": { 11 | "build": "npm-run-all clean babel", 12 | "babel": "babel src -d lib", 13 | "watch": "babel src -d lib --watch", 14 | "clean": "rimraf lib" 15 | }, 16 | "dependencies": { 17 | "emotion-utils": "^9.0.0-0", 18 | "html-tokenize": "^2.0.0", 19 | "multipipe": "^1.0.2", 20 | "through": "^2.3.8" 21 | }, 22 | "devDependencies": { 23 | "babel-cli": "^6.24.1", 24 | "emotion": "^9.0.0-1", 25 | "npm-run-all": "^4.0.2", 26 | "react-emotion": "^9.0.0-1", 27 | "rimraf": "^2.6.1" 28 | }, 29 | "author": "Kye Hohenberger", 30 | "homepage": "https://emotion.sh", 31 | "license": "MIT", 32 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/create-emotion-server", 33 | "keywords": [ 34 | "styles", 35 | "emotion", 36 | "react", 37 | "css", 38 | "css-in-js", 39 | "ssr", 40 | "server-side-rendering" 41 | ], 42 | "bugs": { 43 | "url": "https://github.com/emotion-js/emotion/issues" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/emotion/test/__snapshots__/cx.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`cx all types 1`] = ` 4 | .emotion-0 { 5 | font-size: 20px; 6 | background: green; 7 | font-size: 20px; 8 | background: darkorange; 9 | font-size: 20px; 10 | background: darkgreen; 11 | } 12 | 13 |
16 | `; 17 | 18 | exports[`cx fun fun functions 1`] = ` 19 | .emotion-0 { 20 | font-size: 20px; 21 | background: green; 22 | font-size: 20px; 23 | background: darkorange; 24 | font-size: 20px; 25 | background: darkgreen; 26 | } 27 | 28 |
31 | `; 32 | 33 | exports[`cx merge 2 1`] = ` 34 | .emotion-0 { 35 | font-size: 20px; 36 | background: green; 37 | } 38 | 39 |
42 | `; 43 | 44 | exports[`cx merge 3 1`] = ` 45 | .emotion-0 { 46 | font-size: 20px; 47 | background: green; 48 | font-size: 20px; 49 | background: blue; 50 | } 51 | 52 |
55 | `; 56 | 57 | exports[`cx merge 4 1`] = ` 58 | .emotion-0 { 59 | font-size: 20px; 60 | background: green; 61 | font-size: 20px; 62 | background: blue; 63 | } 64 | 65 |
68 | `; 69 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 13 | 14 | - `emotion` version: 15 | - `react` version: 16 | 17 | Relevant code. 18 | 19 | ```javascript 20 | 21 | ``` 22 | 23 | 24 | What you did: 25 | 26 | 27 | 28 | What happened: 29 | 30 | 36 | 37 | Reproduction: 38 | 39 | 40 | 46 | Problem description: 47 | 48 | 49 | 50 | Suggested solution: 51 | -------------------------------------------------------------------------------- /docs/composition.md: -------------------------------------------------------------------------------- 1 | ## Composition 2 | 3 | `css` can be used in emotion to build styles that can compose with other styles. 4 | 5 | ```javascript 6 | import { css } from 'emotion' 7 | import styled from 'react-emotion' 8 | 9 | // Define a class 10 | const flexCenter = css` 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | ` 15 | 16 | // interpolate it where you want to apply the styles 17 | const flexCenterClass = css` 18 | ${flexCenter}; 19 | flex-direction: column; 20 | ` 21 | 22 | // You can also use it in styled and the css prop 23 | const FlexCenterComponent = styled.div` 24 | ${flexCenter}; 25 | ` 26 | 27 | 28 | const flexWrap = props => css` 29 | flex-wrap: ${props.wrap ? 'wrap' : 'nowrap'}; 30 | ` 31 | 32 | // You can compose with multiple classes 33 | const ColumnCenteredComponent = styled.div` 34 | ${flexCenter}; 35 | ${flexWrap}; 36 | ` 37 | 38 | // Composition can be very powerful. For example, styles are expanded where you interpolate, 39 | // so the following class has flex-direction: column because ${flexCenterClass} is interpolated 40 | // after flex-direction: row 41 | const stillColumn = css` 42 | flex-direction: row; 43 | ${flexCenterClass} 44 | ` 45 | 46 | // Nested composing is supported 47 | const cls = css` 48 | & .flex { 49 | ${flexCenter}; 50 | } 51 | ` 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /packages/create-emotion/test/emotion-instance.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import createEmotion from 'create-emotion' 3 | import createEmotionStyled from 'create-emotion-styled' 4 | import createEmotionServer from 'create-emotion-server' 5 | import { transform } from 'cssjanus' 6 | import React from 'react' 7 | 8 | function stylisPlugin(context, content) { 9 | if (context === 2) { 10 | return transform(content) 11 | } 12 | } 13 | 14 | export const container = document.createElement('div') 15 | 16 | // $FlowFixMe 17 | document.head.appendChild(container) 18 | 19 | const emotion = createEmotion( 20 | // don't use a global so the options aren't cached 21 | {}, 22 | { 23 | stylisPlugins: stylisPlugin, 24 | prefix: (key, value) => { 25 | if (key === 'display' && value === 'flex') { 26 | return false 27 | } 28 | return true 29 | }, 30 | nonce: 'some-nonce', 31 | key: 'some-key', 32 | container 33 | } 34 | ) 35 | 36 | export const { 37 | flush, 38 | hydrate, 39 | cx, 40 | merge, 41 | getRegisteredStyles, 42 | injectGlobal, 43 | keyframes, 44 | css, 45 | sheet, 46 | caches 47 | } = emotion 48 | 49 | export const { 50 | extractCritical, 51 | renderStylesToString, 52 | renderStylesToNodeStream 53 | } = createEmotionServer(emotion) 54 | 55 | export default createEmotionStyled(emotion, React) 56 | -------------------------------------------------------------------------------- /packages/preact-emotion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preact-emotion", 3 | "version": "9.0.0-1", 4 | "description": "The Next Generation of CSS-in-JS, for Preact projects.", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "files": [ 8 | "dist", 9 | "src", 10 | "macro.js" 11 | ], 12 | "scripts": { 13 | "build": "npm-run-all clean rollup", 14 | "clean": "rimraf dist", 15 | "watch": "rollup -c ../../rollup.config.js --watch", 16 | "rollup": "rollup -c ../../rollup.config.js" 17 | }, 18 | "dependencies": { 19 | "babel-plugin-emotion": "^9.0.0-1", 20 | "create-emotion-styled": "^9.0.0-0" 21 | }, 22 | "peerDependencies": { 23 | "emotion": "^9.0.0-1" 24 | }, 25 | "devDependencies": { 26 | "emotion": "^9.0.0-1", 27 | "npm-run-all": "^4.0.2", 28 | "react-emotion": "^9.0.0-1", 29 | "rimraf": "^2.6.1", 30 | "rollup": "^0.51.3" 31 | }, 32 | "author": "Kye Hohenberger", 33 | "homepage": "https://emotion.sh", 34 | "license": "MIT", 35 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/preact-emotion", 36 | "keywords": [ 37 | "styles", 38 | "emotion", 39 | "react", 40 | "preact", 41 | "css", 42 | "css-in-js" 43 | ], 44 | "bugs": { 45 | "url": "https://github.com/emotion-js/emotion/issues" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/create-emotion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-emotion", 3 | "version": "9.0.0-1", 4 | "description": "The Next Generation of CSS-in-JS.", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "files": [ 8 | "src", 9 | "dist", 10 | "types" 11 | ], 12 | "scripts": { 13 | "build": "npm-run-all clean rollup", 14 | "clean": "rimraf dist", 15 | "rollup": "rollup -c ../../rollup.config.js", 16 | "watch": "rollup -c ../../rollup.config.js --watch" 17 | }, 18 | "dependencies": { 19 | "emotion-utils": "^9.0.0-0", 20 | "stylis": "^3.3.2", 21 | "stylis-rule-sheet": "^0.0.5" 22 | }, 23 | "devDependencies": { 24 | "@types/react": "16.0.16", 25 | "babel-cli": "^6.24.1", 26 | "babel-plugin-transform-define": "^1.3.0", 27 | "cross-env": "^5.0.5", 28 | "dtslint": "^0.2.0", 29 | "npm-run-all": "^4.0.2", 30 | "rimraf": "^2.6.1", 31 | "rollup": "^0.51.3" 32 | }, 33 | "author": "Kye Hohenberger", 34 | "homepage": "https://emotion.sh", 35 | "license": "MIT", 36 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/create-emotion", 37 | "keywords": [ 38 | "styles", 39 | "emotion", 40 | "react", 41 | "css", 42 | "css-in-js" 43 | ], 44 | "bugs": { 45 | "url": "https://github.com/emotion-js/emotion/issues" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /flow-typed/npm/react-test-renderer_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: b39646fcd6b54764b610c38b101a4fdd 2 | // flow-typed version: <>/react-test-renderer_v^16.0.0/flow_v0.59.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'react-test-renderer' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | type TestRendererOptions = { 17 | createNodeMock: (element: React$Element) => any 18 | } 19 | 20 | type ReactTestRendererNode = ReactTestRendererJSON | string 21 | 22 | type ReactTestRendererJSON = {| 23 | type: string, 24 | props: { [propName: string]: any }, 25 | children: null | Array, 26 | $$typeof?: Symbol // Optional because we add it with defineProperty(). 27 | |} 28 | 29 | declare module 'react-test-renderer' { 30 | declare module.exports: { 31 | create: ( 32 | element: React$Element, 33 | options?: TestRendererOptions 34 | ) => { 35 | toJSON: () => ReactTestRendererJSON, 36 | update: (newElement: React$Element) => void, 37 | unmount: () => void, 38 | toTree: () => any, 39 | getInstance: () => any, 40 | root: any 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/babel-plugin-emotion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-emotion", 3 | "version": "9.0.0-1", 4 | "description": "A recommended babel preprocessing plugin for emotion, The Next Generation of CSS-in-JS.", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "src", 8 | "lib" 9 | ], 10 | "scripts": { 11 | "build": "npm-run-all clean babel", 12 | "babel": "babel src -d lib", 13 | "watch": "babel src -d lib --watch", 14 | "clean": "rimraf lib" 15 | }, 16 | "dependencies": { 17 | "@babel/helper-module-imports": "7.0.0-beta.32", 18 | "babel-macros": "^1.2.0", 19 | "babel-plugin-syntax-jsx": "^6.18.0", 20 | "convert-source-map": "^1.5.0", 21 | "emotion-utils": "^9.0.0-0", 22 | "find-root": "^1.1.0", 23 | "source-map": "^0.5.7", 24 | "touch": "^1.0.0" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "7.0.0-beta.32", 28 | "babel-cli": "^6.24.1", 29 | "npm-run-all": "^4.0.2", 30 | "rimraf": "^2.6.1" 31 | }, 32 | "author": "Kye Hohenberger", 33 | "homepage": "https://emotion.sh", 34 | "license": "MIT", 35 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/babel-plugin-emotion", 36 | "keywords": [ 37 | "styles", 38 | "emotion", 39 | "react", 40 | "css", 41 | "css-in-js" 42 | ], 43 | "bugs": { 44 | "url": "https://github.com/emotion-js/emotion/issues" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/emotion-theming/types/tests.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as emotionTheming from '../'; 3 | // tslint:disable-next-line:no-duplicate-imports 4 | import { ThemeProvider, withTheme, EmotionThemingModule } from '../'; 5 | 6 | const theme = { primary: "green", secondary: "white" }; 7 | const CompSFC = (props: { prop: boolean }) =>
; 8 | declare class CompC extends React.Component<{ prop: boolean }> { } 9 | 10 | /** 11 | * Theme Provider with no type 12 | */ 13 | ; 14 | theme} />; 15 | 16 | /** 17 | * withTheme with no type 18 | */ 19 | const ThemedSFC = withTheme(CompSFC); 20 | ; 21 | ; 22 | 23 | const ThemedComp = withTheme(CompC); 24 | ; 25 | ; 26 | 27 | const { ThemeProvider: TypedThemeProvider, withTheme: typedWithTheme } = emotionTheming as EmotionThemingModule; 28 | 29 | ; 30 | ; 31 | ({ primary: theme.primary, secondary: theme.secondary })} />; 32 | 33 | const TypedThemedSFC = typedWithTheme(ThemedSFC); 34 | ; 35 | ; 36 | 37 | const TypedCompSFC = typedWithTheme(CompSFC); 38 | ; 39 | ; 40 | -------------------------------------------------------------------------------- /packages/emotion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emotion", 3 | "version": "9.0.0-1", 4 | "description": "The Next Generation of CSS-in-JS.", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "types": "types/index.d.ts", 8 | "files": [ 9 | "src", 10 | "dist", 11 | "macro.js", 12 | "types" 13 | ], 14 | "scripts": { 15 | "build": "npm-run-all clean rollup", 16 | "test:typescript": "dtslint types", 17 | "clean": "rimraf dist", 18 | "rollup": "rollup -c ../../rollup.config.js", 19 | "watch": "rollup -c ../../rollup.config.js --watch" 20 | }, 21 | "dependencies": { 22 | "babel-plugin-emotion": "^9.0.0-1", 23 | "create-emotion": "^9.0.0-1" 24 | }, 25 | "devDependencies": { 26 | "@types/react": "16.0.16", 27 | "babel-cli": "^6.24.1", 28 | "babel-plugin-transform-define": "^1.3.0", 29 | "cross-env": "^5.0.5", 30 | "dtslint": "^0.2.0", 31 | "npm-run-all": "^4.0.2", 32 | "rimraf": "^2.6.1", 33 | "rollup": "^0.51.3" 34 | }, 35 | "author": "Kye Hohenberger", 36 | "homepage": "https://emotion.sh", 37 | "license": "MIT", 38 | "repository": "https://github.com/emotion-js/emotion/tree/master/packages/emotion", 39 | "keywords": [ 40 | "styles", 41 | "emotion", 42 | "react", 43 | "css", 44 | "css-in-js" 45 | ], 46 | "bugs": { 47 | "url": "https://github.com/emotion-js/emotion/issues" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/emotion/test/__snapshots__/inject-global.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`injectGlobal basic 1`] = ` 4 | "html { 5 | background: pink; 6 | } 7 | 8 | html.active { 9 | background: red; 10 | }" 11 | `; 12 | 13 | exports[`injectGlobal interpolated value 1`] = ` 14 | "body { 15 | color: yellow; 16 | margin: 0; 17 | padding: 0; 18 | }" 19 | `; 20 | 21 | exports[`injectGlobal nested interpolated media query 1`] = ` 22 | "@media (max-width:600px) { 23 | body { 24 | display: -webkit-box; 25 | display: -webkit-flex; 26 | display: -ms-flexbox; 27 | display: flex; 28 | } 29 | }" 30 | `; 31 | 32 | exports[`injectGlobal random interpolation 1`] = ` 33 | ".css-k008qs { 34 | display: -webkit-box; 35 | display: -webkit-flex; 36 | display: -ms-flexbox; 37 | display: flex; 38 | } 39 | 40 | body { 41 | display: -webkit-box; 42 | display: -webkit-flex; 43 | display: -ms-flexbox; 44 | display: flex; 45 | }" 46 | `; 47 | 48 | exports[`injectGlobal with @font-face 1`] = ` 49 | "@font-face { 50 | font-family: 'Patrick Hand SC'; 51 | font-style: normal; 52 | font-weight: 400; 53 | src: local('Patrick Hand SC'),local('PatrickHandSC-Regular'),url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2'); 54 | unicode-range: U+0100-024f,U+1-1eff,U+20a0-20ab,U+20ad-20cf,U+2c60-2c7f,U+A720-A7FF; 55 | }" 56 | `; 57 | -------------------------------------------------------------------------------- /packages/emotion-theming/src/with-theme.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as React from 'react' 3 | import hoistNonReactStatics from 'hoist-non-react-statics' 4 | import { channel, contextTypes } from './utils' 5 | 6 | type Props = { theme: Object } 7 | 8 | const withTheme = (Component: React.ComponentType) => { 9 | const componentName = Component.displayName || Component.name || 'Component' 10 | 11 | class WithTheme extends React.Component<{}, { theme: Object }> { 12 | unsubscribeId: number 13 | componentWillMount() { 14 | const themeContext = this.context[channel] 15 | if (themeContext === undefined) { 16 | // eslint-disable-next-line no-console 17 | console.error( 18 | '[withTheme] Please use ThemeProvider to be able to use withTheme' 19 | ) 20 | return 21 | } 22 | this.unsubscribeId = themeContext.subscribe(theme => { 23 | this.setState({ theme }) 24 | }) 25 | } 26 | 27 | componentWillUnmount() { 28 | if (this.unsubscribeId !== -1) { 29 | this.context[channel].unsubscribe(this.unsubscribeId) 30 | } 31 | } 32 | 33 | render() { 34 | return 35 | } 36 | } 37 | WithTheme.displayName = `WithTheme(${componentName})` 38 | WithTheme.contextTypes = contextTypes 39 | 40 | return hoistNonReactStatics(WithTheme, Component) 41 | } 42 | 43 | export default withTheme 44 | -------------------------------------------------------------------------------- /packages/emotion-utils/src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export const memoize = (fn: string => any) => { 4 | const cache = {} 5 | return (arg: string) => { 6 | if (cache[arg] === undefined) cache[arg] = fn(arg) 7 | return cache[arg] 8 | } 9 | } 10 | 11 | export const STYLES_KEY = '__emotion_styles' 12 | export const TARGET_KEY = '__emotion_target' 13 | 14 | export const unitless: { [string]: 1 } = { 15 | animationIterationCount: 1, 16 | borderImageOutset: 1, 17 | borderImageSlice: 1, 18 | borderImageWidth: 1, 19 | boxFlex: 1, 20 | boxFlexGroup: 1, 21 | boxOrdinalGroup: 1, 22 | columnCount: 1, 23 | columns: 1, 24 | flex: 1, 25 | flexGrow: 1, 26 | flexPositive: 1, 27 | flexShrink: 1, 28 | flexNegative: 1, 29 | flexOrder: 1, 30 | gridRow: 1, 31 | gridRowEnd: 1, 32 | gridRowSpan: 1, 33 | gridRowStart: 1, 34 | gridColumn: 1, 35 | gridColumnEnd: 1, 36 | gridColumnSpan: 1, 37 | gridColumnStart: 1, 38 | fontWeight: 1, 39 | lineClamp: 1, 40 | lineHeight: 1, 41 | opacity: 1, 42 | order: 1, 43 | orphans: 1, 44 | tabSize: 1, 45 | widows: 1, 46 | zIndex: 1, 47 | zoom: 1, 48 | 49 | // SVG-related properties 50 | fillOpacity: 1, 51 | floodOpacity: 1, 52 | stopOpacity: 1, 53 | strokeDasharray: 1, 54 | strokeDashoffset: 1, 55 | strokeMiterlimit: 1, 56 | strokeOpacity: 1, 57 | strokeWidth: 1 58 | } 59 | 60 | export { hashString } from './hash' 61 | export { default as Stylis } from './stylis' 62 | -------------------------------------------------------------------------------- /packages/emotion/test/sheet.dom.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { sheet } from 'emotion' 3 | 4 | describe('sheet', () => { 5 | beforeEach(() => { 6 | sheet.flush() 7 | sheet.inject() 8 | }) 9 | 10 | test('speedy', () => { 11 | expect(sheet.isSpeedy).toBe(false) 12 | sheet.speedy(true) 13 | expect(sheet.isSpeedy).toBe(true) 14 | sheet.speedy(false) 15 | expect(sheet.isSpeedy).toBe(false) 16 | }) 17 | 18 | test('tags', () => { 19 | sheet.speedy(true) 20 | const rule = '.foo { color: blue; }' 21 | sheet.insert(rule) 22 | expect(sheet.tags).toMatchSnapshot() 23 | expect(sheet.tags.length).toBe(1) 24 | }) 25 | 26 | test('flush', () => { 27 | sheet.speedy(true) 28 | sheet.insert('.foo { color: blue; }') 29 | sheet.flush() 30 | expect(sheet.tags.length).toBe(0) 31 | }) 32 | 33 | test('throws', () => { 34 | sheet.speedy(true) 35 | const spy = jest.spyOn(global.console, 'warn') 36 | sheet.insert('.asdfasdf4###112121211{') 37 | expect(spy).toHaveBeenCalled() 38 | }) 39 | 40 | test('inject method throws if the sheet is already injected', () => { 41 | expect(() => { 42 | sheet.inject() 43 | }).toThrowErrorMatchingSnapshot() 44 | }) 45 | test('.speedy throws when a rule has already been inserted', () => { 46 | sheet.insert('.foo { color: blue; }') 47 | expect(() => { 48 | sheet.speedy(true) 49 | }).toThrowErrorMatchingSnapshot() 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /docs/extract-static.md: -------------------------------------------------------------------------------- 1 | ## Extract Static 2 | ###### [requires babel plugin](babel.md) 3 | 4 | Extract styles with no interpolations into external css files. 5 | 6 | While there are some beneficial use cases for `extractStatic`, emotion's inherent performance since version 8 makes the added complexity of this feature somewhat disadvantageous. 7 | 8 | 9 | **does NOT work with object styles** 10 | 11 | **If you want to use dynamic values you must use css variables.** 12 | 13 | ```javascript 14 | const Button = styled('button')` 15 | background-color: var(--bg); 16 | padding: 10px; 17 | ` 18 |