├── no-parser.js ├── .gitignore ├── native ├── index.js └── index.d.ts ├── primitives ├── index.js └── index.d.ts ├── .eslintignore ├── docs ├── api.md ├── flow-support.md ├── security.md ├── theming.md ├── README.md ├── css-we-support.md ├── existing-css.md ├── react-native.md ├── typescript-support.md ├── tagged-template-literals.md └── faq.md ├── flow-typed ├── react-native.js ├── npm │ ├── css-to-react-native_v1.x.x.js │ ├── flow-bin_v0.x.x.js │ ├── supports-color_v3.x.x.js │ ├── mocha_v2.4.x.js │ ├── mocha_v3.1.x.js │ ├── is-plain-object_vx.x.x.js │ ├── babel-preset-react_vx.x.x.js │ ├── babel-preset-latest_vx.x.x.js │ ├── rollup-plugin-flow_vx.x.x.js │ ├── rollup-plugin-uglify_vx.x.x.js │ ├── babel-plugin-external-helpers_vx.x.x.js │ ├── babel-plugin-transform-class-properties_vx.x.x.js │ ├── babel-plugin-transform-flow-strip-types_vx.x.x.js │ ├── babel-plugin-transform-object-rest-spread_vx.x.x.js │ ├── rollup-plugin-visualizer_vx.x.x.js │ ├── babel-plugin-add-module-exports_vx.x.x.js │ ├── rollup_vx.x.x.js │ ├── is-function_vx.x.x.js │ ├── chokidar_vx.x.x.js │ ├── pre-commit_vx.x.x.js │ ├── rollup-plugin-json_vx.x.x.js │ ├── rollup-plugin-replace_vx.x.x.js │ ├── css-to-react-native_vx.x.x.js │ ├── flow-copy-source_vx.x.x.js │ ├── node-watch_vx.x.x.js │ ├── rollup-plugin-inject_vx.x.x.js │ ├── rollup-plugin-node-resolve_vx.x.x.js │ ├── babel-plugin-flow-react-proptypes_vx.x.x.js │ ├── babel-loader_vx.x.x.js │ ├── eslint-plugin-flowtype-errors_vx.x.x.js │ ├── rollup-plugin-babel_vx.x.x.js │ ├── expect_vx.x.x.js │ ├── react-addons-test-utils_v15.x.x.js │ ├── eslint-config-airbnb_vx.x.x.js │ ├── babel-eslint_vx.x.x.js │ ├── rollup-plugin-commonjs_vx.x.x.js │ ├── enzyme_v2.3.x.js │ ├── babel-cli_vx.x.x.js │ └── lint-staged_vx.x.x.js └── fbjs_vx.x.x.js ├── src ├── utils │ ├── isTag.js │ ├── getComponentName.js │ ├── isStyledComponent.js │ ├── interleave.js │ ├── test │ │ ├── generateAlphabeticName.test.js │ │ ├── interleave.test.js │ │ ├── extractCompsFromCSS.test.js │ │ └── flatten.test.js │ ├── generateAlphabeticName.js │ ├── extractCompsFromCSS.js │ ├── stringifyRules.js │ ├── createWarnTooManyClasses.js │ ├── create-broadcast.js │ ├── flatten.js │ └── domElements.js ├── vendor │ ├── postcss │ │ ├── stringify.js │ │ ├── warn-once.js │ │ ├── terminal-highlight.js │ │ ├── parse.js │ │ ├── vendor.js │ │ ├── comment.js │ │ ├── list.js │ │ ├── root.js │ │ ├── declaration.js │ │ ├── rule.js │ │ ├── warning.js │ │ └── at-rule.js │ ├── postcss-safe-parser │ │ ├── parse.js │ │ └── safe-parser.js │ ├── README.md │ ├── glamor │ │ └── hash.js │ └── postcss-nested │ │ └── index.js ├── no-parser │ ├── css.js │ ├── stringifyRules.js │ ├── test │ │ ├── keyframes.test.js │ │ └── basic.test.js │ ├── index.js │ └── flatten.js ├── constructors │ ├── css.js │ ├── test │ │ ├── styled.test.js │ │ ├── keyframes.test.js │ │ └── injectGlobal.test.js │ ├── styled.js │ ├── injectGlobal.js │ ├── keyframes.js │ └── constructWithOptions.js ├── models │ ├── AbstractStyledComponent.js │ ├── StyleSheetManager.js │ ├── ComponentStyle.js │ ├── InlineStyle.js │ ├── ThemeProvider.js │ ├── ServerStyleSheet.js │ └── test │ │ └── ThemeProvider.test.js ├── types.js ├── test │ ├── props.test.js │ ├── overriding.test.js │ ├── css.test.js │ ├── warnTooManyClasses.test.js │ ├── utils.js │ └── expanded-api.test.js ├── primitives │ └── index.js ├── index.js ├── hoc │ └── withTheme.js └── native │ └── index.js ├── .editorconfig ├── .jest.native.json ├── .jest.primitives.json ├── .babelrc ├── .travis.yml ├── typings └── tests │ ├── extend-test.tsx │ ├── native-test.tsx │ ├── hoc-test.tsx │ ├── attrs-test.tsx │ ├── nested-test.tsx │ ├── themed-tests │ ├── mytheme-styled-components.tsx │ ├── with-theme-test.tsx │ └── mytheme-test.tsx │ ├── server-test.tsx │ ├── function-themes-test.tsx │ └── with-component-test.tsx ├── appveyor.yml ├── .flowconfig ├── example ├── example.js ├── index.html ├── devServer.js └── with-perf.html ├── LICENSE ├── .eslintrc ├── .github └── ISSUE_TEMPLATE.md ├── CONTRIBUTING.md ├── tslint.json ├── rollup.config.js ├── dangerfile.js └── CODE_OF_CONDUCT.md /no-parser.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | module.exports = require('./lib/no-parser') 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | npm-debug.log.* 4 | dist 5 | .DS_Store 6 | bundle-stats.html 7 | -------------------------------------------------------------------------------- /native/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable flowtype/require-valid-file-annotation */ 2 | module.exports = require('../lib/native') 3 | -------------------------------------------------------------------------------- /primitives/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable flowtype/require-valid-file-annotation */ 2 | module.exports = require('../lib/primitives') 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/decls/**/*.js 2 | src/vendor/**/*.js 3 | src/test/utils.js 4 | *.test.js 5 | example/ 6 | flow-typed/**/*.js 7 | lib/ 8 | -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://styled-components.com/docs/api), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /docs/flow-support.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/api#flow), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /flow-typed/react-native.js: -------------------------------------------------------------------------------- 1 | declare module 'react-native' { 2 | declare module.exports: { 3 | StyleSheet: { 4 | create: Function 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/security.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/advanced#security), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /docs/theming.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/advanced#theming), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /flow-typed/npm/css-to-react-native_v1.x.x.js: -------------------------------------------------------------------------------- 1 | declare module 'css-to-react-native' { 2 | declare module.exports: ([string, string])[] => { [key:string]: any } 3 | } 4 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs), please update your bookmarks!** 4 | -------------------------------------------------------------------------------- /docs/css-we-support.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/api#supported-css), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /docs/existing-css.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/advanced#existing-css), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /docs/react-native.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/basics#react-native), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /docs/typescript-support.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/api#typescript), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /src/utils/isTag.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Target } from '../types' 3 | 4 | export default function isTag(target: Target)/* : %checks */ { 5 | return typeof target === 'string' 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_size = 2 6 | end_of_line = lf 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /docs/tagged-template-literals.md: -------------------------------------------------------------------------------- 1 | **The documentation has been moved to [styled-components.com](https://www.styled-components.com/docs/advanced#tagged-template-literals), please update your bookmarks!** 2 | -------------------------------------------------------------------------------- /src/vendor/postcss/stringify.js: -------------------------------------------------------------------------------- 1 | import Stringifier from './stringifier'; 2 | 3 | export default function stringify(node, builder) { 4 | let str = new Stringifier(builder); 5 | str.stringify(node); 6 | } 7 | -------------------------------------------------------------------------------- /.jest.native.json: -------------------------------------------------------------------------------- 1 | { 2 | "rootDir": ".", 3 | "globals": { 4 | "__DEV__": true 5 | }, 6 | "testRegex": "./src/native/test/.*.js$", 7 | "preset": "react-native", 8 | "testEnvironment": "jsdom" 9 | } 10 | -------------------------------------------------------------------------------- /src/no-parser/css.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import flatten from './flatten' 3 | import type { Interpolation, RuleSet } from '../types' 4 | 5 | export default (interpolations: Array): RuleSet => flatten(interpolations) 6 | -------------------------------------------------------------------------------- /flow-typed/npm/flow-bin_v0.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 6a5610678d4b01e13bbfbbc62bdaf583 2 | // flow-typed version: 3817bc6980/flow-bin_v0.x.x/flow_>=v0.25.x 3 | 4 | declare module "flow-bin" { 5 | declare module.exports: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/getComponentName.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* eslint-disable no-undef */ 4 | export default function getComponentName(target: ReactClass<*>): string { 5 | return ( 6 | target.displayName || 7 | target.name || 8 | 'Component' 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/vendor/postcss/warn-once.js: -------------------------------------------------------------------------------- 1 | let printed = { }; 2 | 3 | export default function warnOnce(message) { 4 | if ( printed[message] ) return; 5 | printed[message] = true; 6 | 7 | if ( typeof console !== 'undefined' && console.warn ) console.warn(message); 8 | } 9 | -------------------------------------------------------------------------------- /.jest.primitives.json: -------------------------------------------------------------------------------- 1 | { 2 | "rootDir": ".", 3 | "globals": { 4 | "__DEV__": true 5 | }, 6 | "testRegex": "./src/primitives/test/.*.js$", 7 | "moduleFileExtensions": ["ios.js", "js"], 8 | "preset": "react-native", 9 | "testEnvironment": "jsdom" 10 | } 11 | -------------------------------------------------------------------------------- /src/utils/isStyledComponent.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Target } from '../types' 3 | 4 | export default function isStyledComponent(target: Target)/* : %checks */ { 5 | return ( 6 | typeof target === 'function' && 7 | typeof target.styledComponentId === 'string' 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "loose": true }], 4 | "react" 5 | ], 6 | "plugins": [ 7 | "flow-react-proptypes", 8 | "add-module-exports", 9 | "transform-flow-strip-types", 10 | "transform-object-rest-spread", 11 | "transform-class-properties" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/constructors/css.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import interleave from '../utils/interleave' 3 | import flatten from '../utils/flatten' 4 | import type { Interpolation, RuleSet } from '../types' 5 | 6 | export default (strings: Array, ...interpolations: Array): RuleSet => ( 7 | flatten(interleave(strings, interpolations)) 8 | ) 9 | -------------------------------------------------------------------------------- /src/vendor/postcss-safe-parser/parse.js: -------------------------------------------------------------------------------- 1 | import Input from '../postcss/input'; 2 | 3 | import SafeParser from './safe-parser'; 4 | 5 | export default function safeParse(css, opts) { 6 | let input = new Input(css, opts); 7 | 8 | let parser = new SafeParser(input); 9 | parser.tokenize(); 10 | parser.loop(); 11 | 12 | return parser.root; 13 | } 14 | -------------------------------------------------------------------------------- /src/constructors/test/styled.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import styled from '../../index' 3 | import domElements from '../../utils/domElements' 4 | 5 | describe('styled', () => { 6 | it('should have all valid HTML5 elements defined as properties', () => { 7 | domElements.forEach(domElement => { 8 | expect(styled[domElement]).toBeTruthy() 9 | }) 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /src/utils/interleave.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Interpolation } from '../types' 3 | 4 | export default ( 5 | strings: Array, 6 | interpolations: Array, 7 | ): Array => ( 8 | interpolations.reduce((array: Array, interp: Interpolation, i: number) => ( 9 | array.concat(interp, strings[i + 1]) 10 | ), [strings[0]]) 11 | ) 12 | -------------------------------------------------------------------------------- /src/utils/test/generateAlphabeticName.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import generateAlphabeticName from '../generateAlphabeticName'; 3 | 4 | describe('generateAlphabeticName', () => { 5 | it('should create alphabetic names for number input data', () => { 6 | expect(generateAlphabeticName(1000000000)).toEqual('cGNYzm'); 7 | expect(generateAlphabeticName(2000000000)).toEqual('fnBWYy'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: trusty 3 | node_js: 4 | - 7 5 | - 6 6 | script: 7 | - node --version 8 | - yarn --version 9 | - yarn run danger run -- --verbose 10 | - yarn run flow 11 | - yarn run lint && yarn run typescript && yarn run tslint && yarn run test 12 | notifications: 13 | email: 14 | on_failure: change 15 | cache: 16 | yarn: true 17 | bundler: true 18 | directories: 19 | - node_modules 20 | -------------------------------------------------------------------------------- /flow-typed/npm/supports-color_v3.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: a46c83d9d0179a257b49b111f3fd3c95 2 | // flow-typed version: 94e9f7e0a4/supports-color_v3.x.x/flow_>=v0.28.x 3 | 4 | declare module 'supports-color' { 5 | declare module.exports: false | 6 | { level: 1, hasBasic: true, has256: false, has16m: false } | 7 | { level: 2, hasBasic: true, has256: true, has16m: false } | 8 | { level: 3, hasBasic: true, has256: true, has16m: true }; 9 | } 10 | -------------------------------------------------------------------------------- /typings/tests/extend-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled from "../.."; 4 | 5 | const Button = styled.button` 6 | color: palevioletred; 7 | font-size: 1em; 8 | margin: 1em; 9 | padding: 0.25em 1em; 10 | border: 2px solid palevioletred; 11 | border-radius: 3px; 12 | `; 13 | 14 | // We're extending Button with some extra styles 15 | const TomatoButton = Button.extend` 16 | color: tomato; 17 | border-color: tomato; 18 | `; 19 | -------------------------------------------------------------------------------- /typings/tests/native-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import styled from "../../native"; 3 | 4 | const StyledView = styled.View` 5 | background-color: papayawhip; 6 | `; 7 | 8 | const StyledText = styled.Text` 9 | color: palevioletred; 10 | `; 11 | 12 | class MyReactNativeComponent extends React.Component<{}, {}> { 13 | render() { 14 | return 15 | Hello World! 16 | ; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /typings/tests/hoc-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled from "../.."; 4 | import { css, keyframes, ThemeProvider, injectGlobal, withTheme, ThemeProps } from "../.."; 5 | 6 | class MyComponent extends React.Component, {}> { 7 | render() { 8 | const { theme } = this.props; 9 | 10 | console.log("Current theme: ", theme); 11 | 12 | return

Hello

; 13 | } 14 | } 15 | 16 | export default withTheme(MyComponent); 17 | -------------------------------------------------------------------------------- /src/constructors/styled.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Target } from '../types' 3 | import domElements from '../utils/domElements' 4 | 5 | export default (styledComponent: Function, constructWithOptions: Function) => { 6 | const styled = (tag: Target) => constructWithOptions(styledComponent, tag) 7 | 8 | // Shorthands for all valid HTML Elements 9 | domElements.forEach(domElement => { 10 | styled[domElement] = styled(domElement) 11 | }) 12 | 13 | return styled 14 | } 15 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | skip_tags: true 3 | build: off 4 | clone_depth: 1 5 | shallow_clone: true 6 | matrix: 7 | fast_finish: true 8 | environment: 9 | matrix: 10 | - nodejs_version: 7 11 | - nodejs_version: 6 12 | init: 13 | - git config --global core.autocrlf input 14 | install: 15 | - ps: Install-Product node $env:nodejs_version x64 16 | - set CI=true 17 | - yarn 18 | cache: 19 | - '%LOCALAPPDATA%/Yarn' 20 | test_script: 21 | - node --version 22 | - yarn --version 23 | - yarn run flow 24 | - yarn run lint && npm run test 25 | -------------------------------------------------------------------------------- /typings/tests/attrs-test.tsx: -------------------------------------------------------------------------------- 1 | import styled from "../.."; 2 | 3 | const Input = styled.input.attrs({ 4 | // we can define static props 5 | type: "password", 6 | 7 | // or we can define dynamic ones 8 | margin: (props: any) => props.size as string || "1em", 9 | padding: (props: any) => props.size as string || "1em" 10 | })` 11 | color: palevioletred; 12 | font-size: 1em; 13 | border: 2px solid palevioletred; 14 | border-radius: 3px; 15 | 16 | /* here we use the dynamically computed props */ 17 | margin: ${(props) => props.margin}; 18 | padding: ${(props) => props.padding}; 19 | `; 20 | -------------------------------------------------------------------------------- /src/utils/generateAlphabeticName.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('') 3 | const charsLength = chars.length 4 | 5 | /* Some high number, usually 9-digit base-10. Map it to base-😎 */ 6 | const generateAlphabeticName = (code: number): string => { 7 | let name = '' 8 | let x 9 | 10 | for ( 11 | x = code; 12 | x > charsLength; 13 | x = Math.floor(x / chars.length) 14 | ) { 15 | name = chars[x % charsLength] + name 16 | } 17 | 18 | return chars[x % charsLength] + name 19 | } 20 | 21 | export default generateAlphabeticName 22 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/flow-remove-types/.* 3 | .*/node_modules/react-native/.* 4 | .*/node_modules/rollup-plugin-flow/.* 5 | .*/node_modules/animated/.* 6 | .*/node_modules/react-sketchapp/.* 7 | .*/node_modules/react-native-web/.* 8 | .*/node_modules/babel-plugin-transform-react-remove-prop-types/.* 9 | .*/dist/.* 10 | .*/lib/.* 11 | .*/node_modules/babel-plugin-flow-react-proptypes/src/__test__/.* 12 | .*/dangerfile.js 13 | 14 | [include] 15 | 16 | [libs] 17 | 18 | [options] 19 | suppress_comment=.*\\$FlowFixMe 20 | suppress_comment=.*\\$FlowInvalidInputTest 21 | unsafe.enable_getters_and_setters=true 22 | -------------------------------------------------------------------------------- /src/models/AbstractStyledComponent.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { Component } from 'react' 3 | import PropTypes from 'prop-types' 4 | 5 | import { CHANNEL } from './ThemeProvider' 6 | import StyleSheet, { CONTEXT_KEY } from './StyleSheet' 7 | 8 | export default class AbstractStyledComponent extends Component { 9 | static isPrototypeOf: Function 10 | state: { 11 | theme: any, 12 | generatedClassName?: string, 13 | generatedStyles?: any 14 | } 15 | unsubscribe: () => void 16 | } 17 | 18 | AbstractStyledComponent.contextTypes = { 19 | [CHANNEL]: PropTypes.func, 20 | [CONTEXT_KEY]: PropTypes.instanceOf(StyleSheet), 21 | } 22 | -------------------------------------------------------------------------------- /typings/tests/nested-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled, { css } from "../.."; 4 | 5 | const Link = styled.a` 6 | color: red; 7 | `; 8 | 9 | const AlternativeLink = styled.a` 10 | color: blue; 11 | `; 12 | 13 | const freeStyles = css` 14 | background-color: black; 15 | color: white; 16 | ${Link} { 17 | color: blue; 18 | } 19 | `; 20 | 21 | const Article = styled.section` 22 | color: red; 23 | ${freeStyles} 24 | & > ${Link} { 25 | color: green; 26 | } 27 | ${p => p.theme.useAlternativeLink ? AlternativeLink : Link} { 28 | color: black 29 | } 30 | `; 31 | -------------------------------------------------------------------------------- /src/no-parser/stringifyRules.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Interpolation } from '../types' 3 | 4 | const stringifyRules = ( 5 | rules: Array, 6 | selector: ?string, 7 | prefix: ?string, 8 | ): string => ( 9 | rules 10 | .reduce((str: string, partial: Interpolation, index: number): string => ( 11 | str + 12 | // NOTE: This is to not prefix keyframes with the animation name 13 | ((index > 0 || !prefix) && selector ? selector : '') + 14 | ( 15 | (partial && Array.isArray(partial)) ? 16 | partial.join('') : 17 | partial.toString() 18 | ) 19 | ), '') 20 | ) 21 | 22 | export default stringifyRules 23 | -------------------------------------------------------------------------------- /typings/tests/themed-tests/mytheme-styled-components.tsx: -------------------------------------------------------------------------------- 1 | import * as styledComponents from "../../.."; 2 | import { ThemedStyledComponentsModule } from "../../.."; 3 | 4 | export interface MyTheme { 5 | primaryColor: string; 6 | backgroundColor: string; 7 | defaultMargin: number; 8 | } 9 | 10 | const { 11 | default: styled, 12 | css, 13 | injectGlobal, 14 | keyframes, 15 | withTheme, 16 | ThemeProvider, 17 | } = styledComponents as ThemedStyledComponentsModule; 18 | 19 | interface ThemeProps { 20 | theme?: MyTheme; 21 | } 22 | 23 | export default styled; 24 | export { css, injectGlobal, keyframes, withTheme, ThemeProvider, ThemeProps }; 25 | -------------------------------------------------------------------------------- /typings/tests/themed-tests/with-theme-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled, { css, keyframes, ThemeProvider, injectGlobal, withTheme, MyTheme, ThemeProps } from "./mytheme-styled-components"; 4 | 5 | interface MyComponentProps extends ThemeProps { 6 | text: string; 7 | } 8 | 9 | class MyComponent extends React.Component { 10 | render() { 11 | return

{this.props.theme}

; 12 | } 13 | } 14 | 15 | const theme: MyTheme = { 16 | primaryColor: "red", 17 | backgroundColor: "blue", 18 | defaultMargin: 10, 19 | }; 20 | 21 | const text = "hey"; 22 | 23 | const MyThemedComponent = withTheme(MyComponent); 24 | 25 | ; 26 | -------------------------------------------------------------------------------- /src/constructors/injectGlobal.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import hashStr from '../vendor/glamor/hash' 3 | import StyleSheet from '../models/StyleSheet' 4 | import type { Interpolation, Stringifier } from '../types' 5 | 6 | export default (stringifyRules: Stringifier, css: Function) => { 7 | const injectGlobal = (strings: Array, ...interpolations: Array) => { 8 | const rules = css(strings, ...interpolations) 9 | const hash = hashStr(JSON.stringify(rules)) 10 | 11 | const componentId = `sc-global-${hash}` 12 | if (StyleSheet.instance.hasInjectedComponent(componentId)) return 13 | 14 | StyleSheet.instance.inject(componentId, false, stringifyRules(rules)) 15 | } 16 | 17 | return injectGlobal 18 | } 19 | -------------------------------------------------------------------------------- /flow-typed/fbjs_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 92609e333a1987056500a1a8bbebee11 2 | // flow-typed version: <>/fbjs_v0/flow_v0.32.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'fbjs' 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 | declare module 'fbjs' { 17 | declare module.exports: any; 18 | } 19 | 20 | declare module 'fbjs/lib/camelizeStyleName' { 21 | declare module.exports: any; 22 | } 23 | 24 | declare module 'fbjs/lib/hyphenateStyleName' { 25 | declare module.exports: any; 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/extractCompsFromCSS.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const SC_COMPONENT_ID = /^[^\S\n]*?\/\* sc-component-id:\s+(\S+)\s+\*\//mg 3 | 4 | export default (maybeCSS: ?string): Array => { 5 | const css = `${maybeCSS || ''}` // Definitely a string, and a clone 6 | const existingComponents = [] 7 | css.replace(SC_COMPONENT_ID, (match, componentId, matchIndex) => { 8 | existingComponents.push({ componentId, matchIndex }) 9 | return match 10 | }) 11 | return existingComponents.map(({ componentId, matchIndex }, i) => { 12 | const nextComp = existingComponents[i + 1] 13 | const cssFromDOM = nextComp ? css.slice(matchIndex, nextComp.matchIndex) : css.slice(matchIndex) 14 | return { componentId, cssFromDOM } 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/stringifyRules.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import stylis from 'stylis' 3 | import type { Interpolation } from '../types' 4 | 5 | stylis.set({ 6 | global: false, 7 | cascade: true, 8 | keyframe: false, 9 | prefix: true, 10 | compress: false, 11 | semicolon: true, 12 | }) 13 | 14 | const stringifyRules = ( 15 | rules: Array, 16 | selector: ?string, 17 | prefix: ?string, 18 | ): string => { 19 | const flatCSS = rules 20 | .join('') 21 | .replace(/^\s*\/\/.*$/gm, '') // replace JS comments 22 | 23 | const cssStr = (selector && prefix) ? 24 | `${prefix} ${selector} { ${flatCSS} }` : 25 | flatCSS 26 | 27 | return stylis(prefix || !selector ? '' : selector, cssStr) 28 | } 29 | 30 | export default stringifyRules 31 | -------------------------------------------------------------------------------- /typings/tests/server-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { renderToString } from "react-dom/server"; 3 | import styled, { ServerStyleSheet, StyleSheetManager } from "../.."; 4 | 5 | const Title = styled.h1` 6 | font-size: 1.5em; 7 | text-align: center; 8 | color: palevioletred; 9 | `; 10 | 11 | const sheet = new ServerStyleSheet(); 12 | const html = renderToString(sheet.collectStyles(Hello world)); 13 | const css = sheet.getStyleTags(); 14 | const styleElement = sheet.getStyleElement(); 15 | 16 | const sheet2 = new ServerStyleSheet(); 17 | const html2 = renderToString( 18 | 19 | Hello world 20 | 21 | ); 22 | 23 | const css2 = sheet2.getStyleElement(); 24 | -------------------------------------------------------------------------------- /src/vendor/README.md: -------------------------------------------------------------------------------- 1 | Vendored postcss source as of [31ae472](https://github.com/postcss/postcss/tree/31ae4724afbc02e103711fec6517ba485177d827) (latest release 5.2.0) 2 | 3 | Vendored postcss-nested source as of [e709092](https://github.com/postcss/postcss-nested/tree/e7090926839cf916f6a24c3ad4079c1206d93b2d) 4 | 5 | Then hacked things around: 6 | 7 | * Deleted `previous-map.js` and all references to it because it `require('fs')`ed 8 | * Deleted reference to `postcss` within `postcss-nested` & simply exported the transform function 9 | * Replaced nested `require` statements with `import` declarations for the sake of a leaner bundle. This entails adding empty imports to three files to guarantee correct ordering – see https://github.com/styled-components/styled-components/pull/100 10 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export type Interpolation = ((executionContext: Object) => Interpolation) | 3 | string | 4 | number | 5 | Array 6 | 7 | /* todo: I want this to actually be an array of Function | string but that causes errors */ 8 | export type RuleSet = Array 9 | 10 | /* eslint-disable no-undef */ 11 | export type Target = string | ReactClass<*> 12 | 13 | export type NameGenerator = (hash: number) => string 14 | 15 | export type Flattener = ( 16 | chunks: Array, 17 | executionContext: ?Object 18 | ) => Array 19 | 20 | export type Stringifier = ( 21 | rules: Array, 22 | selector: ?string, 23 | prefix: ?string 24 | ) => string 25 | 26 | export type StyleSheet = { 27 | create: Function 28 | } 29 | -------------------------------------------------------------------------------- /src/test/props.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import { shallow } from 'enzyme' 4 | 5 | import { resetStyled, expectCSSMatches } from './utils' 6 | 7 | let styled 8 | 9 | describe('props', () => { 10 | beforeEach(() => { 11 | styled = resetStyled() 12 | }) 13 | 14 | it('should execute interpolations and fall back', () => { 15 | const Comp = styled.div` 16 | color: ${props => props.fg || 'black'}; 17 | ` 18 | shallow() 19 | expectCSSMatches('.sc-a {} .b { color: black; }') 20 | }) 21 | it('should execute interpolations and inject props', () => { 22 | const Comp = styled.div` 23 | color: ${props => props.fg || 'black'}; 24 | ` 25 | shallow() 26 | expectCSSMatches('.sc-a {} .b { color: red; }') 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /src/utils/test/interleave.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import interleave from '../interleave' 3 | 4 | describe('interleave', () => { 5 | it('blindly interleave', () => { 6 | expect(interleave([], [])).toEqual([undefined]) 7 | expect(interleave(['foo'], [])).toEqual(['foo']) 8 | expect(interleave(['foo'], [1])).toEqual(['foo', 1, undefined]) 9 | expect(interleave(['foo', 'bar'], [1])).toEqual(['foo', 1, 'bar']) 10 | }) 11 | it('should be driven off the number of interpolations', () => { 12 | expect(interleave(['foo', 'bar'], [])).toEqual(['foo']) 13 | expect(interleave(['foo', 'bar', 'baz'], [1])).toEqual(['foo', 1, 'bar']) 14 | expect(interleave([], [1])).toEqual([undefined, 1, undefined]) 15 | expect(interleave(['foo'], [1, 2, 3])).toEqual(['foo', 1, undefined, 2, undefined, 3, undefined]) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /src/utils/createWarnTooManyClasses.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const LIMIT = 200 4 | 5 | export default (displayName: string) => { 6 | let generatedClasses = {} 7 | let warningSeen = false 8 | 9 | return (className: string) => { 10 | if (!warningSeen) { 11 | generatedClasses[className] = true 12 | if (Object.keys(generatedClasses).length >= LIMIT) { 13 | // Unable to find latestRule in test environment. 14 | /* eslint-disable no-console, prefer-template */ 15 | console.warn(`Over ${LIMIT} classes were generated for component ${displayName}. ` + 16 | 'Consider using style property for frequently changed styles.\n' + 17 | 'Example:\n' + 18 | ' const StyledComp = styled.div`width: 100%;`\n' + 19 | ' ') 20 | warningSeen = true 21 | generatedClasses = {} 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/models/StyleSheetManager.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react' 3 | import PropTypes from 'prop-types' 4 | import StyleSheet, { CONTEXT_KEY } from './StyleSheet' 5 | 6 | class StyleSheetManager extends Component { 7 | getChildContext() { 8 | return { [CONTEXT_KEY]: this.props.sheet } 9 | } 10 | 11 | render() { 12 | /* eslint-disable react/prop-types */ 13 | // Flow v0.43.1 will report an error accessing the `children` property, 14 | // but v0.47.0 will not. It is necessary to use a type cast instead of 15 | // a "fixme" comment to satisfy both Flow versions. 16 | return React.Children.only((this.props: any).children) 17 | } 18 | } 19 | 20 | StyleSheetManager.childContextTypes = { 21 | [CONTEXT_KEY]: PropTypes.instanceOf(StyleSheet).isRequired, 22 | } 23 | 24 | StyleSheetManager.propTypes = { 25 | sheet: PropTypes.instanceOf(StyleSheet).isRequired, 26 | } 27 | 28 | export default StyleSheetManager 29 | -------------------------------------------------------------------------------- /src/test/overriding.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import { shallow } from 'enzyme' 4 | 5 | import { resetStyled, expectCSSMatches } from './utils' 6 | 7 | let styled 8 | 9 | describe('extending', () => { 10 | /** 11 | * Make sure the setup is the same for every test 12 | */ 13 | beforeEach(() => { 14 | styled = resetStyled() 15 | }) 16 | 17 | it('should let you use another component in a css rule', () => { 18 | const Inner = styled.div` 19 | color: blue; 20 | font-weight: light; 21 | ` 22 | const Outer = styled.div` 23 | padding: 1rem; 24 | > ${Inner} { 25 | font-weight: bold; 26 | } 27 | ` 28 | shallow() 29 | shallow() 30 | expectCSSMatches(` 31 | .sc-a {} 32 | .c { color: blue; font-weight: light; } 33 | .sc-b {} 34 | .d { padding: 1rem; } 35 | .d > .sc-a { font-weight: bold; } 36 | `) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /flow-typed/npm/mocha_v2.4.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 908ce59549760ff976de1c8777869375 2 | // flow-typed version: 94e9f7e0a4/mocha_v2.4.x/flow_>=v0.22.x 3 | 4 | type TestFunction = ((done: () => void) => void | Promise); 5 | 6 | declare var describe : { 7 | (name:string, spec:() => void): void; 8 | only(description:string, spec:() => void): void; 9 | skip(description:string, spec:() => void): void; 10 | timeout(ms:number): void; 11 | }; 12 | 13 | declare var context : typeof describe; 14 | 15 | declare var it : { 16 | (name:string, spec?:TestFunction): void; 17 | only(description:string, spec:TestFunction): void; 18 | skip(description:string, spec:TestFunction): void; 19 | timeout(ms:number): void; 20 | }; 21 | 22 | declare function before(method : TestFunction):void; 23 | declare function beforeEach(method : TestFunction):void; 24 | declare function after(method : TestFunction):void; 25 | declare function afterEach(method : TestFunction):void; 26 | -------------------------------------------------------------------------------- /flow-typed/npm/mocha_v3.1.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 6b82cf8c1da27b4f0fa7a58e5ed5babf 2 | // flow-typed version: edf70dde46/mocha_v3.1.x/flow_>=v0.22.x 3 | 4 | type TestFunction = ((done: () => void) => void | Promise); 5 | 6 | declare var describe : { 7 | (name:string, spec:() => void): void; 8 | only(description:string, spec:() => void): void; 9 | skip(description:string, spec:() => void): void; 10 | timeout(ms:number): void; 11 | }; 12 | 13 | declare var context : typeof describe; 14 | 15 | declare var it : { 16 | (name:string, spec?:TestFunction): void; 17 | only(description:string, spec:TestFunction): void; 18 | skip(description:string, spec:TestFunction): void; 19 | timeout(ms:number): void; 20 | }; 21 | 22 | declare function before(method : TestFunction):void; 23 | declare function beforeEach(method : TestFunction):void; 24 | declare function after(method : TestFunction):void; 25 | declare function afterEach(method : TestFunction):void; 26 | -------------------------------------------------------------------------------- /src/utils/create-broadcast.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /** 3 | * Creates a broadcast that can be listened to, i.e. simple event emitter 4 | * 5 | * @see https://github.com/ReactTraining/react-broadcast 6 | */ 7 | 8 | export type Broadcast = { 9 | publish: (value: mixed) => void, 10 | subscribe: (listener: (currentValue: mixed) => void) => () => void 11 | } 12 | 13 | const createBroadcast = (initialValue: mixed): Broadcast => { 14 | let listeners = [] 15 | let currentValue = initialValue 16 | 17 | return { 18 | publish(value: mixed) { 19 | currentValue = value 20 | listeners.forEach(listener => listener(currentValue)) 21 | }, 22 | subscribe(listener) { 23 | listeners.push(listener) 24 | 25 | // Publish to this subscriber once immediately. 26 | listener(currentValue) 27 | 28 | return () => { 29 | listeners = listeners.filter(item => item !== listener) 30 | } 31 | }, 32 | } 33 | } 34 | 35 | export default createBroadcast 36 | -------------------------------------------------------------------------------- /src/constructors/keyframes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import hashStr from '../vendor/glamor/hash' 3 | import type { Interpolation, NameGenerator, Stringifier } from '../types' 4 | import StyleSheet from '../models/StyleSheet' 5 | 6 | const replaceWhitespace = (str: string): string => str.replace(/\s|\\n/g, '') 7 | 8 | export default (nameGenerator: NameGenerator, stringifyRules: Stringifier, css: Function) => 9 | (strings: Array, ...interpolations: Array): string => { 10 | const rules = css(strings, ...interpolations) 11 | const hash = hashStr(replaceWhitespace(JSON.stringify(rules))) 12 | 13 | const existingName = StyleSheet.instance.getName(hash) 14 | if (existingName) return existingName 15 | 16 | const name = nameGenerator(hash) 17 | if (StyleSheet.instance.alreadyInjected(hash, name)) return name 18 | 19 | const generatedCSS = stringifyRules(rules, name, '@keyframes') 20 | StyleSheet.instance.inject(`sc-keyframes-${name}`, true, generatedCSS, hash, name) 21 | return name 22 | } 23 | -------------------------------------------------------------------------------- /typings/tests/function-themes-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled, { ThemeProvider } from "../.."; 4 | 5 | // Define our button, but with the use of props.theme this time 6 | const Button = styled.button` 7 | color: ${props => props.theme.fg}; 8 | border: 2px solid ${props => props.theme.fg}; 9 | background: ${props => props.theme.bg}; 10 | 11 | font-size: 1em; 12 | margin: 1em; 13 | padding: 0.25em 1em; 14 | border-radius: 3px; 15 | `; 16 | 17 | // Define our `fg` and `bg` on the theme 18 | const theme = { 19 | fg: "palevioletred", 20 | bg: "white" 21 | }; 22 | 23 | // This theme swaps `fg` and `bg` 24 | const invertTheme = ({ fg, bg }: { fg: string, bg: string }) => ({ 25 | fg: bg, 26 | bg: fg 27 | }); 28 | 29 | const MyApp = 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 |
38 |
39 | ; 40 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled, { injectGlobal, keyframes } from '../dist/styled-components' 3 | 4 | export default () => { 5 | injectGlobal` 6 | body { 7 | font-family: sans-serif; 8 | } 9 | ` 10 | 11 | // Create a react component that renders an <h1> which is 12 | // centered, palevioletred and sized at 1.5em 13 | const Title = styled.h1` 14 | font-size: 1.5em; 15 | text-align: center; 16 | color: palevioletred; 17 | animation: ${keyframes`from { opacity: 0; }`} 1s both; 18 | `; 19 | 20 | // Create a <Wrapper> react component that renders a <section> with 21 | // some padding and a papayawhip background 22 | const Wrapper = styled.section` 23 | padding: 4em; 24 | background: papayawhip; 25 | `; 26 | 27 | return class Example extends React.Component { 28 | render() { 29 | return ( 30 | <Wrapper> 31 | <Title>Hello World, this is my first styled component! 32 | 33 | ) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /flow-typed/npm/is-plain-object_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: d1b2e98db57131dd1d82f13d87bb778f 2 | // flow-typed version: <>/is-plain-object_v^2.0.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'is-plain-object' 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 | declare module 'is-plain-object' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | 27 | // Filename aliases 28 | declare module 'is-plain-object/index' { 29 | declare module.exports: $Exports<'is-plain-object'>; 30 | } 31 | declare module 'is-plain-object/index.js' { 32 | declare module.exports: $Exports<'is-plain-object'>; 33 | } 34 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-preset-react_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 8bbb361df23a98001e9a8d6e03166b87 2 | // flow-typed version: <>/babel-preset-react_v^6.16.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-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 | declare module 'babel-preset-react' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-react/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-react/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-react/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-preset-latest_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 4a909458473c244946911a31a7ed53ba 2 | // flow-typed version: <>/babel-preset-latest_v^6.16.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-latest' 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 | declare module 'babel-preset-latest' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-latest/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-latest/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-latest/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /primitives/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as ReactPrimitives from "react-primitives"; 2 | import * as React from "react"; 3 | import { StatelessComponent, ComponentClass } from "react"; 4 | 5 | export { 6 | ThemeProps, 7 | ThemeProvider, 8 | Interpolation, 9 | InterpolationValue, 10 | InterpolationFunction, 11 | OuterStyledProps, 12 | StyledFunction, 13 | BaseStyledInterface, 14 | css, 15 | withTheme, 16 | } from ".."; 17 | 18 | import { StyledFunction, BaseStyledInterface } from ".."; 19 | 20 | type Component

= ComponentClass

| StatelessComponent

; 21 | 22 | export type ReactPrimitivesStyledFunction

= StyledFunction

; 23 | 24 | export interface StyledInterface extends BaseStyledInterface { 25 | Image: ReactPrimitivesStyledFunction; 26 | Text: ReactPrimitivesStyledFunction; 27 | Touchable: ReactPrimitivesStyledFunction; 28 | View: ReactPrimitivesStyledFunction; 29 | } 30 | 31 | declare const styled: StyledInterface; 32 | 33 | export default styled; 34 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-flow_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 9e0792c79057a1210f197c5eddfe39dd 2 | // flow-typed version: <>/rollup-plugin-flow_v^1.1.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-flow' 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 | declare module 'rollup-plugin-flow' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | 27 | // Filename aliases 28 | declare module 'rollup-plugin-flow/index' { 29 | declare module.exports: $Exports<'rollup-plugin-flow'>; 30 | } 31 | declare module 'rollup-plugin-flow/index.js' { 32 | declare module.exports: $Exports<'rollup-plugin-flow'>; 33 | } 34 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ### My styles are being repeated multiple times 4 | 5 | You might notice that generating styles based on dynamic props will result in repeated CSS declarations. In other words, in the following example: 6 | 7 | ```js 8 | const Button = styled.button` 9 | /* If it's a small button use less padding */ 10 | padding: ${props => props.small ? '0.25em 1em' : '0.5em 2em'}; 11 | 12 | /* …more styles here… */ 13 | `; 14 | ``` 15 | 16 | You will ultimately end up with two classes, both of which contain the same "more styles here" lines: 17 | 18 | ```css 19 | .foo{ 20 | padding: 0.25em 1em; 21 | /* …more styles here… */ 22 | } 23 | .bar{ 24 | padding: 0.5em 2em; 25 | /* …more styles here… */ 26 | } 27 | ``` 28 | 29 | While this isn't how you would normally write CSS, it's not actually a big issue: 30 | 31 | - On the server, you can gzip your CSS to take care of any duplication. 32 | - On the client, this only increases the amount of *generated* CSS (and not the size of the bundle sent by the server), which doesn't have any noticeable performance impact. 33 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-uglify_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 8c8cf23b3215fa43153281aeec5c3e41 2 | // flow-typed version: <>/rollup-plugin-uglify_v^1.0.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-uglify' 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 | declare module 'rollup-plugin-uglify' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-uglify/dist/rollup-plugin-uglify' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'rollup-plugin-uglify/dist/rollup-plugin-uglify.js' { 31 | declare module.exports: $Exports<'rollup-plugin-uglify/dist/rollup-plugin-uglify'>; 32 | } 33 | -------------------------------------------------------------------------------- /typings/tests/with-component-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled from "../.."; 4 | 5 | const H1 = styled.h1` 6 | color: palevioletred; 7 | font-size: 1em; 8 | `; 9 | 10 | function getRandomInt(min: number, max: number) { 11 | min = Math.ceil(min); 12 | max = Math.floor(max); 13 | return Math.floor(Math.random() * (max - min)) + min; 14 | } 15 | 16 | class Random extends React.Component { 17 | render() { 18 | const i = getRandomInt(1, 6); 19 | 20 | switch (i) { 21 | case 1: 22 | return

Hello World

; 23 | case 2: 24 | return

Hello World

; 25 | case 3: 26 | return

Hello World

; 27 | case 4: 28 | return

Hello World

; 29 | case 5: 30 | return
Hello World
; 31 | case 6: 32 | return
Hello World
; 33 | default: 34 | return null; 35 | } 36 | } 37 | } 38 | 39 | const H2 = H1.withComponent("h2"); 40 | const a = H1.withComponent("a"); 41 | const abbr = H1.withComponent("abbr"); 42 | 43 | const RandomHeading = H1.withComponent(Random); 44 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-external-helpers_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: d8639acd1a3439b6697187e309ce8c1d 2 | // flow-typed version: <>/babel-plugin-external-helpers_v^6.18.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-external-helpers' 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 | declare module 'babel-plugin-external-helpers' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-external-helpers/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-plugin-external-helpers/lib/index.js' { 31 | declare module.exports: $Exports<'babel-plugin-external-helpers/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /src/no-parser/test/keyframes.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | 4 | import _keyframes from '../../constructors/keyframes' 5 | import stringifyRules from '../stringifyRules' 6 | import css from '../css' 7 | 8 | import { resetNoParserStyled, expectCSSMatches } from '../../test/utils' 9 | 10 | let index = 0 11 | const keyframes = _keyframes(() => `keyframe_${index++}`, stringifyRules, css) 12 | 13 | describe('keyframes', () => { 14 | beforeEach(() => { 15 | resetNoParserStyled() 16 | }) 17 | 18 | it('should correctly assemble preprocessed CSS', () => { 19 | const name = keyframes([ 20 | // $FlowFixMe 21 | ['@-webkit-keyframes '], 22 | // $FlowFixMe 23 | [' {from {background-position: 0vw 0px;}to {background-position: 100vw 0px;}} @keyframes '], 24 | // $FlowFixMe 25 | [' {from {background-position: 0vw 0px;}to {background-position: 100vw 0px;}}'] 26 | ]) 27 | 28 | expectCSSMatches(`@-webkit-keyframes ${name} {from {background-position: 0vw 0px;}to {background-position: 100vw 0px;}} @keyframes ${name} {from {background-position: 0vw 0px;}to {background-position: 100vw 0px;}}`) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Glen Maddern and Maximilian Stoiber 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 | -------------------------------------------------------------------------------- /src/vendor/postcss/terminal-highlight.js: -------------------------------------------------------------------------------- 1 | import tokenize from './tokenize'; 2 | import Input from './input'; 3 | 4 | const HIGHLIGHT_THEME = { 5 | 'brackets': [36, 39], // cyan 6 | 'string': [31, 39], // red 7 | 'at-word': [31, 39], // red 8 | 'comment': [90, 39], // gray 9 | '{': [32, 39], // green 10 | '}': [32, 39], // green 11 | ':': [ 1, 22], // bold 12 | ';': [ 1, 22], // bold 13 | '(': [ 1, 22], // bold 14 | ')': [ 1, 22] // bold 15 | }; 16 | 17 | function code(color) { 18 | return '\u001b[' + color + 'm'; 19 | } 20 | 21 | function terminalHighlight(css) { 22 | let tokens = tokenize(new Input(css), { ignoreErrors: true }); 23 | let result = []; 24 | tokens.forEach(token => { 25 | let color = HIGHLIGHT_THEME[token[0]]; 26 | if ( color ) { 27 | result.push(token[1].split(/\r?\n/) 28 | .map( i => code(color[0]) + i + code(color[1]) ) 29 | .join('\n')); 30 | } else { 31 | result.push(token[1]); 32 | } 33 | }) 34 | return result.join(''); 35 | } 36 | 37 | export default terminalHighlight; 38 | -------------------------------------------------------------------------------- /src/vendor/postcss/parse.js: -------------------------------------------------------------------------------- 1 | import Parser from './parser'; 2 | import Input from './input'; 3 | 4 | export default function parse(css, opts) { 5 | if ( opts && opts.safe ) { 6 | throw new Error('Option safe was removed. ' + 7 | 'Use parser: require("postcss-safe-parser")'); 8 | } 9 | 10 | let input = new Input(css, opts); 11 | 12 | let parser = new Parser(input); 13 | try { 14 | parser.tokenize(); 15 | parser.loop(); 16 | } catch (e) { 17 | if ( e.name === 'CssSyntaxError' && opts && opts.from ) { 18 | if ( /\.scss$/i.test(opts.from) ) { 19 | e.message += '\nYou tried to parse SCSS with ' + 20 | 'the standard CSS parser; ' + 21 | 'try again with the postcss-scss parser'; 22 | } else if ( /\.less$/i.test(opts.from) ) { 23 | e.message += '\nYou tried to parse Less with ' + 24 | 'the standard CSS parser; ' + 25 | 'try again with the postcss-less parser'; 26 | } 27 | } 28 | throw e; 29 | } 30 | 31 | return parser.root; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-transform-class-properties_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 81a3b6c59a410c5dd329b050975fd1d1 2 | // flow-typed version: <>/babel-plugin-transform-class-properties_v^6.19.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-transform-class-properties' 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 | declare module 'babel-plugin-transform-class-properties' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-transform-class-properties/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-plugin-transform-class-properties/lib/index.js' { 31 | declare module.exports: $Exports<'babel-plugin-transform-class-properties/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-transform-flow-strip-types_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: b2572b76795ad7c5529ad5e60638d583 2 | // flow-typed version: <>/babel-plugin-transform-flow-strip-types_v^6.21.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-transform-flow-strip-types' 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 | declare module 'babel-plugin-transform-flow-strip-types' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-transform-flow-strip-types/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-plugin-transform-flow-strip-types/lib/index.js' { 31 | declare module.exports: $Exports<'babel-plugin-transform-flow-strip-types/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-transform-object-rest-spread_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: d6f59d9bab9bfcad1e05d43480a93222 2 | // flow-typed version: <>/babel-plugin-transform-object-rest-spread_v^6.20.2/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-transform-object-rest-spread' 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 | declare module 'babel-plugin-transform-object-rest-spread' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-transform-object-rest-spread/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-plugin-transform-object-rest-spread/lib/index.js' { 31 | declare module.exports: $Exports<'babel-plugin-transform-object-rest-spread/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /src/no-parser/test/basic.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import { shallow } from 'enzyme' 4 | 5 | import { resetNoParserStyled, expectCSSMatches } from '../../test/utils' 6 | 7 | let styled 8 | 9 | describe('basic', () => { 10 | beforeEach(() => { 11 | styled = resetNoParserStyled() 12 | }) 13 | 14 | it('should throw a meaningful error when called with null', () => { 15 | const invalidComps = [undefined, null, 123, []] 16 | invalidComps.forEach(comp => { 17 | expect(() => { 18 | // $FlowInvalidInputTest 19 | const Comp = styled(comp) 20 | shallow() 21 | // $FlowInvalidInputTest 22 | }).toThrow(`Cannot create styled-component for component: ${comp}`) 23 | }) 24 | }) 25 | 26 | it('should correctly assemble preprocessed CSS', () => { 27 | const Comp = styled.div([[ '{ color: red; }' ]]) 28 | shallow() 29 | expectCSSMatches('.sc-a {} .b{ color: red; }') 30 | }) 31 | 32 | it('should correctly execute passed functions and assemble preprocessed CSS', () => { 33 | const Comp = styled.div([[ '{ color: ', () => 'red', '; }' ]]) 34 | shallow() 35 | expectCSSMatches('.sc-a {} .b{ color: red; }') 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /src/constructors/constructWithOptions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { Interpolation, Target } from '../types' 3 | 4 | export default (css: Function) => { 5 | const constructWithOptions = (componentConstructor: Function, 6 | tag: Target, 7 | options: Object = {}) => { 8 | if (typeof tag !== 'string' && typeof tag !== 'function') { 9 | // $FlowInvalidInputTest 10 | throw new Error(`Cannot create styled-component for component: ${tag}`) 11 | } 12 | 13 | /* This is callable directly as a template function */ 14 | const templateFunction = 15 | (strings: Array, ...interpolations: Array) => 16 | componentConstructor(tag, options, css(strings, ...interpolations)) 17 | 18 | /* If config methods are called, wrap up a new template function and merge options */ 19 | templateFunction.withConfig = config => 20 | constructWithOptions(componentConstructor, tag, { ...options, ...config }) 21 | templateFunction.attrs = attrs => 22 | constructWithOptions(componentConstructor, tag, { ...options, 23 | attrs: { ...(options.attrs || {}), ...attrs } }) 24 | 25 | return templateFunction 26 | } 27 | 28 | return constructWithOptions 29 | } 30 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-visualizer_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 11eea34a7a2b0459a19fa7a69f630536 2 | // flow-typed version: <>/rollup-plugin-visualizer_v^0.1.5/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-visualizer' 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 | declare module 'rollup-plugin-visualizer' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-visualizer/lib/pluginmain' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup-plugin-visualizer/plugin' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'rollup-plugin-visualizer/lib/pluginmain.js' { 35 | declare module.exports: $Exports<'rollup-plugin-visualizer/lib/pluginmain'>; 36 | } 37 | declare module 'rollup-plugin-visualizer/plugin.js' { 38 | declare module.exports: $Exports<'rollup-plugin-visualizer/plugin'>; 39 | } 40 | -------------------------------------------------------------------------------- /src/constructors/test/keyframes.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import _keyframes from '../keyframes' 3 | import stringifyRules from '../../utils/stringifyRules' 4 | import css from '../css' 5 | import { expectCSSMatches, resetStyled } from '../../test/utils' 6 | 7 | /** 8 | * Setup 9 | */ 10 | let index = 0 11 | const keyframes = _keyframes(() => `keyframe_${index++}`, stringifyRules, css) 12 | 13 | describe('keyframes', () => { 14 | beforeEach(() => { 15 | resetStyled() 16 | index = 0 17 | }) 18 | 19 | it('should return its name', () => { 20 | expect(keyframes` 21 | 0% { 22 | opacity: 0; 23 | } 24 | 100% { 25 | opacity: 1; 26 | } 27 | `).toEqual('keyframe_0') 28 | }) 29 | 30 | it('should insert the correct styles', () => { 31 | const rules = ` 32 | 0% { 33 | opacity: 0; 34 | } 35 | 100% { 36 | opacity: 1; 37 | } 38 | ` 39 | 40 | const name = keyframes`${rules}` 41 | expectCSSMatches(` 42 | @-webkit-keyframes ${name} { 43 | 0% { 44 | opacity: 0; 45 | } 46 | 100% { 47 | opacity: 1; 48 | } 49 | } 50 | 51 | @keyframes ${name} { 52 | 0% { 53 | opacity: 0; 54 | } 55 | 100% { 56 | opacity: 1; 57 | } 58 | } 59 | `) 60 | }) 61 | }) 62 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "plugins": ["flowtype", "flowtype-errors"], 5 | "rules": { 6 | "semi": [2, "never"], 7 | "arrow-parens": 0, 8 | "class-methods-use-this": 0, 9 | "symbol-description": 0, 10 | "no-unused-vars": [2, { "varsIgnorePattern": "^_+$" }], 11 | "import/no-extraneous-dependencies": 0, 12 | "no-confusing-arrow": 0, 13 | "no-else-return": 0, 14 | "react/sort-comp": 0, 15 | "react/jsx-filename-extension": 0, 16 | "flowtype-errors/show-errors": 2, 17 | "no-prototype-builtins": 0, 18 | "no-duplicate-imports": 0, 19 | "flowtype/require-valid-file-annotation": [2, "always", {"annotationStyle": "line"}], 20 | "flowtype/semi": [2, "never"], 21 | "flowtype/boolean-style": [2, "boolean"], 22 | "flowtype/no-dupe-keys": 2, 23 | "flowtype/space-before-type-colon": [2, "never"], 24 | "flowtype/space-after-type-colon": [2, "always"], 25 | "flowtype/union-intersection-spacing": [2, "always"], 26 | "flowtype/object-type-delimiter": 2 27 | }, 28 | "env": { 29 | "mocha": true, 30 | "browser": "true" 31 | }, 32 | "parserOptions": { 33 | "ecmaVersion": 7, 34 | "sourceType": "module", 35 | "ecmaFeatures": { 36 | "impliedStrict": true, 37 | "jsx": true, 38 | "experimentalObjectRestSpread": true 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-add-module-exports_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 527fdc5f4678a0f701dc6e01a439abf9 2 | // flow-typed version: <>/babel-plugin-add-module-exports_v^0.2.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-add-module-exports' 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 | declare module 'babel-plugin-add-module-exports' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-add-module-exports/changelog' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'babel-plugin-add-module-exports/lib/index' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'babel-plugin-add-module-exports/changelog.js' { 35 | declare module.exports: $Exports<'babel-plugin-add-module-exports/changelog'>; 36 | } 37 | declare module 'babel-plugin-add-module-exports/lib/index.js' { 38 | declare module.exports: $Exports<'babel-plugin-add-module-exports/lib/index'>; 39 | } 40 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 84868a173acdf7dcb8cbd16adafcda8d 2 | // flow-typed version: <>/rollup_v^0.37.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup' 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 | declare module 'rollup' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup/dist/rollup.browser' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup/dist/rollup.es' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'rollup/dist/rollup' { 34 | declare module.exports: any; 35 | } 36 | 37 | // Filename aliases 38 | declare module 'rollup/dist/rollup.browser.js' { 39 | declare module.exports: $Exports<'rollup/dist/rollup.browser'>; 40 | } 41 | declare module 'rollup/dist/rollup.es.js' { 42 | declare module.exports: $Exports<'rollup/dist/rollup.es'>; 43 | } 44 | declare module 'rollup/dist/rollup.js' { 45 | declare module.exports: $Exports<'rollup/dist/rollup'>; 46 | } 47 | -------------------------------------------------------------------------------- /src/test/css.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import { shallow } from 'enzyme' 4 | 5 | import { resetStyled, expectCSSMatches } from './utils' 6 | 7 | let styled 8 | 9 | describe('css features', () => { 10 | beforeEach(() => { 11 | styled = resetStyled() 12 | }) 13 | 14 | it('should add vendor prefixes in the right order', () => { 15 | const Comp = styled.div` 16 | transition: opacity 0.3s; 17 | ` 18 | shallow() 19 | expectCSSMatches('.sc-a {} .b { -webkit-transition: opacity 0.3s; transition: opacity 0.3s; }') 20 | }) 21 | 22 | it('should add vendor prefixes for display', () => { 23 | const Comp = styled.div` 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | ` 28 | shallow() 29 | expectCSSMatches(` 30 | .sc-a {} 31 | .b { 32 | display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; 33 | } 34 | `) 35 | }) 36 | 37 | it('should pass through custom properties', () => { 38 | const Comp = styled.div` 39 | --custom-prop: some-val; 40 | ` 41 | shallow() 42 | expectCSSMatches('.sc-a {} .b { --custom-prop: some-val; }') 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /flow-typed/npm/is-function_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: f087ac7f75c3cd1ca8d366bdbb69e804 2 | // flow-typed version: <>/is-function_v^1.0.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'is-function' 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 | declare module 'is-function' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'is-function/browser-test' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'is-function/test' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'is-function/browser-test.js' { 35 | declare module.exports: $Exports<'is-function/browser-test'>; 36 | } 37 | declare module 'is-function/index' { 38 | declare module.exports: $Exports<'is-function'>; 39 | } 40 | declare module 'is-function/index.js' { 41 | declare module.exports: $Exports<'is-function'>; 42 | } 43 | declare module 'is-function/test.js' { 44 | declare module.exports: $Exports<'is-function/test'>; 45 | } 46 | -------------------------------------------------------------------------------- /flow-typed/npm/chokidar_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 3de05e6ca36df049f4530c6bdbf3b83e 2 | // flow-typed version: <>/chokidar_v^1.6.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'chokidar' 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 | declare module 'chokidar' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'chokidar/lib/fsevents-handler' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'chokidar/lib/nodefs-handler' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'chokidar/index' { 35 | declare module.exports: $Exports<'chokidar'>; 36 | } 37 | declare module 'chokidar/index.js' { 38 | declare module.exports: $Exports<'chokidar'>; 39 | } 40 | declare module 'chokidar/lib/fsevents-handler.js' { 41 | declare module.exports: $Exports<'chokidar/lib/fsevents-handler'>; 42 | } 43 | declare module 'chokidar/lib/nodefs-handler.js' { 44 | declare module.exports: $Exports<'chokidar/lib/nodefs-handler'>; 45 | } 46 | -------------------------------------------------------------------------------- /src/primitives/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* eslint-disable import/no-unresolved */ 4 | import reactPrimitives from 'react-primitives' 5 | 6 | import _InlineStyle from '../models/InlineStyle' 7 | import _StyledNativeComponent from '../models/StyledNativeComponent' 8 | import _constructWithOptions from '../constructors/constructWithOptions' 9 | 10 | import css from '../constructors/css' 11 | import ThemeProvider from '../models/ThemeProvider' 12 | import withTheme from '../hoc/withTheme' 13 | 14 | import type { Target } from '../types' 15 | 16 | const constructWithOptions = _constructWithOptions(css) 17 | const InlineStyle = _InlineStyle(reactPrimitives.StyleSheet) 18 | const StyledNativeComponent = _StyledNativeComponent( 19 | constructWithOptions, 20 | InlineStyle, 21 | ) 22 | const styled = (tag: Target) => constructWithOptions(StyledNativeComponent, tag) 23 | 24 | /* React native lazy-requires each of these modules for some reason, so let's 25 | * assume it's for a good reason and not eagerly load them all */ 26 | const aliases = 'Image Text Touchable View ' 27 | 28 | /* Define a getter for each alias which simply gets the reactNative component 29 | * and passes it to styled */ 30 | aliases.split(/\s+/m).forEach(alias => Object.defineProperty(styled, alias, { 31 | enumerable: true, 32 | configurable: false, 33 | get() { 34 | return styled(reactPrimitives[alias]) 35 | }, 36 | })) 37 | 38 | export { css, ThemeProvider, withTheme } 39 | export default styled 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | ## Version 25 | 1.0.5 26 | 27 | ## Reproduction 28 | 29 | https://www.webpackbin.com/bins/-KeeZCr0xKfutOfOujxN 30 | 31 | ## Steps to reproduce 32 | 33 | ## Expected Behavior 34 | 35 | ## Actual Behavior 36 | -------------------------------------------------------------------------------- /src/vendor/postcss/vendor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains helpers for working with vendor prefixes. 3 | * 4 | * @example 5 | * const vendor = postcss.vendor; 6 | * 7 | * @namespace vendor 8 | */ 9 | let vendor = { 10 | 11 | /** 12 | * Returns the vendor prefix extracted from an input string. 13 | * 14 | * @param {string} prop - string with or without vendor prefix 15 | * 16 | * @return {string} vendor prefix or empty string 17 | * 18 | * @example 19 | * postcss.vendor.prefix('-moz-tab-size') //=> '-moz-' 20 | * postcss.vendor.prefix('tab-size') //=> '' 21 | */ 22 | prefix(prop) { 23 | if ( prop[0] === '-' ) { 24 | let sep = prop.indexOf('-', 1); 25 | return prop.substr(0, sep + 1); 26 | } else { 27 | return ''; 28 | } 29 | }, 30 | 31 | /** 32 | * Returns the input string stripped of its vendor prefix. 33 | * 34 | * @param {string} prop - string with or without vendor prefix 35 | * 36 | * @return {string} string name without vendor prefixes 37 | * 38 | * @example 39 | * postcss.vendor.unprefixed('-moz-tab-size') //=> 'tab-size' 40 | */ 41 | unprefixed(prop) { 42 | if ( prop[0] === '-' ) { 43 | let sep = prop.indexOf('-', 1); 44 | return prop.substr(sep + 1); 45 | } else { 46 | return prop; 47 | } 48 | } 49 | 50 | }; 51 | 52 | export default vendor; 53 | -------------------------------------------------------------------------------- /src/test/warnTooManyClasses.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import { shallow } from 'enzyme' 4 | 5 | import { resetStyled, expectCSSMatches } from './utils' 6 | import styleSheet from '../models/StyleSheet' 7 | 8 | let styled 9 | 10 | describe('warn too many classes', () => { 11 | const nativeWarn = console.warn 12 | let warnCallCount; 13 | /** 14 | * Make sure the setup is the same for every test 15 | */ 16 | beforeEach(() => { 17 | (console: any).warn = () => warnCallCount++ 18 | warnCallCount = 0 19 | styled = resetStyled() 20 | }) 21 | 22 | afterEach(() => { 23 | (console: any).warn = nativeWarn 24 | }) 25 | 26 | it('should warn once', () => { 27 | const Comp = styled.div` 28 | width: ${props => props.size}; 29 | ` 30 | for (let i = 0; i < 300; i++) { 31 | shallow() 32 | } 33 | expect(warnCallCount).toEqual(1) 34 | }) 35 | 36 | it('should warn if number of classes is 200', () => { 37 | const Comp = styled.div` 38 | width: ${props => props.size}; 39 | ` 40 | for (let i = 0; i < 200; i++) { 41 | shallow() 42 | } 43 | expect(warnCallCount).toEqual(1) 44 | }) 45 | 46 | it('should not warn if number of classes is below 200', () => { 47 | const Comp = styled.div` 48 | width: ${props => props.size}; 49 | ` 50 | for (let i = 0; i < 199; i++) { 51 | shallow() 52 | } 53 | 54 | expect(warnCallCount).toEqual(0) 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /src/vendor/glamor/hash.js: -------------------------------------------------------------------------------- 1 | // murmurhash2 via https://gist.github.com/raycmorgan/588423 2 | 3 | export default function doHash(str, seed) { 4 | var m = 0x5bd1e995; 5 | var r = 24; 6 | var h = seed ^ str.length; 7 | var length = str.length; 8 | var currentIndex = 0; 9 | 10 | while (length >= 4) { 11 | var k = UInt32(str, currentIndex); 12 | 13 | k = Umul32(k, m); 14 | k ^= k >>> r; 15 | k = Umul32(k, m); 16 | 17 | h = Umul32(h, m); 18 | h ^= k; 19 | 20 | currentIndex += 4; 21 | length -= 4; 22 | } 23 | 24 | switch (length) { 25 | case 3: 26 | h ^= UInt16(str, currentIndex); 27 | h ^= str.charCodeAt(currentIndex + 2) << 16; 28 | h = Umul32(h, m); 29 | break; 30 | 31 | case 2: 32 | h ^= UInt16(str, currentIndex); 33 | h = Umul32(h, m); 34 | break; 35 | 36 | case 1: 37 | h ^= str.charCodeAt(currentIndex); 38 | h = Umul32(h, m); 39 | break; 40 | } 41 | 42 | h ^= h >>> 13; 43 | h = Umul32(h, m); 44 | h ^= h >>> 15; 45 | 46 | return h >>> 0; 47 | } 48 | 49 | function UInt32(str, pos) { 50 | return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8) + (str.charCodeAt(pos++) << 16) + (str.charCodeAt(pos) << 24); 51 | } 52 | 53 | function UInt16(str, pos) { 54 | return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8); 55 | } 56 | 57 | function Umul32(n, m) { 58 | n = n | 0; 59 | m = m | 0; 60 | var nlo = n & 0xffff; 61 | var nhi = n >>> 16; 62 | var res = nlo * m + ((nhi * m & 0xffff) << 16) | 0; 63 | return res; 64 | } 65 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thanks for giving this a read! We're always open to your contributions to styled-components. 2 | This document will get you started on how to contribute and things you should know. 3 | So please give it a thorough read. 4 | 5 | Please also give the code of conduct a read. 6 | 7 | ## How do I contribute code? 8 | 9 | 1. Find some issue you're interested in, or a feature that you'd like to tackle. 10 | Also make sure that no one else is already working on it. We don't want you to be 11 | disappointed. 12 | 13 | 2. Fork, then clone: `git clone https://github.com/YOUR_USERNAME/styled-components.git` 14 | 15 | 3. Create a branch with a meaningful name for the issue: `git checkout -b fix-something` 16 | 17 | 4. Make your changes and commit: `git add` and `git commit` 18 | 19 | 5. Make sure that the tests still pass: `npm test` and `npm run flow` (for the type checks) 20 | 21 | 6. Push your branch: `git push -u origin your-branch-name` 22 | 23 | 7. Submit a pull request to the upstream styled-components repository. 24 | 25 | 8. Choose a descriptive title and describe your changes briefly. 26 | 27 | 9. Wait for a maintainer to review your PR, make changes if it's being recommended, and get it merged. 28 | 29 | 10. Perform a celebratory dance! :dancer: 30 | 31 | ## How do I set up the project? 32 | 33 | Run `npm install` and edit code in the `src/` folder. It's luckily very simple! :wink: 34 | 35 | When you commit our pre-commit hook will run, which executes `lint-staged`. It will run 36 | the linter automatically and warn you, if the code you've written doesn't comply with our 37 | code style. 38 | -------------------------------------------------------------------------------- /flow-typed/npm/pre-commit_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: b0e7ab49671c0c812975f3adf83292f3 2 | // flow-typed version: <>/pre-commit_v^1.2.2/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'pre-commit' 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 | declare module 'pre-commit' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'pre-commit/install' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'pre-commit/test' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'pre-commit/uninstall' { 34 | declare module.exports: any; 35 | } 36 | 37 | // Filename aliases 38 | declare module 'pre-commit/index' { 39 | declare module.exports: $Exports<'pre-commit'>; 40 | } 41 | declare module 'pre-commit/index.js' { 42 | declare module.exports: $Exports<'pre-commit'>; 43 | } 44 | declare module 'pre-commit/install.js' { 45 | declare module.exports: $Exports<'pre-commit/install'>; 46 | } 47 | declare module 'pre-commit/test.js' { 48 | declare module.exports: $Exports<'pre-commit/test'>; 49 | } 50 | declare module 'pre-commit/uninstall.js' { 51 | declare module.exports: $Exports<'pre-commit/uninstall'>; 52 | } 53 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-json_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 3d086c03e2e2ccfe7e06b78af530b5df 2 | // flow-typed version: <>/rollup-plugin-json_v^2.1.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-json' 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 | declare module 'rollup-plugin-json' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-json/dist/rollup-plugin-json.cjs' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup-plugin-json/dist/rollup-plugin-json.es' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'rollup-plugin-json/src/index' { 34 | declare module.exports: any; 35 | } 36 | 37 | // Filename aliases 38 | declare module 'rollup-plugin-json/dist/rollup-plugin-json.cjs.js' { 39 | declare module.exports: $Exports<'rollup-plugin-json/dist/rollup-plugin-json.cjs'>; 40 | } 41 | declare module 'rollup-plugin-json/dist/rollup-plugin-json.es.js' { 42 | declare module.exports: $Exports<'rollup-plugin-json/dist/rollup-plugin-json.es'>; 43 | } 44 | declare module 'rollup-plugin-json/src/index.js' { 45 | declare module.exports: $Exports<'rollup-plugin-json/src/index'>; 46 | } 47 | -------------------------------------------------------------------------------- /src/utils/flatten.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import hyphenate from 'fbjs/lib/hyphenateStyleName' 3 | import isPlainObject from 'is-plain-object' 4 | 5 | import type { Interpolation } from '../types' 6 | 7 | export const objToCss = (obj: Object, prevKey?: string): string => { 8 | const css = Object.keys(obj).map(key => { 9 | if (isPlainObject(obj[key])) return objToCss(obj[key], key) 10 | return `${hyphenate(key)}: ${obj[key]};` 11 | }).join(' ') 12 | return prevKey ? `${prevKey} { 13 | ${css} 14 | }` : css 15 | } 16 | 17 | const flatten = (chunks: Array, executionContext: ?Object): Array => ( 18 | chunks.reduce((ruleSet: Array, chunk: ?Interpolation) => { 19 | /* Remove falsey values */ 20 | if (chunk === undefined || chunk === null || chunk === false || chunk === '') return ruleSet 21 | /* Flatten ruleSet */ 22 | if (Array.isArray(chunk)) return [...ruleSet, ...flatten(chunk, executionContext)] 23 | 24 | /* Handle other components */ 25 | // $FlowFixMe not sure how to make this pass 26 | if (chunk.hasOwnProperty('styledComponentId')) return [...ruleSet, `.${chunk.styledComponentId}`] 27 | 28 | /* Either execute or defer the function */ 29 | if (typeof chunk === 'function') { 30 | return executionContext 31 | ? ruleSet.concat(...flatten([chunk(executionContext)], executionContext)) 32 | : ruleSet.concat(chunk) 33 | } 34 | 35 | /* Handle objects */ 36 | // $FlowFixMe have to add %checks somehow to isPlainObject 37 | return ruleSet.concat(isPlainObject(chunk) ? objToCss(chunk) : chunk.toString()) 38 | }, []) 39 | ) 40 | 41 | export default flatten 42 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-replace_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 0c20655ad5fff4c7cec587f61b9beae4 2 | // flow-typed version: <>/rollup-plugin-replace_v^1.1.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-replace' 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 | declare module 'rollup-plugin-replace' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-replace/dist/rollup-plugin-replace.cjs' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup-plugin-replace/dist/rollup-plugin-replace.es' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'rollup-plugin-replace/src/index' { 34 | declare module.exports: any; 35 | } 36 | 37 | // Filename aliases 38 | declare module 'rollup-plugin-replace/dist/rollup-plugin-replace.cjs.js' { 39 | declare module.exports: $Exports<'rollup-plugin-replace/dist/rollup-plugin-replace.cjs'>; 40 | } 41 | declare module 'rollup-plugin-replace/dist/rollup-plugin-replace.es.js' { 42 | declare module.exports: $Exports<'rollup-plugin-replace/dist/rollup-plugin-replace.es'>; 43 | } 44 | declare module 'rollup-plugin-replace/src/index.js' { 45 | declare module.exports: $Exports<'rollup-plugin-replace/src/index'>; 46 | } 47 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* Import singletons */ 4 | import flatten from './utils/flatten' 5 | import stringifyRules from './utils/stringifyRules' 6 | import generateAlphabeticName from './utils/generateAlphabeticName' 7 | import css from './constructors/css' 8 | import ServerStyleSheet from './models/ServerStyleSheet' 9 | import StyleSheetManager from './models/StyleSheetManager' 10 | 11 | /* Import singleton constructors */ 12 | import _StyledComponent from './models/StyledComponent' 13 | import _ComponentStyle from './models/ComponentStyle' 14 | import _styled from './constructors/styled' 15 | import _keyframes from './constructors/keyframes' 16 | import _injectGlobal from './constructors/injectGlobal' 17 | import _constructWithOptions from './constructors/constructWithOptions' 18 | 19 | /* Import components */ 20 | import ThemeProvider from './models/ThemeProvider' 21 | 22 | /* Import Higher Order Components */ 23 | import withTheme from './hoc/withTheme' 24 | 25 | /* Instantiate singletons */ 26 | const ComponentStyle = _ComponentStyle(generateAlphabeticName, flatten, stringifyRules) 27 | const constructWithOptions = _constructWithOptions(css) 28 | const StyledComponent = _StyledComponent(ComponentStyle, constructWithOptions) 29 | 30 | /* Instantiate exported singletons */ 31 | const keyframes = _keyframes(generateAlphabeticName, stringifyRules, css) 32 | const injectGlobal = _injectGlobal(stringifyRules, css) 33 | const styled = _styled(StyledComponent, constructWithOptions) 34 | 35 | /* Export everything */ 36 | export default styled 37 | export { 38 | css, 39 | keyframes, 40 | injectGlobal, 41 | ThemeProvider, 42 | withTheme, 43 | ServerStyleSheet, 44 | StyleSheetManager, 45 | } 46 | -------------------------------------------------------------------------------- /src/no-parser/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* Import no-parser singleton variants */ 4 | import flatten from './flatten' 5 | import stringifyRules from './stringifyRules' 6 | import css from './css' 7 | 8 | /* Import singletons */ 9 | import generateAlphabeticName from '../utils/generateAlphabeticName' 10 | import ServerStyleSheet from '../models/ServerStyleSheet' 11 | import StyleSheetManager from '../models/StyleSheetManager' 12 | 13 | /* Import singleton constructors */ 14 | import _StyledComponent from '../models/StyledComponent' 15 | import _ComponentStyle from '../models/ComponentStyle' 16 | import _styled from '../constructors/styled' 17 | import _keyframes from '../constructors/keyframes' 18 | import _injectGlobal from '../constructors/injectGlobal' 19 | import _constructWithOptions from '../constructors/constructWithOptions' 20 | 21 | /* Import components */ 22 | import ThemeProvider from '../models/ThemeProvider' 23 | 24 | /* Import Higher Order Components */ 25 | import withTheme from '../hoc/withTheme' 26 | 27 | /* Instantiate singletons */ 28 | const ComponentStyle = _ComponentStyle(generateAlphabeticName, flatten, stringifyRules) 29 | const constructWithOptions = _constructWithOptions(css) 30 | const StyledComponent = _StyledComponent(ComponentStyle, constructWithOptions) 31 | 32 | /* Instantiate exported singletons */ 33 | const keyframes = _keyframes(generateAlphabeticName, stringifyRules, css) 34 | const injectGlobal = _injectGlobal(stringifyRules, css) 35 | const styled = _styled(StyledComponent, constructWithOptions) 36 | 37 | /* Export everything */ 38 | export default styled 39 | export { 40 | css, 41 | keyframes, 42 | injectGlobal, 43 | ThemeProvider, 44 | withTheme, 45 | ServerStyleSheet, 46 | StyleSheetManager, 47 | } 48 | -------------------------------------------------------------------------------- /src/constructors/test/injectGlobal.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react' 3 | import { shallow } from 'enzyme' 4 | 5 | import _injectGlobal from '../injectGlobal' 6 | import stringifyRules from '../../utils/stringifyRules' 7 | import css from '../css' 8 | import { expectCSSMatches, resetStyled } from '../../test/utils' 9 | 10 | const injectGlobal = _injectGlobal(stringifyRules, css) 11 | 12 | let styled = resetStyled() 13 | const rule1 = 'width: 100%;' 14 | const rule2 = 'padding: 10px;' 15 | const rule3 = 'color: blue;' 16 | 17 | describe('injectGlobal', () => { 18 | beforeEach(() => { 19 | resetStyled() 20 | }) 21 | 22 | it(`should inject rules into the head`, () => { 23 | injectGlobal` 24 | html { 25 | ${rule1} 26 | } 27 | ` 28 | expectCSSMatches(` 29 | html { 30 | ${rule1} 31 | } 32 | `) 33 | }) 34 | 35 | it(`should non-destructively inject styles when called repeatedly`, () => { 36 | injectGlobal` 37 | html { 38 | ${rule1} 39 | } 40 | ` 41 | 42 | injectGlobal` 43 | a { 44 | ${rule2} 45 | } 46 | ` 47 | expectCSSMatches(` 48 | html { 49 | ${rule1} 50 | } 51 | a { 52 | ${rule2} 53 | } 54 | `) 55 | }) 56 | 57 | it(`should non-destructively inject styles when called after a component`, () => { 58 | const Comp = styled.div` 59 | ${rule3} 60 | ` 61 | shallow() 62 | 63 | injectGlobal` 64 | html { 65 | ${rule1} 66 | } 67 | ` 68 | 69 | expectCSSMatches(` 70 | .sc-a {} 71 | .b { 72 | ${rule3} 73 | } 74 | html { 75 | ${rule1} 76 | } 77 | `) 78 | }) 79 | }); 80 | -------------------------------------------------------------------------------- /flow-typed/npm/css-to-react-native_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: e7758ca1251748d9cb57509ae99126e8 2 | // flow-typed version: <>/css-to-react-native_v^1.0.6/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'css-to-react-native' 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 | declare module 'css-to-react-native' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'css-to-react-native/dist/grammar' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'css-to-react-native/dist/index' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'css-to-react-native/src/index' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'css-to-react-native/src/index.test' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'css-to-react-native/dist/grammar.js' { 43 | declare module.exports: $Exports<'css-to-react-native/dist/grammar'>; 44 | } 45 | declare module 'css-to-react-native/dist/index.js' { 46 | declare module.exports: $Exports<'css-to-react-native/dist/index'>; 47 | } 48 | declare module 'css-to-react-native/src/index.js' { 49 | declare module.exports: $Exports<'css-to-react-native/src/index'>; 50 | } 51 | declare module 'css-to-react-native/src/index.test.js' { 52 | declare module.exports: $Exports<'css-to-react-native/src/index.test'>; 53 | } 54 | -------------------------------------------------------------------------------- /flow-typed/npm/flow-copy-source_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 89b29e06dd0ed6dd184ac24b17ebf563 2 | // flow-typed version: <>/flow-copy-source_v^1.1.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'flow-copy-source' 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 | declare module 'flow-copy-source' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'flow-copy-source/bin/flow-copy-source' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'flow-copy-source/src/index' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'flow-copy-source/src/kefir-copy-file' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'flow-copy-source/src/kefir-glob' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'flow-copy-source/bin/flow-copy-source.js' { 43 | declare module.exports: $Exports<'flow-copy-source/bin/flow-copy-source'>; 44 | } 45 | declare module 'flow-copy-source/src/index.js' { 46 | declare module.exports: $Exports<'flow-copy-source/src/index'>; 47 | } 48 | declare module 'flow-copy-source/src/kefir-copy-file.js' { 49 | declare module.exports: $Exports<'flow-copy-source/src/kefir-copy-file'>; 50 | } 51 | declare module 'flow-copy-source/src/kefir-glob.js' { 52 | declare module.exports: $Exports<'flow-copy-source/src/kefir-glob'>; 53 | } 54 | -------------------------------------------------------------------------------- /src/vendor/postcss/comment.js: -------------------------------------------------------------------------------- 1 | import warnOnce from './warn-once'; 2 | import Node from './node'; 3 | 4 | /** 5 | * Represents a comment between declarations or statements (rule and at-rules). 6 | * 7 | * Comments inside selectors, at-rule parameters, or declaration values 8 | * will be stored in the `raws` properties explained above. 9 | * 10 | * @extends Node 11 | */ 12 | class Comment extends Node { 13 | 14 | constructor(defaults) { 15 | super(defaults); 16 | this.type = 'comment'; 17 | } 18 | 19 | get left() { 20 | warnOnce('Comment#left was deprecated. Use Comment#raws.left'); 21 | return this.raws.left; 22 | } 23 | 24 | set left(val) { 25 | warnOnce('Comment#left was deprecated. Use Comment#raws.left'); 26 | this.raws.left = val; 27 | } 28 | 29 | get right() { 30 | warnOnce('Comment#right was deprecated. Use Comment#raws.right'); 31 | return this.raws.right; 32 | } 33 | 34 | set right(val) { 35 | warnOnce('Comment#right was deprecated. Use Comment#raws.right'); 36 | this.raws.right = val; 37 | } 38 | 39 | /** 40 | * @memberof Comment# 41 | * @member {string} text - the comment’s text 42 | */ 43 | 44 | /** 45 | * @memberof Comment# 46 | * @member {object} raws - Information to generate byte-to-byte equal 47 | * node string as it was in the origin input. 48 | * 49 | * Every parser saves its own properties, 50 | * but the default CSS parser uses: 51 | * 52 | * * `before`: the space symbols before the node. 53 | * * `left`: the space symbols between `/*` and the comment’s text. 54 | * * `right`: the space symbols between the comment’s text. 55 | */ 56 | } 57 | 58 | export default Comment; 59 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic Example 6 | 7 | 8 | 9 |

Basic Example

10 |
11 | 12 | 13 | 14 | 15 | 16 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/models/ComponentStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import hashStr from '../vendor/glamor/hash' 3 | 4 | import type { RuleSet, NameGenerator, Flattener, Stringifier } from '../types' 5 | import StyleSheet from './StyleSheet' 6 | 7 | /* 8 | ComponentStyle is all the CSS-specific stuff, not 9 | the React-specific stuff. 10 | */ 11 | export default (nameGenerator: NameGenerator, flatten: Flattener, stringifyRules: Stringifier) => { 12 | class ComponentStyle { 13 | rules: RuleSet 14 | componentId: string 15 | 16 | constructor(rules: RuleSet, componentId: string) { 17 | this.rules = rules 18 | this.componentId = componentId 19 | if (!StyleSheet.instance.hasInjectedComponent(this.componentId)) { 20 | const placeholder = process.env.NODE_ENV !== 'production' ? `.${componentId} {}` : '' 21 | StyleSheet.instance.deferredInject(componentId, true, placeholder) 22 | } 23 | } 24 | 25 | /* 26 | * Flattens a rule set into valid CSS 27 | * Hashes it, wraps the whole chunk in a .hash1234 {} 28 | * Returns the hash to be injected on render() 29 | * */ 30 | generateAndInjectStyles(executionContext: Object, styleSheet: StyleSheet) { 31 | const flatCSS = flatten(this.rules, executionContext) 32 | const hash = hashStr(this.componentId + flatCSS.join('')) 33 | 34 | const existingName = styleSheet.getName(hash) 35 | if (existingName) return existingName 36 | 37 | const name = nameGenerator(hash) 38 | if (styleSheet.alreadyInjected(hash, name)) return name 39 | 40 | const css = `\n${stringifyRules(flatCSS, `.${name}`)}` 41 | styleSheet.inject(this.componentId, true, css, hash, name) 42 | return name 43 | } 44 | 45 | static generateName(str: string) { 46 | return nameGenerator(hashStr(str)) 47 | } 48 | } 49 | 50 | return ComponentStyle 51 | } 52 | -------------------------------------------------------------------------------- /flow-typed/npm/node-watch_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 882194d91554cedc0fed8c667eab6ca0 2 | // flow-typed version: <>/node-watch_v^0.4.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'node-watch' 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 | declare module 'node-watch' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'node-watch/lib/watch' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'node-watch/test/filter-option' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'node-watch/test/utils/tree' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'node-watch/test/watcher' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'node-watch/index' { 43 | declare module.exports: $Exports<'node-watch'>; 44 | } 45 | declare module 'node-watch/index.js' { 46 | declare module.exports: $Exports<'node-watch'>; 47 | } 48 | declare module 'node-watch/lib/watch.js' { 49 | declare module.exports: $Exports<'node-watch/lib/watch'>; 50 | } 51 | declare module 'node-watch/test/filter-option.js' { 52 | declare module.exports: $Exports<'node-watch/test/filter-option'>; 53 | } 54 | declare module 'node-watch/test/utils/tree.js' { 55 | declare module.exports: $Exports<'node-watch/test/utils/tree'>; 56 | } 57 | declare module 'node-watch/test/watcher.js' { 58 | declare module.exports: $Exports<'node-watch/test/watcher'>; 59 | } 60 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-inject_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: e302c5faf706cf8513d84378a47dd501 2 | // flow-typed version: <>/rollup-plugin-inject_v^2.0.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-inject' 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 | declare module 'rollup-plugin-inject' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-inject/dist/rollup-plugin-inject.cjs' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup-plugin-inject/dist/rollup-plugin-inject.es6' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'rollup-plugin-inject/src/index' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'rollup-plugin-inject/src/makeLegalIdentifier' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'rollup-plugin-inject/dist/rollup-plugin-inject.cjs.js' { 43 | declare module.exports: $Exports<'rollup-plugin-inject/dist/rollup-plugin-inject.cjs'>; 44 | } 45 | declare module 'rollup-plugin-inject/dist/rollup-plugin-inject.es6.js' { 46 | declare module.exports: $Exports<'rollup-plugin-inject/dist/rollup-plugin-inject.es6'>; 47 | } 48 | declare module 'rollup-plugin-inject/src/index.js' { 49 | declare module.exports: $Exports<'rollup-plugin-inject/src/index'>; 50 | } 51 | declare module 'rollup-plugin-inject/src/makeLegalIdentifier.js' { 52 | declare module.exports: $Exports<'rollup-plugin-inject/src/makeLegalIdentifier'>; 53 | } 54 | -------------------------------------------------------------------------------- /src/hoc/withTheme.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* globals ReactClass */ 3 | 4 | import React from 'react' 5 | import PropTypes from 'prop-types' 6 | import hoistStatics from 'hoist-non-react-statics' 7 | import { CHANNEL } from '../models/ThemeProvider' 8 | import _isStyledComponent from '../utils/isStyledComponent' 9 | 10 | const wrapWithTheme = (Component: ReactClass) => { 11 | const componentName = ( 12 | Component.displayName || 13 | Component.name || 14 | 'Component' 15 | ) 16 | 17 | const isStyledComponent = _isStyledComponent(Component) 18 | 19 | class WithTheme extends React.Component { 20 | static displayName = `WithTheme(${componentName})` 21 | 22 | // NOTE: This is so that isStyledComponent passes for the innerRef unwrapping 23 | static styledComponentId = 'withTheme' 24 | 25 | static contextTypes = { 26 | [CHANNEL]: PropTypes.func, 27 | }; 28 | 29 | state: { theme?: ?Object } = {}; 30 | unsubscribe: () => void; 31 | 32 | componentWillMount() { 33 | if (!this.context[CHANNEL]) { 34 | throw new Error('[withTheme] Please use ThemeProvider to be able to use withTheme') 35 | } 36 | 37 | const subscribe = this.context[CHANNEL] 38 | this.unsubscribe = subscribe(theme => { 39 | this.setState({ theme }) 40 | }) 41 | } 42 | 43 | componentWillUnmount() { 44 | if (typeof this.unsubscribe === 'function') this.unsubscribe() 45 | } 46 | 47 | render() { 48 | // eslint-disable-next-line react/prop-types 49 | const { innerRef } = this.props 50 | const { theme } = this.state 51 | 52 | return ( 53 | 59 | ) 60 | } 61 | } 62 | 63 | return hoistStatics(WithTheme, Component) 64 | } 65 | 66 | export default wrapWithTheme 67 | -------------------------------------------------------------------------------- /example/devServer.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const exec = require('child_process').exec 3 | const Express = require('express') 4 | const watch = require('node-watch') 5 | 6 | import fs from 'fs' 7 | import React from 'react' 8 | import { renderToString } from 'react-dom/server' 9 | import { ServerStyleSheet } from '../dist/styled-components' 10 | import getExample from "./example" 11 | 12 | const HTML = fs.readFileSync(__dirname + '/index.html').toString() 13 | 14 | const srcPath = __dirname.split('/example')[0] + '/src'; 15 | 16 | const hotBuild = () => exec('npm run build:dist', (err, stdout, stderr) => { 17 | if (err) throw err 18 | if (stdout) { 19 | console.log(`npm run build:dist --- ${stdout}`) 20 | } 21 | if (stderr) { 22 | console.log(`npm run build:dist --- ${stderr}`) 23 | } 24 | }) 25 | 26 | watch(srcPath, (filename) => { 27 | console.log(`${filename} file has changed`) 28 | hotBuild() 29 | }) 30 | 31 | const app = new Express() 32 | const port = 3000 33 | 34 | app.use(Express.static(__dirname)) 35 | app.use(Express.static('dist')) 36 | 37 | app.get('/with-perf.html', (req, res) => { 38 | res.sendFile(path.join(__dirname, 'with-perf.html')) 39 | }) 40 | 41 | app.get('/ssr.html', (req, res) => { 42 | const Example = getExample() 43 | 44 | const sheet = new ServerStyleSheet() 45 | const html = renderToString(sheet.collectStyles()) 46 | const css = sheet.getStyleTags() 47 | res.send( 48 | HTML 49 | .replace(//, html) 50 | .replace(//, css) 51 | ) 52 | }) 53 | 54 | app.get('/', (req, res) => { 55 | res.sendFile(path.join(__dirname, 'index.html')) 56 | }) 57 | 58 | app.listen(port, error => { 59 | /* eslint-disable no-console */ 60 | if (error) { 61 | console.error(error) 62 | } else { 63 | console.info( 64 | '🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.', 65 | port, 66 | port 67 | ) 68 | } 69 | /* eslint-enable no-console */ 70 | }) 71 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-node-resolve_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 4b83a6f0d8b1309dc9f0e6a44407c469 2 | // flow-typed version: <>/rollup-plugin-node-resolve_v^2.0.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-node-resolve' 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 | declare module 'rollup-plugin-node-resolve' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.cjs' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.es6' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'rollup-plugin-node-resolve/src/empty' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'rollup-plugin-node-resolve/src/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.cjs.js' { 43 | declare module.exports: $Exports<'rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.cjs'>; 44 | } 45 | declare module 'rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.es6.js' { 46 | declare module.exports: $Exports<'rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.es6'>; 47 | } 48 | declare module 'rollup-plugin-node-resolve/src/empty.js' { 49 | declare module.exports: $Exports<'rollup-plugin-node-resolve/src/empty'>; 50 | } 51 | declare module 'rollup-plugin-node-resolve/src/index.js' { 52 | declare module.exports: $Exports<'rollup-plugin-node-resolve/src/index'>; 53 | } 54 | -------------------------------------------------------------------------------- /src/native/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* eslint-disable import/no-unresolved */ 4 | import reactNative from 'react-native' 5 | 6 | import _InlineStyle from '../models/InlineStyle' 7 | import _StyledNativeComponent from '../models/StyledNativeComponent' 8 | import _constructWithOptions from '../constructors/constructWithOptions' 9 | 10 | import css from '../constructors/css' 11 | import ThemeProvider from '../models/ThemeProvider' 12 | import withTheme from '../hoc/withTheme' 13 | 14 | import type { Target } from '../types' 15 | 16 | const constructWithOptions = _constructWithOptions(css) 17 | const InlineStyle = _InlineStyle(reactNative.StyleSheet) 18 | const StyledNativeComponent = _StyledNativeComponent(constructWithOptions, InlineStyle) 19 | const styled = (tag: Target) => constructWithOptions(StyledNativeComponent, tag) 20 | 21 | /* React native lazy-requires each of these modules for some reason, so let's 22 | * assume it's for a good reason and not eagerly load them all */ 23 | const aliases = `ActivityIndicator ActivityIndicatorIOS ART Button DatePickerIOS DrawerLayoutAndroid 24 | Image ImageEditor ImageStore KeyboardAvoidingView ListView MapView Modal Navigator NavigatorIOS 25 | Picker PickerIOS ProgressBarAndroid ProgressViewIOS ScrollView SegmentedControlIOS Slider 26 | SliderIOS SnapshotViewIOS Switch RecyclerViewBackedScrollView RefreshControl StatusBar 27 | SwipeableListView SwitchAndroid SwitchIOS TabBarIOS Text TextInput ToastAndroid ToolbarAndroid 28 | Touchable TouchableHighlight TouchableNativeFeedback TouchableOpacity TouchableWithoutFeedback 29 | View ViewPagerAndroid WebView FlatList SectionList VirtualizedList` 30 | 31 | /* Define a getter for each alias which simply gets the reactNative component 32 | * and passes it to styled */ 33 | aliases.split(/\s+/m).forEach(alias => Object.defineProperty(styled, alias, { 34 | enumerable: true, 35 | configurable: false, 36 | get() { 37 | return styled(reactNative[alias]) 38 | }, 39 | })) 40 | 41 | export { css, ThemeProvider, withTheme } 42 | export default styled 43 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-flow-react-proptypes_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 0f9b5af853d4d0b2d667d57fdf0005cb 2 | // flow-typed version: <>/babel-plugin-flow-react-proptypes_v^0.18.2/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-flow-react-proptypes' 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 | declare module 'babel-plugin-flow-react-proptypes' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-flow-react-proptypes/lib/convertToPropTypes' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'babel-plugin-flow-react-proptypes/lib/index' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'babel-plugin-flow-react-proptypes/lib/makePropTypesAst' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'babel-plugin-flow-react-proptypes/lib/util' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js' { 43 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/convertToPropTypes'>; 44 | } 45 | declare module 'babel-plugin-flow-react-proptypes/lib/index.js' { 46 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/index'>; 47 | } 48 | declare module 'babel-plugin-flow-react-proptypes/lib/makePropTypesAst.js' { 49 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/makePropTypesAst'>; 50 | } 51 | declare module 'babel-plugin-flow-react-proptypes/lib/util.js' { 52 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/util'>; 53 | } 54 | -------------------------------------------------------------------------------- /src/models/InlineStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* eslint-disable import/no-unresolved */ 3 | import transformDeclPairs from 'css-to-react-native' 4 | 5 | import hashStr from '../vendor/glamor/hash' 6 | import type { RuleSet, StyleSheet } from '../types' 7 | import flatten from '../utils/flatten' 8 | import parse from '../vendor/postcss-safe-parser/parse' 9 | 10 | let generated = {} 11 | 12 | export const resetStyleCache = () => { 13 | generated = {} 14 | } 15 | 16 | /* 17 | InlineStyle takes arbitrary CSS and generates a flat object 18 | */ 19 | export default (styleSheet: StyleSheet) => { 20 | class InlineStyle { 21 | rules: RuleSet 22 | 23 | constructor(rules: RuleSet) { 24 | this.rules = rules 25 | } 26 | 27 | generateStyleObject(executionContext: Object) { 28 | const flatCSS = flatten(this.rules, executionContext).join('') 29 | const hash = hashStr(flatCSS) 30 | if (!generated[hash]) { 31 | const root = parse(flatCSS) 32 | const declPairs = [] 33 | root.each(node => { 34 | if (node.type === 'decl') { 35 | declPairs.push([node.prop, node.value]) 36 | } else { 37 | /* eslint-disable no-console */ 38 | console.warn(`Node of type ${node.type} not supported as an inline style`) 39 | } 40 | }) 41 | // RN currently does not support differing values for the corner radii of Image 42 | // components (but does for View). It is almost impossible to tell whether we'll have 43 | // support, so we'll just disable multiple values here. 44 | // https://github.com/styled-components/css-to-react-native/issues/11 45 | const styleObject = transformDeclPairs(declPairs, [ 46 | 'borderRadius', 47 | 'borderWidth', 48 | 'borderColor', 49 | 'borderStyle', 50 | ]) 51 | const styles = styleSheet.create({ 52 | generated: styleObject, 53 | }) 54 | generated[hash] = styles.generated 55 | } 56 | return generated[hash] 57 | } 58 | } 59 | 60 | return InlineStyle 61 | } 62 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-loader_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 860184a65864273e2021c922c56fddd1 2 | // flow-typed version: <>/babel-loader_v^6.2.10/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-loader' 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 | declare module 'babel-loader' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-loader/lib/fs-cache' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'babel-loader/lib/index' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'babel-loader/lib/resolve-rc' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'babel-loader/lib/utils/exists' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'babel-loader/lib/utils/read' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'babel-loader/lib/utils/relative' { 46 | declare module.exports: any; 47 | } 48 | 49 | // Filename aliases 50 | declare module 'babel-loader/lib/fs-cache.js' { 51 | declare module.exports: $Exports<'babel-loader/lib/fs-cache'>; 52 | } 53 | declare module 'babel-loader/lib/index.js' { 54 | declare module.exports: $Exports<'babel-loader/lib/index'>; 55 | } 56 | declare module 'babel-loader/lib/resolve-rc.js' { 57 | declare module.exports: $Exports<'babel-loader/lib/resolve-rc'>; 58 | } 59 | declare module 'babel-loader/lib/utils/exists.js' { 60 | declare module.exports: $Exports<'babel-loader/lib/utils/exists'>; 61 | } 62 | declare module 'babel-loader/lib/utils/read.js' { 63 | declare module.exports: $Exports<'babel-loader/lib/utils/read'>; 64 | } 65 | declare module 'babel-loader/lib/utils/relative.js' { 66 | declare module.exports: $Exports<'babel-loader/lib/utils/relative'>; 67 | } 68 | -------------------------------------------------------------------------------- /flow-typed/npm/eslint-plugin-flowtype-errors_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 410eef235a4131f68e55172ce185934c 2 | // flow-typed version: <>/eslint-plugin-flowtype-errors_v^2.0.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'eslint-plugin-flowtype-errors' 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 | declare module 'eslint-plugin-flowtype-errors' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'eslint-plugin-flowtype-errors/dist/collect' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'eslint-plugin-flowtype-errors/dist/filter' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'eslint-plugin-flowtype-errors/dist/format' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'eslint-plugin-flowtype-errors/dist/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'eslint-plugin-flowtype-errors/dist/collect.js' { 43 | declare module.exports: $Exports<'eslint-plugin-flowtype-errors/dist/collect'>; 44 | } 45 | declare module 'eslint-plugin-flowtype-errors/dist/filter.js' { 46 | declare module.exports: $Exports<'eslint-plugin-flowtype-errors/dist/filter'>; 47 | } 48 | declare module 'eslint-plugin-flowtype-errors/dist/format.js' { 49 | declare module.exports: $Exports<'eslint-plugin-flowtype-errors/dist/format'>; 50 | } 51 | declare module 'eslint-plugin-flowtype-errors/dist/index.js' { 52 | declare module.exports: $Exports<'eslint-plugin-flowtype-errors/dist/index'>; 53 | } 54 | declare module 'eslint-plugin-flowtype-errors/index' { 55 | declare module.exports: $Exports<'eslint-plugin-flowtype-errors'>; 56 | } 57 | declare module 'eslint-plugin-flowtype-errors/index.js' { 58 | declare module.exports: $Exports<'eslint-plugin-flowtype-errors'>; 59 | } 60 | -------------------------------------------------------------------------------- /src/utils/domElements.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // Thanks to ReactDOMFactories for this handy list! 3 | 4 | export default [ 5 | 'a', 6 | 'abbr', 7 | 'address', 8 | 'area', 9 | 'article', 10 | 'aside', 11 | 'audio', 12 | 'b', 13 | 'base', 14 | 'bdi', 15 | 'bdo', 16 | 'big', 17 | 'blockquote', 18 | 'body', 19 | 'br', 20 | 'button', 21 | 'canvas', 22 | 'caption', 23 | 'cite', 24 | 'code', 25 | 'col', 26 | 'colgroup', 27 | 'data', 28 | 'datalist', 29 | 'dd', 30 | 'del', 31 | 'details', 32 | 'dfn', 33 | 'dialog', 34 | 'div', 35 | 'dl', 36 | 'dt', 37 | 'em', 38 | 'embed', 39 | 'fieldset', 40 | 'figcaption', 41 | 'figure', 42 | 'footer', 43 | 'form', 44 | 'h1', 45 | 'h2', 46 | 'h3', 47 | 'h4', 48 | 'h5', 49 | 'h6', 50 | 'head', 51 | 'header', 52 | 'hgroup', 53 | 'hr', 54 | 'html', 55 | 'i', 56 | 'iframe', 57 | 'img', 58 | 'input', 59 | 'ins', 60 | 'kbd', 61 | 'keygen', 62 | 'label', 63 | 'legend', 64 | 'li', 65 | 'link', 66 | 'main', 67 | 'map', 68 | 'mark', 69 | 'menu', 70 | 'menuitem', 71 | 'meta', 72 | 'meter', 73 | 'nav', 74 | 'noscript', 75 | 'object', 76 | 'ol', 77 | 'optgroup', 78 | 'option', 79 | 'output', 80 | 'p', 81 | 'param', 82 | 'picture', 83 | 'pre', 84 | 'progress', 85 | 'q', 86 | 'rp', 87 | 'rt', 88 | 'ruby', 89 | 's', 90 | 'samp', 91 | 'script', 92 | 'section', 93 | 'select', 94 | 'small', 95 | 'source', 96 | 'span', 97 | 'strong', 98 | 'style', 99 | 'sub', 100 | 'summary', 101 | 'sup', 102 | 'table', 103 | 'tbody', 104 | 'td', 105 | 'textarea', 106 | 'tfoot', 107 | 'th', 108 | 'thead', 109 | 'time', 110 | 'title', 111 | 'tr', 112 | 'track', 113 | 'u', 114 | 'ul', 115 | 'var', 116 | 'video', 117 | 'wbr', 118 | 119 | // SVG 120 | 'circle', 121 | 'clipPath', 122 | 'defs', 123 | 'ellipse', 124 | 'g', 125 | 'image', 126 | 'line', 127 | 'linearGradient', 128 | 'mask', 129 | 'path', 130 | 'pattern', 131 | 'polygon', 132 | 'polyline', 133 | 'radialGradient', 134 | 'rect', 135 | 'stop', 136 | 'svg', 137 | 'text', 138 | 'tspan', 139 | ] 140 | 141 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsRules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "indent": [ 9 | true, 10 | "spaces" 11 | ], 12 | "no-duplicate-variable": true, 13 | "no-eval": true, 14 | "no-trailing-whitespace": true, 15 | "no-unsafe-finally": true, 16 | "one-line": [ 17 | true, 18 | "check-open-brace", 19 | "check-whitespace" 20 | ], 21 | "quotemark": [ 22 | true, 23 | "double" 24 | ], 25 | "semicolon": [ 26 | true, 27 | "always" 28 | ], 29 | "triple-equals": [ 30 | true, 31 | "allow-null-check" 32 | ], 33 | "variable-name": [ 34 | true, 35 | "ban-keywords" 36 | ], 37 | "whitespace": [ 38 | true, 39 | "check-branch", 40 | "check-decl", 41 | "check-operator", 42 | "check-separator", 43 | "check-type" 44 | ] 45 | }, 46 | "rules": { 47 | "class-name": true, 48 | "comment-format": [ 49 | true, 50 | "check-space" 51 | ], 52 | "indent": [ 53 | true, 54 | "spaces" 55 | ], 56 | "no-eval": true, 57 | "no-internal-module": true, 58 | "no-trailing-whitespace": true, 59 | "no-unsafe-finally": true, 60 | "no-var-keyword": true, 61 | "one-line": [ 62 | true, 63 | "check-open-brace", 64 | "check-whitespace" 65 | ], 66 | "quotemark": [ 67 | true, 68 | "double" 69 | ], 70 | "semicolon": [ 71 | true, 72 | "always" 73 | ], 74 | "triple-equals": [ 75 | true, 76 | "allow-null-check" 77 | ], 78 | "typedef-whitespace": [ 79 | true, 80 | { 81 | "call-signature": "nospace", 82 | "index-signature": "nospace", 83 | "parameter": "nospace", 84 | "property-declaration": "nospace", 85 | "variable-declaration": "nospace" 86 | } 87 | ], 88 | "variable-name": [ 89 | true, 90 | "ban-keywords" 91 | ], 92 | "whitespace": [ 93 | true, 94 | "check-branch", 95 | "check-decl", 96 | "check-operator", 97 | "check-separator", 98 | "check-type" 99 | ] 100 | } 101 | } -------------------------------------------------------------------------------- /src/vendor/postcss-nested/index.js: -------------------------------------------------------------------------------- 1 | function selectors(parent, node) { 2 | var result = []; 3 | parent.selectors.forEach(function (i) { 4 | node.selectors.forEach(function (j) { 5 | if (j.indexOf('&') === -1) { 6 | result.push(i + ' ' + j); 7 | } else { 8 | result.push(j.replace(/&/g, i)); 9 | } 10 | }); 11 | }); 12 | return result; 13 | } 14 | 15 | function pickComment(comment, after) { 16 | if (comment && comment.type === 'comment') { 17 | return comment.moveAfter(after); 18 | } else { 19 | return after; 20 | } 21 | } 22 | 23 | function atruleChilds(rule, atrule) { 24 | var children = []; 25 | atrule.each(function (child) { 26 | if (child.type === 'comment') { 27 | children.push(child); 28 | } 29 | if (child.type === 'decl') { 30 | children.push(child); 31 | } else if (child.type === 'rule') { 32 | child.selectors = selectors(rule, child); 33 | } else if (child.type === 'atrule') { 34 | atruleChilds(rule, child); 35 | } 36 | }); 37 | if (children.length) { 38 | var clone = rule.clone({ nodes: [] }); 39 | for (var i = 0; i < children.length; i++) children[i].moveTo(clone); 40 | atrule.prepend(clone); 41 | } 42 | } 43 | 44 | function processRule(rule, bubble) { 45 | var unwrapped = false; 46 | var after = rule; 47 | rule.each(function (child) { 48 | if (child.type === 'rule') { 49 | unwrapped = true; 50 | child.selectors = selectors(rule, child); 51 | after = pickComment(child.prev(), after); 52 | after = child.moveAfter(after); 53 | } else if (child.type === 'atrule') { 54 | if (bubble.indexOf(child.name) !== -1) { 55 | unwrapped = true; 56 | atruleChilds(rule, child); 57 | after = pickComment(child.prev(), after); 58 | after = child.moveAfter(after); 59 | } 60 | } 61 | }); 62 | if (unwrapped) { 63 | rule.raws.semicolon = true; 64 | if (rule.nodes.length === 0) rule.remove(); 65 | } 66 | } 67 | 68 | var bubble = ['media', 'supports', 'document']; 69 | 70 | const process = node => { 71 | node.each(function (child) { 72 | if (child.type === 'rule') { 73 | processRule(child, bubble); 74 | } else if (child.type === 'atrule') { 75 | process(child); 76 | } 77 | }); 78 | }; 79 | 80 | export default process; 81 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-babel_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 81da4abedf4b4c63fd96dff12d87b31b 2 | // flow-typed version: <>/rollup-plugin-babel_v^2.7.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-babel' 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 | declare module 'rollup-plugin-babel' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-babel/dist/rollup-plugin-babel.cjs' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup-plugin-babel/dist/rollup-plugin-babel.es' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'rollup-plugin-babel/src/constants' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'rollup-plugin-babel/src/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'rollup-plugin-babel/src/preflightCheck' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'rollup-plugin-babel/src/utils' { 46 | declare module.exports: any; 47 | } 48 | 49 | // Filename aliases 50 | declare module 'rollup-plugin-babel/dist/rollup-plugin-babel.cjs.js' { 51 | declare module.exports: $Exports<'rollup-plugin-babel/dist/rollup-plugin-babel.cjs'>; 52 | } 53 | declare module 'rollup-plugin-babel/dist/rollup-plugin-babel.es.js' { 54 | declare module.exports: $Exports<'rollup-plugin-babel/dist/rollup-plugin-babel.es'>; 55 | } 56 | declare module 'rollup-plugin-babel/src/constants.js' { 57 | declare module.exports: $Exports<'rollup-plugin-babel/src/constants'>; 58 | } 59 | declare module 'rollup-plugin-babel/src/index.js' { 60 | declare module.exports: $Exports<'rollup-plugin-babel/src/index'>; 61 | } 62 | declare module 'rollup-plugin-babel/src/preflightCheck.js' { 63 | declare module.exports: $Exports<'rollup-plugin-babel/src/preflightCheck'>; 64 | } 65 | declare module 'rollup-plugin-babel/src/utils.js' { 66 | declare module.exports: $Exports<'rollup-plugin-babel/src/utils'>; 67 | } 68 | -------------------------------------------------------------------------------- /flow-typed/npm/expect_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: b074889a4c5f7bfb8995bdb500322cad 2 | // flow-typed version: <>/expect_v^1.20.2/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'expect' 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 | declare module 'expect' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'expect/lib/assert' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'expect/lib/Expectation' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'expect/lib/extend' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'expect/lib/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'expect/lib/SpyUtils' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'expect/lib/TestUtils' { 46 | declare module.exports: any; 47 | } 48 | 49 | declare module 'expect/umd/expect' { 50 | declare module.exports: any; 51 | } 52 | 53 | declare module 'expect/umd/expect.min' { 54 | declare module.exports: any; 55 | } 56 | 57 | // Filename aliases 58 | declare module 'expect/lib/assert.js' { 59 | declare module.exports: $Exports<'expect/lib/assert'>; 60 | } 61 | declare module 'expect/lib/Expectation.js' { 62 | declare module.exports: $Exports<'expect/lib/Expectation'>; 63 | } 64 | declare module 'expect/lib/extend.js' { 65 | declare module.exports: $Exports<'expect/lib/extend'>; 66 | } 67 | declare module 'expect/lib/index.js' { 68 | declare module.exports: $Exports<'expect/lib/index'>; 69 | } 70 | declare module 'expect/lib/SpyUtils.js' { 71 | declare module.exports: $Exports<'expect/lib/SpyUtils'>; 72 | } 73 | declare module 'expect/lib/TestUtils.js' { 74 | declare module.exports: $Exports<'expect/lib/TestUtils'>; 75 | } 76 | declare module 'expect/umd/expect.js' { 77 | declare module.exports: $Exports<'expect/umd/expect'>; 78 | } 79 | declare module 'expect/umd/expect.min.js' { 80 | declare module.exports: $Exports<'expect/umd/expect.min'>; 81 | } 82 | -------------------------------------------------------------------------------- /example/with-perf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Example with Perf logging 6 | 7 | 8 |

Example with Perf logging

9 |
10 | 11 | 12 | 13 | 14 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /flow-typed/npm/react-addons-test-utils_v15.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 323fcc1a3353d5f7a36c5f1edcd963ef 2 | // flow-typed version: 41f45a7d8c/react-addons-test-utils_v15.x.x/flow_>=v0.23.x 3 | 4 | declare type ReactAddonTest$FunctionOrComponentClass = React$Component | Function; 5 | declare module 'react-addons-test-utils' { 6 | declare var Simulate: { 7 | [eventName: string]: (element: Element, eventData?: Object) => void; 8 | }; 9 | declare function renderIntoDocument(instance: React$Element): React$Component; 10 | declare function mockComponent(componentClass: ReactAddonTest$FunctionOrComponentClass, mockTagName?: string): Object; 11 | declare function isElement(element: React$Element): boolean; 12 | declare function isElementOfType(element: React$Element, componentClass: ReactAddonTest$FunctionOrComponentClass): boolean; 13 | declare function isDOMComponent(instance: React$Component): boolean; 14 | declare function isCompositeComponent(instance: React$Component): boolean; 15 | declare function isCompositeComponentWithType(instance: React$Component, componentClass: ReactAddonTest$FunctionOrComponentClass): boolean; 16 | declare function findAllInRenderedTree(tree: React$Component, test: (child: React$Component) => boolean): Array>; 17 | declare function scryRenderedDOMComponentsWithClass(tree: React$Component, className: string): Array; 18 | declare function findRenderedDOMComponentWithClass(tree: React$Component, className: string): ?Element; 19 | declare function scryRenderedDOMComponentsWithTag(tree: React$Component, tagName: string): Array; 20 | declare function findRenderedDOMComponentWithTag(tree: React$Component, tagName: string): ?Element; 21 | declare function scryRenderedComponentsWithType(tree: React$Component, componentClass: ReactAddonTest$FunctionOrComponentClass): Array>; 22 | declare function findRenderedComponentWithType(tree: React$Component, componentClass: ReactAddonTest$FunctionOrComponentClass): ?React$Component; 23 | declare class ReactShallowRender { 24 | render(element: React$Element): void; 25 | getRenderOutput(): React$Element; 26 | } 27 | declare function createRenderer(): ReactShallowRender; 28 | } 29 | -------------------------------------------------------------------------------- /src/vendor/postcss-safe-parser/safe-parser.js: -------------------------------------------------------------------------------- 1 | import tokenize from '../postcss/tokenize'; 2 | import Comment from '../postcss/comment'; 3 | import Parser from '../postcss/parser'; 4 | 5 | export default class SafeParser extends Parser { 6 | 7 | tokenize() { 8 | this.tokens = tokenize(this.input, { ignoreErrors: true }); 9 | } 10 | 11 | comment(token) { 12 | let node = new Comment(); 13 | this.init(node, token[2], token[3]); 14 | node.source.end = { line: token[4], column: token[5] }; 15 | 16 | let text = token[1].slice(2); 17 | if ( text.slice(-2) === '*/' ) text = text.slice(0, -2); 18 | 19 | if ( /^\s*$/.test(text) ) { 20 | node.text = ''; 21 | node.raws.left = text; 22 | node.raws.right = ''; 23 | } else { 24 | let match = text.match(/^(\s*)([^]*[^\s])(\s*)$/); 25 | node.text = match[2]; 26 | node.raws.left = match[1]; 27 | node.raws.right = match[3]; 28 | } 29 | } 30 | 31 | unclosedBracket() { } 32 | 33 | unknownWord(start) { 34 | let buffer = this.tokens.slice(start, this.pos + 1); 35 | this.spaces += buffer.map( i => i[1] ).join(''); 36 | } 37 | 38 | unexpectedClose() { 39 | this.current.raws.after += '}'; 40 | } 41 | 42 | doubleColon() { } 43 | 44 | unnamedAtrule(node) { 45 | node.name = ''; 46 | } 47 | 48 | precheckMissedSemicolon(tokens) { 49 | let colon = this.colon(tokens); 50 | if ( colon === false ) return; 51 | 52 | let split; 53 | for ( split = colon - 1; split >= 0; split-- ) { 54 | if ( tokens[split][0] === 'word' ) break; 55 | } 56 | for ( split -= 1; split >= 0; split-- ) { 57 | if ( tokens[split][0] !== 'space' ) { 58 | split += 1; 59 | break; 60 | } 61 | } 62 | let other = tokens.splice(split, tokens.length - split); 63 | this.decl(other); 64 | } 65 | 66 | checkMissedSemicolon() { } 67 | 68 | endFile() { 69 | if ( this.current.nodes && this.current.nodes.length ) { 70 | this.current.raws.semicolon = this.semicolon; 71 | } 72 | this.current.raws.after = (this.current.raws.after || '') + this.spaces; 73 | 74 | while ( this.current.parent ) { 75 | this.current = this.current.parent; 76 | this.current.raws.after = ''; 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /flow-typed/npm/eslint-config-airbnb_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: f831684346237a5dd08778a06e2e3b90 2 | // flow-typed version: <>/eslint-config-airbnb_v^13.0.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'eslint-config-airbnb' 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 | declare module 'eslint-config-airbnb' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'eslint-config-airbnb/base' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'eslint-config-airbnb/legacy' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'eslint-config-airbnb/rules/react-a11y' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'eslint-config-airbnb/rules/react' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'eslint-config-airbnb/test/test-base' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'eslint-config-airbnb/test/test-react-order' { 46 | declare module.exports: any; 47 | } 48 | 49 | // Filename aliases 50 | declare module 'eslint-config-airbnb/base.js' { 51 | declare module.exports: $Exports<'eslint-config-airbnb/base'>; 52 | } 53 | declare module 'eslint-config-airbnb/index' { 54 | declare module.exports: $Exports<'eslint-config-airbnb'>; 55 | } 56 | declare module 'eslint-config-airbnb/index.js' { 57 | declare module.exports: $Exports<'eslint-config-airbnb'>; 58 | } 59 | declare module 'eslint-config-airbnb/legacy.js' { 60 | declare module.exports: $Exports<'eslint-config-airbnb/legacy'>; 61 | } 62 | declare module 'eslint-config-airbnb/rules/react-a11y.js' { 63 | declare module.exports: $Exports<'eslint-config-airbnb/rules/react-a11y'>; 64 | } 65 | declare module 'eslint-config-airbnb/rules/react.js' { 66 | declare module.exports: $Exports<'eslint-config-airbnb/rules/react'>; 67 | } 68 | declare module 'eslint-config-airbnb/test/test-base.js' { 69 | declare module.exports: $Exports<'eslint-config-airbnb/test/test-base'>; 70 | } 71 | declare module 'eslint-config-airbnb/test/test-react-order.js' { 72 | declare module.exports: $Exports<'eslint-config-airbnb/test/test-react-order'>; 73 | } 74 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-eslint_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: c7d003afd341bba28bbb4cfe64d13a12 2 | // flow-typed version: <>/babel-eslint_v^7.1.1/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-eslint' 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 | declare module 'babel-eslint' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-eslint/babylon-to-espree/attachComments' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'babel-eslint/babylon-to-espree/convertTemplateType' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'babel-eslint/babylon-to-espree/index' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'babel-eslint/babylon-to-espree/toAST' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'babel-eslint/babylon-to-espree/toToken' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'babel-eslint/babylon-to-espree/toTokens' { 46 | declare module.exports: any; 47 | } 48 | 49 | // Filename aliases 50 | declare module 'babel-eslint/babylon-to-espree/attachComments.js' { 51 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/attachComments'>; 52 | } 53 | declare module 'babel-eslint/babylon-to-espree/convertTemplateType.js' { 54 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/convertTemplateType'>; 55 | } 56 | declare module 'babel-eslint/babylon-to-espree/index.js' { 57 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/index'>; 58 | } 59 | declare module 'babel-eslint/babylon-to-espree/toAST.js' { 60 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toAST'>; 61 | } 62 | declare module 'babel-eslint/babylon-to-espree/toToken.js' { 63 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toToken'>; 64 | } 65 | declare module 'babel-eslint/babylon-to-espree/toTokens.js' { 66 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toTokens'>; 67 | } 68 | declare module 'babel-eslint/index' { 69 | declare module.exports: $Exports<'babel-eslint'>; 70 | } 71 | declare module 'babel-eslint/index.js' { 72 | declare module.exports: $Exports<'babel-eslint'>; 73 | } 74 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable flowtype/require-valid-file-annotation, no-console, import/extensions */ 2 | import nodeResolve from 'rollup-plugin-node-resolve' 3 | import replace from 'rollup-plugin-replace' 4 | import commonjs from 'rollup-plugin-commonjs' 5 | import inject from 'rollup-plugin-inject' 6 | import babel from 'rollup-plugin-babel' 7 | import json from 'rollup-plugin-json' 8 | import flow from 'rollup-plugin-flow' 9 | import uglify from 'rollup-plugin-uglify' 10 | import visualizer from 'rollup-plugin-visualizer' 11 | 12 | const processShim = '\0process-shim' 13 | 14 | const prod = process.env.PRODUCTION 15 | const esbundle = process.env.ESBUNDLE 16 | 17 | let targets 18 | if (prod) { 19 | console.log('Creating production UMD bundle...') 20 | targets = [{ dest: 'dist/styled-components.min.js', format: 'umd' }] 21 | } else if (esbundle) { 22 | console.log('Creating ES modules bundle...') 23 | targets = [{ dest: 'dist/styled-components.es.js', format: 'es' }] 24 | } else { 25 | console.log('Creating development UMD bundle') 26 | targets = [{ dest: 'dist/styled-components.js', format: 'umd' }] 27 | } 28 | 29 | const plugins = [ 30 | // Unlike Webpack and Browserify, Rollup doesn't automatically shim Node 31 | // builtins like `process`. This ad-hoc plugin creates a 'virtual module' 32 | // which includes a shim containing just the parts the bundle needs. 33 | { 34 | resolveId(importee) { 35 | if (importee === processShim) return importee 36 | return null 37 | }, 38 | load(id) { 39 | if (id === processShim) return 'export default { argv: [], env: {} }' 40 | return null 41 | }, 42 | }, 43 | flow(), 44 | nodeResolve(), 45 | commonjs(), 46 | replace({ 47 | 'process.env.NODE_ENV': JSON.stringify(prod ? 'production' : 'development'), 48 | }), 49 | inject({ 50 | process: processShim, 51 | }), 52 | babel({ 53 | babelrc: false, 54 | presets: [ 55 | ['env', { modules: false, loose: true }], 56 | 'react', 57 | ], 58 | plugins: [ 59 | !prod && 'flow-react-proptypes', 60 | prod && 'transform-react-remove-prop-types', 61 | 'transform-flow-strip-types', 62 | 'external-helpers', 63 | 'transform-object-rest-spread', 64 | 'transform-class-properties', 65 | ].filter(Boolean), 66 | }), 67 | json(), 68 | ] 69 | 70 | if (prod) plugins.push(uglify(), visualizer({ filename: './bundle-stats.html' })) 71 | 72 | export default { 73 | entry: 'src/index.js', 74 | moduleName: 'styled', 75 | external: ['react'].concat(esbundle ? ['stylis'] : []), 76 | exports: 'named', 77 | targets, 78 | plugins, 79 | globals: { react: 'React' }, 80 | } 81 | -------------------------------------------------------------------------------- /src/utils/test/extractCompsFromCSS.test.js: -------------------------------------------------------------------------------- 1 | import extractCompsFromCSS from '../extractCompsFromCSS' 2 | 3 | describe('extractCompsFromCSS', () => { 4 | it('should work for null or empty', () => { 5 | expect(extractCompsFromCSS('')).toEqual([]) 6 | expect(extractCompsFromCSS(null)).toEqual([]) 7 | }) 8 | 9 | it('should ignore anything before the first SC', () => { 10 | expect(extractCompsFromCSS(` 11 | Totally ignored, who cares. 12 | `)).toEqual([]) 13 | }) 14 | 15 | it('should return a single SC', () => { 16 | const css = ` 17 | /* sc-component-id: 123 */ 18 | .foo { color: red; } 19 | ` 20 | expect(extractCompsFromCSS(css)).toEqual([ 21 | { componentId: '123', cssFromDOM: css.replace(/^\n/,'') }, 22 | ]) 23 | }) 24 | 25 | it('should return a single SC with multiple lines', () => { 26 | const css = ` 27 | /* sc-component-id: 123 */ 28 | .foo { color: red; } 29 | .bar { color: blue; } 30 | ` 31 | expect(extractCompsFromCSS(css)).toEqual([ 32 | { componentId: '123', cssFromDOM: css.replace(/^\n/,'') }, 33 | ]) 34 | }) 35 | 36 | it('should return multiple SCs with single lines', () => { 37 | const a = ` 38 | /* sc-component-id: 123 */ 39 | .foo { color: red; } 40 | ` 41 | const b = ` 42 | /* sc-component-id: 456 */ 43 | .bar { color: blue; } 44 | ` 45 | expect(extractCompsFromCSS(a + b)).toEqual([ 46 | { componentId: '123', cssFromDOM: a.replace(/^\n/,'') + '\n' }, 47 | { componentId: '456', cssFromDOM: b.replace(/^\n/,'') }, 48 | ]) 49 | }) 50 | 51 | it('should return multiple SCs with multiple lines', () => { 52 | const a = ` 53 | /* sc-component-id: 123 */ 54 | .foo { color: red; } 55 | .bar { color: blue; } 56 | ` 57 | const b = ` 58 | /* sc-component-id: 456 */ 59 | .baz { color: green; } 60 | .boo { color: black; } 61 | ` 62 | expect(extractCompsFromCSS(a + b)).toEqual([ 63 | { componentId: '123', cssFromDOM: a.replace(/^\n/,'') + '\n' }, 64 | { componentId: '456', cssFromDOM: b.replace(/^\n/,'') }, 65 | ]) 66 | }) 67 | 68 | it('should include whitespace after a component', () => { 69 | const a = ` 70 | /* sc-component-id: 123 */ 71 | .foo { color: red; } 72 | .bar { color: blue; } 73 | 74 | 75 | 76 | ` 77 | const b = ` 78 | /* sc-component-id: 456 */ 79 | .baz { color: green; } 80 | .boo { color: black; } 81 | 82 | 83 | 84 | ` 85 | expect(extractCompsFromCSS(a + b)).toEqual([ 86 | { componentId: '123', cssFromDOM: a.replace(/^\n/,'') + '\n' }, 87 | { componentId: '456', cssFromDOM: b.replace(/^\n/,'') }, 88 | ]) 89 | }) 90 | }) 91 | -------------------------------------------------------------------------------- /src/vendor/postcss/list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains helpers for safely splitting lists of CSS values, 3 | * preserving parentheses and quotes. 4 | * 5 | * @example 6 | * const list = postcss.list; 7 | * 8 | * @namespace list 9 | */ 10 | let list = { 11 | 12 | split(string, separators, last) { 13 | let array = []; 14 | let current = ''; 15 | let split = false; 16 | 17 | let func = 0; 18 | let quote = false; 19 | let escape = false; 20 | 21 | for ( let i = 0; i < string.length; i++ ) { 22 | let letter = string[i]; 23 | 24 | if ( quote ) { 25 | if ( escape ) { 26 | escape = false; 27 | } else if ( letter === '\\' ) { 28 | escape = true; 29 | } else if ( letter === quote ) { 30 | quote = false; 31 | } 32 | } else if ( letter === '"' || letter === '\'' ) { 33 | quote = letter; 34 | } else if ( letter === '(' ) { 35 | func += 1; 36 | } else if ( letter === ')' ) { 37 | if ( func > 0 ) func -= 1; 38 | } else if ( func === 0 ) { 39 | if ( separators.indexOf(letter) !== -1 ) split = true; 40 | } 41 | 42 | if ( split ) { 43 | if ( current !== '' ) array.push(current.trim()); 44 | current = ''; 45 | split = false; 46 | } else { 47 | current += letter; 48 | } 49 | } 50 | 51 | if ( last || current !== '' ) array.push(current.trim()); 52 | return array; 53 | }, 54 | 55 | /** 56 | * Safely splits space-separated values (such as those for `background`, 57 | * `border-radius`, and other shorthand properties). 58 | * 59 | * @param {string} string - space-separated values 60 | * 61 | * @return {string[]} splitted values 62 | * 63 | * @example 64 | * postcss.list.space('1px calc(10% + 1px)') //=> ['1px', 'calc(10% + 1px)'] 65 | */ 66 | space(string) { 67 | let spaces = [' ', '\n', '\t']; 68 | return list.split(string, spaces); 69 | }, 70 | 71 | /** 72 | * Safely splits comma-separated values (such as those for `transition-*` 73 | * and `background` properties). 74 | * 75 | * @param {string} string - comma-separated values 76 | * 77 | * @return {string[]} splitted values 78 | * 79 | * @example 80 | * postcss.list.comma('black, linear-gradient(white, black)') 81 | * //=> ['black', 'linear-gradient(white, black)'] 82 | */ 83 | comma(string) { 84 | let comma = ','; 85 | return list.split(string, [comma], true); 86 | } 87 | 88 | }; 89 | 90 | export default list; 91 | -------------------------------------------------------------------------------- /dangerfile.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { danger, warn, fail, message } from 'danger' 4 | import fs from 'fs' 5 | 6 | const jsModifiedFiles = danger.git.modified_files.filter(path => path.startsWith('src') && path.endsWith('js')) 7 | const vendorModifiedFiles = danger.git.modified_files.filter(path => path.startsWith('src/vendor') && path.endsWith('js')) 8 | 9 | const hasAppChanges = jsModifiedFiles.length > 0 10 | const jsTestChanges = jsModifiedFiles.filter(filepath => filepath.endsWith('test.js')) 11 | const hasTestChanges = jsTestChanges.length > 0 12 | 13 | // Congrats, version bump up! 14 | const isVersionBump = danger.git.modified_files.includes('package.json') 15 | const packageDiff = danger.git.diffForFile('package.json') 16 | 17 | if (isVersionBump && packageDiff && packageDiff.includes('version')) { message(':tada: Version BUMP UP!') } 18 | 19 | // Warn when there is a big PR 20 | const bigPRThreshold = 500 21 | if (danger.github.pr.additions + danger.github.pr.deletions > bigPRThreshold) { 22 | warn(':exclamation: Big PR') 23 | } 24 | 25 | // Fail if there are app changes without a CHANGELOG 26 | if (!danger.git.modified_files.includes('CHANGELOG.md') && hasAppChanges) { 27 | const changelogLink = 'https://github.com/styled-components/styled-components/blob/master/CHANGELOG.md' 28 | fail(`Please include a CHANGELOG entry. You can find it at CHANGELOG.md`) 29 | } 30 | 31 | // Warn if there are library changes, but not tests (excluding vendor) 32 | const libraryOnlyFiles = jsModifiedFiles.filter(file => !vendorModifiedFiles.includes(file)) 33 | if (libraryOnlyFiles.length > 0 && hasTestChanges) { 34 | warn("There are library changes, but not tests. That's OK as long as you're refactoring existing code") 35 | } 36 | 37 | // Warn if StyledComponent.js was edited but not StyledNativeComponent.js or viceversa 38 | const hasStyledChanges = danger.git.modified_files.find(path => path.endsWith('StyledComponent.js')) !== null 39 | const hasNativeStyledChanges = danger.git.modified_files.find(path => path.endsWith('StyledNativeComponent.js')) !== null 40 | if (hasStyledChanges && !hasNativeStyledChanges) { 41 | warn("A change was made in StyledComponent.js that wasn't made in StyledNativeComponent.js or viceversa.") 42 | } 43 | 44 | // Changes to these files may need SemVer bumps 45 | const semverBumpFiles = ['ThemeProvider.js', 'StyledComponent.js', 'StyledNativeComponent.js'] 46 | semverBumpFiles.forEach(file => { 47 | if (jsModifiedFiles.includes(file)) { 48 | warn('Changes to #{file} might be SemVer major changes.') 49 | } 50 | }) 51 | 52 | // Be careful of leaving testing shortcuts in the codebase 53 | jsTestChanges.forEach(file => { 54 | const content = fs.readFileSync(file).toString() 55 | if (content.includes('it.only') || content.includes('describe.only')) { fail(`an \`only\` was left in tests (${file})`) } 56 | }) 57 | -------------------------------------------------------------------------------- /flow-typed/npm/rollup-plugin-commonjs_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 3d68e94528138d60900033606dce68a7 2 | // flow-typed version: <>/rollup-plugin-commonjs_v^6.0.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rollup-plugin-commonjs' 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 | declare module 'rollup-plugin-commonjs' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rollup-plugin-commonjs/dist/rollup-plugin-commonjs.cjs' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rollup-plugin-commonjs/dist/rollup-plugin-commonjs.es' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'rollup-plugin-commonjs/src/ast-utils' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'rollup-plugin-commonjs/src/defaultResolver' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'rollup-plugin-commonjs/src/helpers' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'rollup-plugin-commonjs/src/index' { 46 | declare module.exports: any; 47 | } 48 | 49 | declare module 'rollup-plugin-commonjs/src/transform' { 50 | declare module.exports: any; 51 | } 52 | 53 | declare module 'rollup-plugin-commonjs/src/utils' { 54 | declare module.exports: any; 55 | } 56 | 57 | // Filename aliases 58 | declare module 'rollup-plugin-commonjs/dist/rollup-plugin-commonjs.cjs.js' { 59 | declare module.exports: $Exports<'rollup-plugin-commonjs/dist/rollup-plugin-commonjs.cjs'>; 60 | } 61 | declare module 'rollup-plugin-commonjs/dist/rollup-plugin-commonjs.es.js' { 62 | declare module.exports: $Exports<'rollup-plugin-commonjs/dist/rollup-plugin-commonjs.es'>; 63 | } 64 | declare module 'rollup-plugin-commonjs/src/ast-utils.js' { 65 | declare module.exports: $Exports<'rollup-plugin-commonjs/src/ast-utils'>; 66 | } 67 | declare module 'rollup-plugin-commonjs/src/defaultResolver.js' { 68 | declare module.exports: $Exports<'rollup-plugin-commonjs/src/defaultResolver'>; 69 | } 70 | declare module 'rollup-plugin-commonjs/src/helpers.js' { 71 | declare module.exports: $Exports<'rollup-plugin-commonjs/src/helpers'>; 72 | } 73 | declare module 'rollup-plugin-commonjs/src/index.js' { 74 | declare module.exports: $Exports<'rollup-plugin-commonjs/src/index'>; 75 | } 76 | declare module 'rollup-plugin-commonjs/src/transform.js' { 77 | declare module.exports: $Exports<'rollup-plugin-commonjs/src/transform'>; 78 | } 79 | declare module 'rollup-plugin-commonjs/src/utils.js' { 80 | declare module.exports: $Exports<'rollup-plugin-commonjs/src/utils'>; 81 | } 82 | -------------------------------------------------------------------------------- /typings/tests/themed-tests/mytheme-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled, { css, keyframes, ThemeProvider, injectGlobal, MyTheme } from "./mytheme-styled-components"; 4 | 5 | // Create a react component that renders an <h1> which is 6 | // centered, palevioletred and sized at 1.5em 7 | const Title = styled.h1` 8 | font-size: 1.5em; 9 | text-align: center; 10 | color: ${p => p.theme.primaryColor}; 11 | `; 12 | 13 | const RedTitle = Title.extend` 14 | color: red; 15 | border-color: ${p => p.theme.primaryColor}; 16 | `; 17 | 18 | // Create a <Wrapper> react component that renders a <section> with 19 | // some padding and a papayawhip background 20 | const Wrapper = styled.section` 21 | background: ${p => p.theme.backgroundColor}; 22 | `; 23 | 24 | const Input = styled.input` 25 | font-size: 1.25em; 26 | padding: 0.5em; 27 | margin: ${p => p.theme.defaultMargin}em; 28 | color: palevioletred; 29 | background: papayawhip; 30 | border: none; 31 | border-radius: 3px; 32 | 33 | &:hover { 34 | box-shadow: inset 1px 1px 2px rgba(0,0,0,0.1); 35 | } 36 | `; 37 | 38 | interface ButtonProps { 39 | name: string; 40 | primary?: boolean; 41 | } 42 | 43 | class MyButton extends React.Component<ButtonProps, {}> { 44 | render() { 45 | return <button>Custom button</button>; 46 | } 47 | } 48 | 49 | const TomatoButton = styled(MyButton)` 50 | color: tomato; 51 | border-color: tomato; 52 | `; 53 | 54 | const CustomizableButton = styled(MyButton)` 55 | /* Adapt the colors based on primary prop */ 56 | background: ${props => props.primary ? "palevioletred" : "white"}; 57 | color: ${props => props.primary ? "white" : "palevioletred"}; 58 | 59 | font-size: 1em; 60 | margin: 1em; 61 | padding: 0.25em 1em; 62 | border: 2px solid ${props => props.theme.primaryColor}; 63 | border-radius: 3px; 64 | `; 65 | 66 | 67 | const example = css` 68 | font-size: 1.5em; 69 | text-align: center; 70 | color: ${props => props.theme.primaryColor}; 71 | border-color: ${"red"}; 72 | `; 73 | 74 | const fadeIn = keyframes` 75 | 0% { 76 | opacity: 0; 77 | } 78 | 100% { 79 | opacity: 1; 80 | } 81 | `; 82 | 83 | const theme: MyTheme = { 84 | primaryColor: "mediumseagreen", 85 | backgroundColor: "yellow", 86 | defaultMargin: .5 87 | }; 88 | 89 | injectGlobal` 90 | @font-face { 91 | font-family: 'Operator Mono'; 92 | src: url('../fonts/Operator-Mono.ttf'); 93 | } 94 | 95 | body { 96 | margin: 0; 97 | } 98 | `; 99 | 100 | class Example extends React.Component<{}, {}> { 101 | render() { 102 | return <ThemeProvider theme={theme}> 103 | <Wrapper> 104 | <Title>Hello World, this is my first styled component! 105 | 106 | 107 | 108 | ; 109 | ; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/utils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /** 3 | * This sets up our end-to-end test suite, which essentially makes sure 4 | * our public API works the way we promise/want 5 | */ 6 | import _styled from '../constructors/styled' 7 | import css from '../constructors/css' 8 | import _constructWithOptions from '../constructors/constructWithOptions' 9 | import StyleSheet from '../models/StyleSheet' 10 | import flatten from '../utils/flatten' 11 | import stringifyRules from '../utils/stringifyRules' 12 | import _StyledComponent from '../models/StyledComponent' 13 | import _ComponentStyle from '../models/ComponentStyle' 14 | 15 | import noParserCss from '../no-parser/css' 16 | import noParserFlatten from '../no-parser/flatten' 17 | import noParserStringifyRules from '../no-parser/stringifyRules' 18 | 19 | /* Ignore hashing, just return class names sequentially as .a .b .c etc */ 20 | let index = 0 21 | let seededClassnames = [] 22 | const classNames = () => seededClassnames.shift() || String.fromCodePoint(97 + index++) 23 | 24 | export const seedNextClassnames = (names: Array) => seededClassnames = names 25 | export const resetStyled = (isServer: boolean = false) => { 26 | if (!document.head) throw new Error("Missing document ") 27 | document.head.innerHTML = '' 28 | StyleSheet.reset(isServer) 29 | index = 0 30 | 31 | const ComponentStyle = _ComponentStyle(classNames, flatten, stringifyRules) 32 | const constructWithOptions = _constructWithOptions(css) 33 | const StyledComponent = _StyledComponent(ComponentStyle, constructWithOptions) 34 | 35 | return _styled(StyledComponent, constructWithOptions) 36 | } 37 | 38 | export const resetNoParserStyled = () => { 39 | if (!document.head) throw new Error("Missing document ") 40 | document.head.innerHTML = '' 41 | StyleSheet.reset() 42 | index = 0 43 | 44 | const ComponentStyle = _ComponentStyle(classNames, noParserFlatten, noParserStringifyRules) 45 | const constructWithOptions = _constructWithOptions(noParserCss) 46 | const StyledComponent = _StyledComponent(ComponentStyle, constructWithOptions) 47 | 48 | return _styled(StyledComponent, constructWithOptions) 49 | } 50 | 51 | const stripComments = (str: string) => 52 | str.replace(/\/\*.*?\*\/\n?/g, '') 53 | 54 | export const stripWhitespace = (str: string) => 55 | str.trim().replace(/([;\{\}])/g, '$1 ').replace(/\s+/g, ' ') 56 | 57 | export const expectCSSMatches = (_expectation: string, opts: { ignoreWhitespace: boolean } = { ignoreWhitespace: true }) => { 58 | // NOTE: This should normalise both CSS strings to make irrelevant mismatches less likely 59 | const expectation = _expectation 60 | .replace(/ {/g, '{') 61 | .replace(/:\s+;/g, ':;') 62 | 63 | const css = Array.from(document.querySelectorAll('style')) 64 | .map(tag => tag.innerHTML) 65 | .join('\n') 66 | .replace(/ {/g, '{') 67 | .replace(/:\s+;/g, ':;') 68 | 69 | if (opts.ignoreWhitespace) { 70 | const stripped = stripWhitespace(stripComments(css)) 71 | expect(stripped).toEqual(stripWhitespace(expectation)) 72 | return stripped 73 | } else { 74 | expect(css).toEqual(expectation) 75 | return css 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/models/ThemeProvider.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* globals React$Element */ 3 | import React, { Component } from 'react' 4 | import PropTypes from 'prop-types' 5 | import isFunction from 'is-function' 6 | import isPlainObject from 'is-plain-object' 7 | import createBroadcast from '../utils/create-broadcast' 8 | import type { Broadcast } from '../utils/create-broadcast' 9 | 10 | // NOTE: DO NOT CHANGE, changing this is a semver major change! 11 | export const CHANNEL = '__styled-components__' 12 | 13 | export type Theme = {[key: string]: mixed} 14 | type ThemeProviderProps = {| 15 | children?: React$Element, 16 | theme: Theme | (outerTheme: Theme) => void, 17 | |} 18 | 19 | /** 20 | * Provide a theme to an entire react component tree via context and event listeners (have to do 21 | * both context and event emitter as pure components block context updates) 22 | */ 23 | class ThemeProvider extends Component { 24 | getTheme: (theme?: Theme | (outerTheme: Theme) => void) => Theme 25 | outerTheme: Theme 26 | unsubscribeToOuter: () => void 27 | props: ThemeProviderProps 28 | broadcast: Broadcast 29 | 30 | constructor() { 31 | super() 32 | this.getTheme = this.getTheme.bind(this) 33 | } 34 | 35 | componentWillMount() { 36 | // If there is a ThemeProvider wrapper anywhere around this theme provider, merge this theme 37 | // with the outer theme 38 | if (this.context[CHANNEL]) { 39 | const subscribe = this.context[CHANNEL] 40 | this.unsubscribeToOuter = subscribe(theme => { 41 | this.outerTheme = theme 42 | }) 43 | } 44 | this.broadcast = createBroadcast(this.getTheme()) 45 | } 46 | 47 | getChildContext() { 48 | return { ...this.context, [CHANNEL]: this.broadcast.subscribe } 49 | } 50 | 51 | componentWillReceiveProps(nextProps: ThemeProviderProps) { 52 | if (this.props.theme !== nextProps.theme) this.broadcast.publish(this.getTheme(nextProps.theme)) 53 | } 54 | 55 | componentWillUnmount() { 56 | if (this.context[CHANNEL]) { 57 | this.unsubscribeToOuter() 58 | } 59 | } 60 | 61 | // Get the theme from the props, supporting both (outerTheme) => {} as well as object notation 62 | getTheme(passedTheme: (outerTheme: Theme) => void | Theme) { 63 | const theme = passedTheme || this.props.theme 64 | if (isFunction(theme)) { 65 | const mergedTheme = theme(this.outerTheme) 66 | if (!isPlainObject(mergedTheme)) { 67 | throw new Error('[ThemeProvider] Please return an object from your theme function, i.e. theme={() => ({})}!') 68 | } 69 | return mergedTheme 70 | } 71 | if (!isPlainObject(theme)) { 72 | throw new Error('[ThemeProvider] Please make your theme prop a plain object') 73 | } 74 | return { ...this.outerTheme, ...(theme: Object) } 75 | } 76 | 77 | render() { 78 | if (!this.props.children) { 79 | return null 80 | } 81 | return React.Children.only(this.props.children) 82 | } 83 | } 84 | 85 | ThemeProvider.childContextTypes = { 86 | [CHANNEL]: PropTypes.func.isRequired, 87 | } 88 | ThemeProvider.contextTypes = { 89 | [CHANNEL]: PropTypes.func, 90 | } 91 | 92 | export default ThemeProvider 93 | -------------------------------------------------------------------------------- /src/no-parser/flatten.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import isPlainObject from 'is-plain-object' 3 | import type { Interpolation } from '../types' 4 | import _flatten, { objToCss } from '../utils/flatten' 5 | 6 | const isRuleSet = (interpolation: Interpolation): boolean => !!( 7 | interpolation && 8 | Array.isArray(interpolation) && 9 | interpolation.length > 0 && 10 | interpolation[0] && 11 | Array.isArray(interpolation[0]) 12 | ) 13 | 14 | const flatten = (chunks: Array, executionContext: ?Object): Array => { 15 | /* Fall back to old flattener for non-rule-set chunks */ 16 | if (!isRuleSet(chunks)) { 17 | return _flatten(chunks, executionContext) 18 | } 19 | 20 | return chunks.reduce( 21 | (ruleSet: Array, chunk: ?Interpolation): Array => { 22 | if (!Array.isArray(chunk)) { 23 | return ruleSet 24 | } 25 | 26 | let appendChunks = [] 27 | 28 | const newChunk = chunk.reduce( 29 | (rules: Array, rule: ?Interpolation): Array => { 30 | /* Remove falsey values */ 31 | if (rule === undefined || rule === null || rule === false || rule === '') { 32 | return rules 33 | } 34 | 35 | /* Flatten nested rule set */ 36 | if (isRuleSet(rule)) { 37 | // $FlowFixMe Don't know what's wrong here 38 | appendChunks = [...appendChunks, ...flatten(rule, executionContext)] 39 | return rules 40 | } 41 | 42 | /* Stringify unexpected array */ 43 | if (Array.isArray(rule)) { 44 | return [...rules, ..._flatten(rule, executionContext)] 45 | } 46 | 47 | /* Either execute or defer the function */ 48 | if (typeof rule === 'function') { 49 | if (executionContext) { 50 | const res = rule(executionContext) 51 | 52 | if (isRuleSet(res)) { 53 | // $FlowFixMe Don't know what's wrong here 54 | appendChunks = [...appendChunks, ...flatten(res, executionContext)] 55 | return rules 56 | } 57 | 58 | /* Flatten non-ruleset values */ 59 | return [...rules, ...flatten([res], executionContext)] 60 | } else { 61 | return [...rules, rule] 62 | } 63 | } 64 | 65 | /* Handle other components */ 66 | if (typeof rule === 'object' && rule.hasOwnProperty('styledComponentId')) return [...rules, `.${rule.styledComponentId}`] 67 | 68 | /* Convert object to css string */ 69 | if (typeof rule === 'object' && isPlainObject(rule)) { 70 | return [...rules, objToCss(rule)] 71 | } 72 | 73 | return [...rules, rule.toString()] 74 | }, 75 | [], 76 | ) 77 | 78 | if (executionContext) { 79 | const newChunkStr = newChunk.join('') 80 | if (appendChunks.length) { 81 | return [...ruleSet, newChunkStr, ...appendChunks] 82 | } 83 | 84 | return [...ruleSet, newChunkStr] 85 | } 86 | 87 | return [...ruleSet, newChunk, ...appendChunks] 88 | }, [], 89 | ) 90 | } 91 | 92 | export default flatten 93 | -------------------------------------------------------------------------------- /src/utils/test/flatten.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import flatten from '../flatten' 3 | 4 | describe('flatten', () => { 5 | it('doesnt merge strings', () => { 6 | expect(flatten(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz']) 7 | }) 8 | it('drops nulls', () => { 9 | // $FlowInvalidInputTest 10 | expect(flatten(['foo', false, 'bar', undefined, 'baz', null])).toEqual(['foo', 'bar', 'baz']) 11 | }) 12 | it('doesnt drop any numbers', () => { 13 | expect(flatten(['foo', 0, 'bar', NaN, 'baz', -1])).toEqual(['foo', '0', 'bar', 'NaN', 'baz', '-1']) 14 | }) 15 | it('toStrings everything', () => { 16 | // $FlowInvalidInputTest 17 | expect(flatten([1, true])).toEqual(['1', 'true']) 18 | }) 19 | it('hypenates objects', () => { 20 | const obj = { 21 | fontSize: '14px', 22 | WebkitFilter: 'blur(2px)', 23 | } 24 | const css = 'font-size: 14px; -webkit-filter: blur(2px);' 25 | // $FlowFixMe 26 | expect(flatten([obj])).toEqual([css]) 27 | // $FlowFixMe 28 | expect(flatten(['some:thing;', obj, 'something: else;'])).toEqual(['some:thing;', css, 'something: else;']) 29 | }) 30 | it('handles nested objects', () => { 31 | const obj = { 32 | fontSize: '14px', 33 | '@media screen and (min-width: 250px)': { 34 | fontSize: '16px', 35 | }, 36 | '&:hover': { 37 | fontWeight: 'bold', 38 | }, 39 | } 40 | const css = 'font-size: 14px; @media screen and (min-width: 250px) {\n font-size: 16px;\n} &:hover {\n font-weight: bold;\n}' 41 | // $FlowFixMe 42 | expect(flatten([obj])).toEqual([css]) 43 | // $FlowFixMe 44 | expect(flatten(['some:thing;', obj, 'something: else;'])).toEqual(['some:thing;', css, 'something: else;']) 45 | }) 46 | it('toStrings class instances', () => { 47 | class SomeClass { 48 | toString() { 49 | return 'some: thing;' 50 | } 51 | } 52 | // $FlowFixMe 53 | expect(flatten([new SomeClass()])).toEqual(['some: thing;']) 54 | }) 55 | it('flattens subarrays', () => { 56 | expect(flatten([1, 2, [3, 4, 5], 'come:on;', 'lets:ride;'])).toEqual(['1', '2', '3', '4', '5', 'come:on;', 'lets:ride;']) 57 | }) 58 | it('defers functions', () => { 59 | const func = () => 'bar' 60 | const funcWFunc = () => ['static', subfunc => subfunc ? 'bar' : 'baz'] 61 | expect(flatten(['foo', func, 'baz'])).toEqual(['foo', func, 'baz']) 62 | expect(flatten(['foo', funcWFunc, 'baz'])).toEqual(['foo', funcWFunc, 'baz']) 63 | }) 64 | it('executes functions', () => { 65 | const func = () => 'bar' 66 | expect(flatten(['foo', func, 'baz'], { bool: true })).toEqual(['foo', 'bar', 'baz']) 67 | }) 68 | it('passes values to function', () => { 69 | const func = ({ bool }) => bool ? 'bar' : 'baz' 70 | expect(flatten(['foo', func], { bool: true })).toEqual(['foo', 'bar']) 71 | expect(flatten(['foo', func], { bool: false })).toEqual(['foo', 'baz']) 72 | }) 73 | it('recursively calls functions', () => { 74 | const func = () => ['static', ({ bool }) => bool ? 'bar' : 'baz'] 75 | expect(flatten(['foo', func], { bool: true })).toEqual(['foo', 'static', 'bar']) 76 | expect(flatten(['foo', func], { bool: false })).toEqual(['foo', 'static', 'baz']) 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /src/vendor/postcss/root.js: -------------------------------------------------------------------------------- 1 | import './rule'; // break cyclical dependency deadlock – #87 2 | 3 | import Container from './container'; 4 | import LazyResult from './lazy-result'; 5 | import Processor from './processor'; 6 | import warnOnce from './warn-once'; 7 | 8 | /** 9 | * Represents a CSS file and contains all its parsed nodes. 10 | * 11 | * @extends Container 12 | * 13 | * @example 14 | * const root = postcss.parse('a{color:black} b{z-index:2}'); 15 | * root.type //=> 'root' 16 | * root.nodes.length //=> 2 17 | */ 18 | class Root extends Container { 19 | 20 | constructor(defaults) { 21 | super(defaults); 22 | this.type = 'root'; 23 | if ( !this.nodes ) this.nodes = []; 24 | } 25 | 26 | removeChild(child) { 27 | child = this.index(child); 28 | 29 | if ( child === 0 && this.nodes.length > 1 ) { 30 | this.nodes[1].raws.before = this.nodes[child].raws.before; 31 | } 32 | 33 | return super.removeChild(child); 34 | } 35 | 36 | normalize(child, sample, type) { 37 | let nodes = super.normalize(child); 38 | 39 | if ( sample ) { 40 | if ( type === 'prepend' ) { 41 | if ( this.nodes.length > 1 ) { 42 | sample.raws.before = this.nodes[1].raws.before; 43 | } else { 44 | delete sample.raws.before; 45 | } 46 | } else if ( this.first !== sample ) { 47 | nodes.forEach(node => { 48 | node.raws.before = sample.raws.before; 49 | }) 50 | } 51 | } 52 | 53 | return nodes; 54 | } 55 | 56 | /** 57 | * Returns a {@link Result} instance representing the root’s CSS. 58 | * 59 | * @param {processOptions} [opts] - options with only `to` and `map` keys 60 | * 61 | * @return {Result} result with current root’s CSS 62 | * 63 | * @example 64 | * const root1 = postcss.parse(css1, { from: 'a.css' }); 65 | * const root2 = postcss.parse(css2, { from: 'b.css' }); 66 | * root1.append(root2); 67 | * const result = root1.toResult({ to: 'all.css', map: true }); 68 | */ 69 | toResult(opts = { }) { 70 | let lazy = new LazyResult(new Processor(), this, opts); 71 | return lazy.stringify(); 72 | } 73 | 74 | remove(child) { 75 | warnOnce('Root#remove is deprecated. Use Root#removeChild'); 76 | this.removeChild(child); 77 | } 78 | 79 | prevMap() { 80 | warnOnce('Root#prevMap is deprecated. Use Root#source.input.map'); 81 | return this.source.input.map; 82 | } 83 | 84 | /** 85 | * @memberof Root# 86 | * @member {object} raws - Information to generate byte-to-byte equal 87 | * node string as it was in the origin input. 88 | * 89 | * Every parser saves its own properties, 90 | * but the default CSS parser uses: 91 | * 92 | * * `after`: the space symbols after the last child to the end of file. 93 | * * `semicolon`: is the last child has an (optional) semicolon. 94 | * 95 | * @example 96 | * postcss.parse('a {}\n').raws //=> { after: '\n' } 97 | * postcss.parse('a {}').raws //=> { after: '' } 98 | */ 99 | 100 | } 101 | 102 | export default Root; 103 | -------------------------------------------------------------------------------- /src/vendor/postcss/declaration.js: -------------------------------------------------------------------------------- 1 | import warnOnce from './warn-once'; 2 | import Node from './node'; 3 | 4 | /** 5 | * Represents a CSS declaration. 6 | * 7 | * @extends Node 8 | * 9 | * @example 10 | * const root = postcss.parse('a { color: black }'); 11 | * const decl = root.first.first; 12 | * decl.type //=> 'decl' 13 | * decl.toString() //=> ' color: black' 14 | */ 15 | class Declaration extends Node { 16 | 17 | constructor(defaults) { 18 | super(defaults); 19 | this.type = 'decl'; 20 | } 21 | 22 | get _value() { 23 | warnOnce('Node#_value was deprecated. Use Node#raws.value'); 24 | return this.raws.value; 25 | } 26 | 27 | set _value(val) { 28 | warnOnce('Node#_value was deprecated. Use Node#raws.value'); 29 | this.raws.value = val; 30 | } 31 | 32 | get _important() { 33 | warnOnce('Node#_important was deprecated. Use Node#raws.important'); 34 | return this.raws.important; 35 | } 36 | 37 | set _important(val) { 38 | warnOnce('Node#_important was deprecated. Use Node#raws.important'); 39 | this.raws.important = val; 40 | } 41 | 42 | /** 43 | * @memberof Declaration# 44 | * @member {string} prop - the declaration’s property name 45 | * 46 | * @example 47 | * const root = postcss.parse('a { color: black }'); 48 | * const decl = root.first.first; 49 | * decl.prop //=> 'color' 50 | */ 51 | 52 | /** 53 | * @memberof Declaration# 54 | * @member {string} value - the declaration’s value 55 | * 56 | * @example 57 | * const root = postcss.parse('a { color: black }'); 58 | * const decl = root.first.first; 59 | * decl.value //=> 'black' 60 | */ 61 | 62 | /** 63 | * @memberof Declaration# 64 | * @member {boolean} important - `true` if the declaration 65 | * has an !important annotation. 66 | * 67 | * @example 68 | * const root = postcss.parse('a { color: black !important; color: red }'); 69 | * root.first.first.important //=> true 70 | * root.first.last.important //=> undefined 71 | */ 72 | 73 | /** 74 | * @memberof Declaration# 75 | * @member {object} raws - Information to generate byte-to-byte equal 76 | * node string as it was in the origin input. 77 | * 78 | * Every parser saves its own properties, 79 | * but the default CSS parser uses: 80 | * 81 | * * `before`: the space symbols before the node. It also stores `*` 82 | * and `_` symbols before the declaration (IE hack). 83 | * * `between`: the symbols between the property and value 84 | * for declarations, selector and `{` for rules, or last parameter 85 | * and `{` for at-rules. 86 | * * `important`: the content of the important statement, 87 | * if it is not just `!important`. 88 | * 89 | * PostCSS cleans declaration from comments and extra spaces, 90 | * but it stores origin content in raws properties. 91 | * As such, if you don’t change a declaration’s value, 92 | * PostCSS will use the raw value with comments. 93 | * 94 | * @example 95 | * const root = postcss.parse('a {\n color:black\n}') 96 | * root.first.first.raws //=> { before: '\n ', between: ':' } 97 | */ 98 | 99 | } 100 | 101 | export default Declaration; 102 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /src/test/expanded-api.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react' 3 | import { shallow } from 'enzyme' 4 | 5 | import { resetStyled } from './utils' 6 | 7 | let styled 8 | 9 | describe('expanded api', () => { 10 | /** 11 | * Make sure the setup is the same for every test 12 | */ 13 | beforeEach(() => { 14 | styled = resetStyled() 15 | }) 16 | 17 | describe('displayName', () => { 18 | it('should be auto-generated if none passed', () => { 19 | const Comp = styled.div`` 20 | expect(Comp.displayName).toBe('styled.div') 21 | }) 22 | 23 | it('should be attached if supplied', () => { 24 | const Comp = styled.div.withConfig({ displayName: 'Comp' })`` 25 | expect(Comp.displayName).toBe('Comp') 26 | }) 27 | }) 28 | 29 | describe('componentId', () => { 30 | it('should be generated as "sc" + hash', () => { 31 | const Comp = styled.div`` 32 | const Comp2 = styled.div`` 33 | expect(Comp.styledComponentId).toBe('sc-a') 34 | expect(shallow().prop('className')).toMatch(/sc-a/) 35 | expect(Comp2.styledComponentId).toBe('sc-b') 36 | expect(shallow().prop('className')).toMatch(/sc-b/) 37 | }) 38 | 39 | it('should be generated from displayName + hash', () => { 40 | const Comp = styled.div.withConfig({ displayName: 'Comp' })`` 41 | const Comp2 = styled.div.withConfig({ displayName: 'Comp2' })`` 42 | expect(Comp.styledComponentId).toBe('Comp-a') 43 | expect(shallow().prop('className')).toMatch(/Comp-a/) 44 | expect(Comp2.styledComponentId).toBe('Comp2-b') 45 | expect(shallow().prop('className')).toMatch(/Comp2-b/) 46 | }) 47 | 48 | it('should be attached if passed in', () => { 49 | const Comp = styled.div.withConfig({ componentId: 'LOLOMG' })`` 50 | const Comp2 = styled.div.withConfig({ componentId: 'OMGLOL' })`` 51 | expect(Comp.styledComponentId).toBe('LOLOMG') 52 | expect(shallow().prop('className')).toMatch(/LOLOMG/) 53 | expect(Comp2.styledComponentId).toBe('OMGLOL') 54 | expect(shallow().prop('className')).toMatch(/OMGLOL/) 55 | }) 56 | 57 | it('should be combined with displayName if both passed in', () => { 58 | const Comp = styled.div.withConfig({ displayName: 'Comp', componentId: 'LOLOMG' })`` 59 | const Comp2 = styled.div.withConfig({ displayName: 'Comp2', componentId: 'OMGLOL' })`` 60 | expect(Comp.styledComponentId).toBe('Comp-LOLOMG') 61 | expect(shallow().prop('className')).toMatch(/Comp-LOLOMG/) 62 | expect(Comp2.styledComponentId).toBe('Comp2-OMGLOL') 63 | expect(shallow().prop('className')).toMatch(/Comp2-OMGLOL/) 64 | }) 65 | }) 66 | 67 | describe('chaining', () => { 68 | it('should merge the options strings', () => { 69 | const Comp = styled.div 70 | .withConfig({ componentId: 'id-1' }) 71 | .withConfig({ displayName: 'dn-2' }) 72 | `` 73 | expect(Comp.displayName).toBe('dn-2') 74 | expect(shallow().prop('className')).toBe('dn-2-id-1 a') 75 | }) 76 | 77 | it('should keep the last value passed in when merging', () => { 78 | const Comp = styled.div 79 | .withConfig({ displayName: 'dn-2', componentId: 'id-3' }) 80 | .withConfig({ displayName: 'dn-5', componentId: 'id-4' }) 81 | `` 82 | expect(Comp.displayName).toBe('dn-5') 83 | expect(shallow().prop('className')).toBe('dn-5-id-4 a') 84 | }) 85 | }) 86 | }) 87 | -------------------------------------------------------------------------------- /flow-typed/npm/enzyme_v2.3.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: f3b75915e82ea23b5d37b8b584eddb76 2 | // flow-typed version: d4e590e9bf/enzyme_v2.3.x/flow_>=v0.28.x 3 | 4 | declare module 'enzyme' { 5 | declare type PredicateFunction = (wrapper: T) => boolean; 6 | declare type NodeOrNodes = React$Element | Array>; 7 | declare type EnzymeSelector = string | ReactClass | Object; 8 | 9 | // CheerioWrapper is a type alias for an actual cheerio instance 10 | // TODO: Reference correct type from cheerio's type declarations 11 | declare type CheerioWrapper = any; 12 | 13 | declare class Wrapper { 14 | find(selector: EnzymeSelector): this; 15 | findWhere(predicate: PredicateFunction): this; 16 | filter(selector: EnzymeSelector): this; 17 | filterWhere(predicate: PredicateFunction): this; 18 | contains(nodeOrNodes: NodeOrNodes): boolean; 19 | containsMatchingElement(node: React$Element): boolean; 20 | containsAllMatchingElements(nodes: NodeOrNodes): boolean; 21 | containsAnyMatchingElements(nodes: NodeOrNodes): boolean; 22 | matchesElement(node: React$Element): boolean; 23 | hasClass(className: string): boolean; 24 | is(selector: EnzymeSelector): boolean; 25 | isEmpty(): boolean; 26 | not(selector: EnzymeSelector): boolean; 27 | children(selector?: EnzymeSelector): this; 28 | childAt(index: number): this; 29 | parents(selector?: EnzymeSelector): this; 30 | parent(): this; 31 | closest(selector: EnzymeSelector): this; 32 | render(): CheerioWrapper; 33 | unmount(): this; 34 | text(): string; 35 | html(): string; 36 | get(index: number): React$Element; 37 | at(index: number): this; 38 | first(): this; 39 | last(): this; 40 | state(key?: string): any; 41 | context(key?: string): any; 42 | props(): Object; 43 | prop(key: string): any; 44 | key(): string; 45 | simulate(event: string, ...args: Array): this; 46 | setState(state: Object): this; 47 | setProps(props: Object): this; 48 | setContext(context: Object): this; 49 | instance(): React$Component; 50 | update(): this; 51 | debug(): string; 52 | type(): string | Function | null; 53 | name(): string; 54 | forEach(fn: (node: this) => any): this; 55 | map(fn: (node: this) => T): Array; 56 | reduce(fn: (value: T, node: this, index: number) => T, initialValue?: T): Array; 57 | reduceRight(fn: (value: T, node: this, index: number) => T, initialValue?: T): Array; 58 | some(selector: EnzymeSelector): boolean; 59 | someWhere(predicate: PredicateFunction): boolean; 60 | every(selector: EnzymeSelector): boolean; 61 | everyWhere(predicate: PredicateFunction): boolean; 62 | length: number; 63 | } 64 | 65 | declare export class ReactWrapper extends Wrapper { 66 | mount(): this; 67 | ref(refName: string): this; 68 | detach(): void; 69 | } 70 | 71 | declare export class ShallowWrapper extends Wrapper { 72 | equals(node: React$Element): boolean; 73 | shallow(options?: { context?: Object }): ShallowWrapper; 74 | } 75 | 76 | declare export function shallow(node: React$Element, options?: { context?: Object }): ShallowWrapper; 77 | declare export function mount(node: React$Element, options?: { context?: Object, attachTo?: HTMLElement, childContextTypes?: Object }): ReactWrapper; 78 | declare export function render(node: React$Element, options?: { context?: Object }): CheerioWrapper; 79 | } 80 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-cli_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 54225bcc23e4c3534b2ecfea0bed37f3 2 | // flow-typed version: <>/babel-cli_v^6.18.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-cli' 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 | declare module 'babel-cli' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-cli/bin/babel-doctor' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'babel-cli/bin/babel-external-helpers' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'babel-cli/bin/babel-node' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'babel-cli/bin/babel' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'babel-cli/lib/_babel-node' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'babel-cli/lib/babel-external-helpers' { 46 | declare module.exports: any; 47 | } 48 | 49 | declare module 'babel-cli/lib/babel-node' { 50 | declare module.exports: any; 51 | } 52 | 53 | declare module 'babel-cli/lib/babel/dir' { 54 | declare module.exports: any; 55 | } 56 | 57 | declare module 'babel-cli/lib/babel/file' { 58 | declare module.exports: any; 59 | } 60 | 61 | declare module 'babel-cli/lib/babel/index' { 62 | declare module.exports: any; 63 | } 64 | 65 | declare module 'babel-cli/lib/babel/util' { 66 | declare module.exports: any; 67 | } 68 | 69 | // Filename aliases 70 | declare module 'babel-cli/bin/babel-doctor.js' { 71 | declare module.exports: $Exports<'babel-cli/bin/babel-doctor'>; 72 | } 73 | declare module 'babel-cli/bin/babel-external-helpers.js' { 74 | declare module.exports: $Exports<'babel-cli/bin/babel-external-helpers'>; 75 | } 76 | declare module 'babel-cli/bin/babel-node.js' { 77 | declare module.exports: $Exports<'babel-cli/bin/babel-node'>; 78 | } 79 | declare module 'babel-cli/bin/babel.js' { 80 | declare module.exports: $Exports<'babel-cli/bin/babel'>; 81 | } 82 | declare module 'babel-cli/index' { 83 | declare module.exports: $Exports<'babel-cli'>; 84 | } 85 | declare module 'babel-cli/index.js' { 86 | declare module.exports: $Exports<'babel-cli'>; 87 | } 88 | declare module 'babel-cli/lib/_babel-node.js' { 89 | declare module.exports: $Exports<'babel-cli/lib/_babel-node'>; 90 | } 91 | declare module 'babel-cli/lib/babel-external-helpers.js' { 92 | declare module.exports: $Exports<'babel-cli/lib/babel-external-helpers'>; 93 | } 94 | declare module 'babel-cli/lib/babel-node.js' { 95 | declare module.exports: $Exports<'babel-cli/lib/babel-node'>; 96 | } 97 | declare module 'babel-cli/lib/babel/dir.js' { 98 | declare module.exports: $Exports<'babel-cli/lib/babel/dir'>; 99 | } 100 | declare module 'babel-cli/lib/babel/file.js' { 101 | declare module.exports: $Exports<'babel-cli/lib/babel/file'>; 102 | } 103 | declare module 'babel-cli/lib/babel/index.js' { 104 | declare module.exports: $Exports<'babel-cli/lib/babel/index'>; 105 | } 106 | declare module 'babel-cli/lib/babel/util.js' { 107 | declare module.exports: $Exports<'babel-cli/lib/babel/util'>; 108 | } 109 | -------------------------------------------------------------------------------- /src/vendor/postcss/rule.js: -------------------------------------------------------------------------------- 1 | import './at-rule'; // break cyclical dependency deadlock – #87 2 | 3 | import Container from './container'; 4 | import warnOnce from './warn-once'; 5 | import list from './list'; 6 | 7 | /** 8 | * Represents a CSS rule: a selector followed by a declaration block. 9 | * 10 | * @extends Container 11 | * 12 | * @example 13 | * const root = postcss.parse('a{}'); 14 | * const rule = root.first; 15 | * rule.type //=> 'rule' 16 | * rule.toString() //=> 'a{}' 17 | */ 18 | class Rule extends Container { 19 | 20 | constructor(defaults) { 21 | super(defaults); 22 | this.type = 'rule'; 23 | if ( !this.nodes ) this.nodes = []; 24 | } 25 | 26 | /** 27 | * An array containing the rule’s individual selectors. 28 | * Groups of selectors are split at commas. 29 | * 30 | * @type {string[]} 31 | * 32 | * @example 33 | * const root = postcss.parse('a, b { }'); 34 | * const rule = root.first; 35 | * 36 | * rule.selector //=> 'a, b' 37 | * rule.selectors //=> ['a', 'b'] 38 | * 39 | * rule.selectors = ['a', 'strong']; 40 | * rule.selector //=> 'a, strong' 41 | */ 42 | get selectors() { 43 | return list.comma(this.selector); 44 | } 45 | 46 | set selectors(values) { 47 | let match = this.selector ? this.selector.match(/,\s*/) : null; 48 | let sep = match ? match[0] : ',' + this.raw('between', 'beforeOpen'); 49 | this.selector = values.join(sep); 50 | } 51 | 52 | get _selector() { 53 | warnOnce('Rule#_selector is deprecated. Use Rule#raws.selector'); 54 | return this.raws.selector; 55 | } 56 | 57 | set _selector(val) { 58 | warnOnce('Rule#_selector is deprecated. Use Rule#raws.selector'); 59 | this.raws.selector = val; 60 | } 61 | 62 | /** 63 | * @memberof Rule# 64 | * @member {string} selector - the rule’s full selector represented 65 | * as a string 66 | * 67 | * @example 68 | * const root = postcss.parse('a, b { }'); 69 | * const rule = root.first; 70 | * rule.selector //=> 'a, b' 71 | */ 72 | 73 | /** 74 | * @memberof Rule# 75 | * @member {object} raws - Information to generate byte-to-byte equal 76 | * node string as it was in the origin input. 77 | * 78 | * Every parser saves its own properties, 79 | * but the default CSS parser uses: 80 | * 81 | * * `before`: the space symbols before the node. It also stores `*` 82 | * and `_` symbols before the declaration (IE hack). 83 | * * `after`: the space symbols after the last child of the node 84 | * to the end of the node. 85 | * * `between`: the symbols between the property and value 86 | * for declarations, selector and `{` for rules, or last parameter 87 | * and `{` for at-rules. 88 | * * `semicolon`: contains true if the last child has 89 | * an (optional) semicolon. 90 | * 91 | * PostCSS cleans selectors from comments and extra spaces, 92 | * but it stores origin content in raws properties. 93 | * As such, if you don’t change a declaration’s value, 94 | * PostCSS will use the raw value with comments. 95 | * 96 | * @example 97 | * const root = postcss.parse('a {\n color:black\n}') 98 | * root.first.first.raws //=> { before: '', between: ' ', after: '\n' } 99 | */ 100 | 101 | } 102 | 103 | export default Rule; 104 | -------------------------------------------------------------------------------- /src/models/ServerStyleSheet.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import type { Tag } from './StyleSheet' 4 | import StyleSheet, { SC_ATTR, LOCAL_ATTR, clones } from './StyleSheet' 5 | import StyleSheetManager from './StyleSheetManager' 6 | 7 | class ServerTag implements Tag { 8 | isLocal: boolean 9 | components: { [string]: Object } 10 | size: number 11 | names: Array 12 | 13 | constructor(isLocal: boolean) { 14 | this.isLocal = isLocal 15 | this.components = {} 16 | this.size = 0 17 | this.names = [] 18 | } 19 | 20 | isFull() { 21 | return false 22 | } 23 | 24 | addComponent(componentId: string) { 25 | if (this.components[componentId]) throw new Error(`Trying to add Component '${componentId}' twice!`) 26 | this.components[componentId] = { componentId, css: '' } 27 | this.size += 1 28 | } 29 | 30 | inject(componentId: string, css: string, name: ?string) { 31 | const comp = this.components[componentId] 32 | 33 | if (!comp) throw new Error('Must add a new component before you can inject css into it') 34 | if (comp.css === '') comp.css = `/* sc-component-id: ${componentId} */\n` 35 | 36 | comp.css += css.replace(/\n*$/, '\n') 37 | 38 | if (name) this.names.push(name) 39 | } 40 | 41 | toHTML() { 42 | const namesAttr = `${SC_ATTR}="${this.names.join(' ')}"` 43 | const localAttr = `${LOCAL_ATTR}="${this.isLocal ? 'true' : 'false'}"` 44 | const css = Object.keys(this.components) 45 | .map(key => this.components[key].css) 46 | .join('') 47 | 48 | return `` 49 | } 50 | 51 | toReactElement(key: string) { 52 | const attributes = { 53 | [SC_ATTR]: this.names.join(' '), 54 | [LOCAL_ATTR]: this.isLocal.toString(), 55 | } 56 | const css = Object.keys(this.components) 57 | .map(k => this.components[k].css) 58 | .join('') 59 | 60 | return ( 61 |