├── src ├── constructors │ ├── test │ │ ├── css.test.js │ │ ├── styled.test.js │ │ ├── keyframes.test.js │ │ ├── injectGlobal.test.js │ │ └── element.test.js │ ├── css.js │ ├── injectGlobal.js │ ├── styled.js │ └── keyframes.js ├── utils │ ├── isTag.js │ ├── interleave.js │ ├── test │ │ ├── generateAlphabeticName.test.js │ │ ├── interleave.test.js │ │ └── flatten.test.js │ ├── generateAlphabeticName.js │ ├── create-broadcast.js │ ├── autoprefix.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 ├── models │ ├── AbstractStyledComponent.js │ ├── GlobalStyle.js │ ├── StyleSheet.js │ ├── ComponentStyle.js │ ├── InlineStyle.js │ ├── test │ │ ├── StyleSheet.test.js │ │ └── ThemeProvider.test.js │ └── ThemeProvider.js ├── types.js ├── test │ ├── props.test.js │ ├── utils.js │ ├── css.test.js │ ├── extending.test.js │ └── basic.test.js ├── index.js ├── hoc │ └── withTheme.js └── native │ └── index.js ├── .gitignore ├── native.js ├── native ├── index.js └── index.d.ts ├── .eslintignore ├── 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 │ └── mocha-jsdom_vx.x.x.js └── fbjs_vx.x.x.js ├── .editorconfig ├── .babelrc ├── .travis.yml ├── .flowconfig ├── typings ├── styled-components-hoc-test.tsx ├── styled-components-native-test.tsx ├── themed-tests │ ├── mytheme-styled-components.tsx │ ├── with-theme-test.tsx │ └── mytheme-styled-components-test.tsx └── styled-components-test.tsx ├── appveyor.yml ├── docs ├── flow-support.md ├── README.md ├── faq.md ├── css-we-support.md ├── react-native.md ├── theming.md ├── tagged-template-literals.md ├── security.md ├── existing-css.md └── typescript-support.md ├── LICENSE ├── example ├── devServer.js ├── index.html └── with-perf.html ├── .eslintrc ├── .github └── ISSUE_TEMPLATE.md ├── CONTRIBUTING.md ├── tslint.json ├── rollup.config.js ├── dangerfile.js └── CODE_OF_CONDUCT.md /src/constructors/test/css.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | npm-debug.log.* 4 | dist 5 | .DS_Store 6 | bundle-stats.html 7 | -------------------------------------------------------------------------------- /native.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable flowtype/require-valid-file-annotation */ 2 | module.exports = require('./lib/native') 3 | -------------------------------------------------------------------------------- /native/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable flowtype/require-valid-file-annotation */ 2 | module.exports = require('../lib/native') 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 | -------------------------------------------------------------------------------- /flow-typed/react-native.js: -------------------------------------------------------------------------------- 1 | declare module 'react-native' { 2 | declare module.exports: { 3 | StyleSheet: { 4 | create: Function 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "env", 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/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/constructors/test/styled.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import expect from 'expect' 3 | import styled from '../../index' 4 | import domElements from '../../utils/domElements' 5 | 6 | describe('styled', () => { 7 | it('should have all valid HTML5 elements defined as properties', () => { 8 | domElements.forEach(domElement => { 9 | expect(styled[domElement]).toExist() 10 | }) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /src/constructors/injectGlobal.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import css from './css' 3 | import GlobalStyle from '../models/GlobalStyle' 4 | import type { Interpolation } from '../types' 5 | 6 | const injectGlobal = (strings: Array, ...interpolations: Array) => { 7 | const globalStyle = new GlobalStyle(css(strings, ...interpolations)) 8 | globalStyle.generateAndInject() 9 | } 10 | 11 | export default injectGlobal 12 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/utils/test/generateAlphabeticName.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import generateAlphabeticName from '../generateAlphabeticName'; 4 | import expect from 'expect'; 5 | 6 | describe('generateAlphabeticName', () => { 7 | it('should create alphabetic names for number input data', () => { 8 | expect(generateAlphabeticName(1000000000)).toEqual('cGNYzm'); 9 | expect(generateAlphabeticName(2000000000)).toEqual('fnBWYy'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/flow-remove-types/.* 3 | .*/node_modules/react-native/.* 4 | .*/node_modules/rollup-plugin-flow/.* 5 | .*/dist/.* 6 | .*/lib/.* 7 | .*/node_modules/babel-plugin-flow-react-proptypes/src/__test__/.* 8 | .*/dangerfile.js 9 | 10 | [include] 11 | 12 | [libs] 13 | flow-typed 14 | 15 | [options] 16 | suppress_comment=.*\\$FlowFixMe 17 | suppress_comment=.*\\$FlowInvalidInputTest 18 | unsafe.enable_getters_and_setters=true 19 | -------------------------------------------------------------------------------- /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/styled-components-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 | 7 | class MyComponent extends React.Component, {}> { 8 | render() { 9 | const { theme } = this.props; 10 | 11 | console.log("Current theme: ", theme); 12 | 13 | return

Hello

; 14 | } 15 | } 16 | 17 | export default withTheme(MyComponent); 18 | -------------------------------------------------------------------------------- /typings/styled-components-native-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react-native"; 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 | -------------------------------------------------------------------------------- /src/utils/generateAlphabeticName.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('') 3 | 4 | /* Some high number, usually 9-digit base-10. Map it to base-😎 */ 5 | const generateAlphabeticName = (code: number): string => { 6 | const lastDigit = chars[code % chars.length] 7 | return code > chars.length 8 | ? `${generateAlphabeticName(Math.floor(code / chars.length))}${lastDigit}` 9 | : lastDigit 10 | } 11 | 12 | export default generateAlphabeticName 13 | -------------------------------------------------------------------------------- /src/models/AbstractStyledComponent.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { Component } from 'react' 3 | import PropTypes from 'prop-types' 4 | 5 | import { CHANNEL } from './ThemeProvider' 6 | 7 | export default class AbstractStyledComponent extends Component { 8 | static isPrototypeOf: Function 9 | state: { 10 | theme: any, 11 | generatedClassName?: string, 12 | generatedStyles?: any 13 | } 14 | unsubscribe: () => void 15 | } 16 | 17 | AbstractStyledComponent.contextTypes = { 18 | [CHANNEL]: PropTypes.func, 19 | } 20 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export type Interpolation = ((executionContext: Object) => string) | string | number 3 | /* todo: I want this to actually be an array of Function | string but that causes errors */ 4 | export type RuleSet = Array 5 | 6 | /* eslint-disable no-undef */ 7 | export type Target = string | ReactClass<*> 8 | 9 | export type NameGenerator = (hash: number) => string 10 | 11 | export type GlamorRule = { cssText: string } 12 | 13 | export interface GlamorInsertedRule { 14 | appendRule(css: string): void 15 | } 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/constructors/styled.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import css from './css' 3 | import type { Interpolation, Target } from '../types' 4 | import domElements from '../utils/domElements' 5 | 6 | export default (styledComponent: Function) => { 7 | const styled = (tag: Target) => 8 | (strings: Array, ...interpolations: Array) => 9 | styledComponent(tag, css(strings, ...interpolations)) 10 | 11 | // Shorthands for all valid HTML Elements 12 | domElements.forEach(domElement => { 13 | styled[domElement] = styled(domElement) 14 | }) 15 | 16 | return styled 17 | } 18 | -------------------------------------------------------------------------------- /typings/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/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 | -------------------------------------------------------------------------------- /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/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('.a { 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('.a { color: red; }') 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /src/utils/test/interleave.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import expect from 'expect' 3 | import interleave from '../interleave' 4 | 5 | describe('interleave', () => { 6 | it('blindly interleave', () => { 7 | expect(interleave([], [])).toEqual([undefined]) 8 | expect(interleave(['foo'], [])).toEqual(['foo']) 9 | expect(interleave(['foo'], [1])).toEqual(['foo', 1, undefined]) 10 | expect(interleave(['foo', 'bar'], [1])).toEqual(['foo', 1, 'bar']) 11 | }) 12 | it('should be driven off the number of interpolations', () => { 13 | expect(interleave(['foo', 'bar'], [])).toEqual(['foo']) 14 | expect(interleave(['foo', 'bar', 'baz'], [1])).toEqual(['foo', 1, 'bar']) 15 | expect(interleave([], [1])).toEqual([undefined, 1, undefined]) 16 | expect(interleave(['foo'], [1, 2, 3])).toEqual(['foo', 1, undefined, 2, undefined, 3, undefined]) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /docs/flow-support.md: -------------------------------------------------------------------------------- 1 | # Flow Support 2 | 3 | To use flowtype with the public api of styled-components we recommend that 4 | you use the library definition in [flow-typed]. 5 | 6 | To install it you can use the flow-typed cli or download it manually from 7 | the git repository and storing it in a flow-typed folder in the same folder 8 | as your flowconfig. 9 | 10 | ### Installing the libdef with flow-typed 11 | 12 | ```shell 13 | npm i -g flow-typed # if you do not already have flow-typed 14 | flow-typed install styled-components@ 15 | ``` 16 | 17 | ### Ignore styled-components sources from flow 18 | 19 | You should add this to your flowconfig if you run into flow errors from the 20 | styled-components package in node_modules. 21 | 22 | ``` 23 | [ignore] 24 | .*/node_modules/styled-components/.* 25 | ``` 26 | 27 | [flow-typed]: https://github.com/flowtype/flow-typed 28 | -------------------------------------------------------------------------------- /src/constructors/keyframes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import hashStr from '../vendor/glamor/hash' 3 | import css from './css' 4 | import GlobalStyle from '../models/GlobalStyle' 5 | import type { Interpolation, NameGenerator } from '../types' 6 | 7 | const replaceWhitespace = (str: string): string => str.replace(/\s|\\n/g, '') 8 | 9 | export default (nameGenerator: NameGenerator) => 10 | (strings: Array, ...interpolations: Array): string => { 11 | const rules = css(strings, ...interpolations) 12 | const hash = hashStr(replaceWhitespace(JSON.stringify(rules))) 13 | const name = nameGenerator(hash) 14 | const keyframes = new GlobalStyle(rules, `@keyframes ${name}`) 15 | const keyframesWebkit = new GlobalStyle(rules, `@-webkit-keyframes ${name}`) 16 | keyframes.generateAndInject() 17 | keyframesWebkit.generateAndInject() 18 | return name 19 | } 20 | -------------------------------------------------------------------------------- /src/models/GlobalStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import parse from '../vendor/postcss-safe-parser/parse' 3 | import autoprefix from '../utils/autoprefix' 4 | import postcssNested from '../vendor/postcss-nested' 5 | 6 | import type { RuleSet } from '../types' 7 | import flatten from '../utils/flatten' 8 | 9 | import styleSheet from './StyleSheet' 10 | 11 | export default class ComponentStyle { 12 | rules: RuleSet; 13 | selector: ?string; 14 | 15 | constructor(rules: RuleSet, selector: ?string) { 16 | this.rules = rules 17 | this.selector = selector 18 | } 19 | 20 | generateAndInject() { 21 | if (!styleSheet.injected) styleSheet.inject() 22 | let flatCSS = flatten(this.rules).join('') 23 | if (this.selector) { 24 | flatCSS = `${this.selector} {${flatCSS}\n}` 25 | } 26 | const root = parse(flatCSS) 27 | postcssNested(root) 28 | autoprefix(root) 29 | styleSheet.insert(root.toResult().css, { global: true }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /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: () => 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/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* Import singletons */ 4 | import generateAlphabeticName from './utils/generateAlphabeticName' 5 | import css from './constructors/css' 6 | import injectGlobal from './constructors/injectGlobal' 7 | 8 | /* Import singleton constructors */ 9 | import _styledComponent from './models/StyledComponent' 10 | import _styled from './constructors/styled' 11 | import _keyframes from './constructors/keyframes' 12 | import _ComponentStyle from './models/ComponentStyle' 13 | 14 | /* Import components */ 15 | import ThemeProvider from './models/ThemeProvider' 16 | 17 | /* Import Higher Order Components */ 18 | import withTheme from './hoc/withTheme' 19 | 20 | /* Instantiate singletons */ 21 | const keyframes = _keyframes(generateAlphabeticName) 22 | const styled = _styled(_styledComponent(_ComponentStyle(generateAlphabeticName))) 23 | 24 | /* Export everything */ 25 | export default styled 26 | export { css, keyframes, injectGlobal, ThemeProvider, withTheme } 27 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | This is the `styled-components` documentation. 4 | 5 | ## Table of Contents 6 | 7 | - [API Reference](./api.md): A reference for all APIs that we export or return 8 | - [Tips and Tricks](./tips-and-tricks.md): A few handy tips for working with `styled-components` 9 | - [Tagged Template Literals](./tagged-template-literals.md): How do they work? 10 | - [Using `styled-components` with existing CSS](./existing-css.md): Some edge cases you should be aware of when using `styled-components` with an existing CSS codebase 11 | - [What CSS we support](./css-we-support.md): What parts & extensions of CSS can you use within a component? 12 | - [Theming](./theming.md): How to work with themes 13 | - [Security](./security.md): Security considerations when allowing users to configure themes 14 | - [React Native](./react-native.md): Details for React Native 15 | - [Typescript](./typescript-support.md): Typescript Support 16 | - [FAQ](./faq.md): Frequently Asked Questions 17 | -------------------------------------------------------------------------------- /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 | Vendored glamor/sheet.js as of [582dde4](https://github.com/threepointone/glamor/blob/582dde44713bcbe9212a961706c06a34a4ebccb0/src/sheet.js) 6 | 7 | Then hacked things around: 8 | 9 | * Deleted `previous-map.js` and all references to it because it `require('fs')`ed 10 | * Deleted reference to `postcss` within `postcss-nested` & simply exported the transform function 11 | * Made `StyleSheet.insert()` return something with an `update()` method 12 | * 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 13 | -------------------------------------------------------------------------------- /src/utils/autoprefix.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import camelizeStyleName from 'fbjs/lib/camelizeStyleName' 3 | import hyphenateStyleName from 'fbjs/lib/hyphenateStyleName' 4 | 5 | // eslint-disable-next-line 6 | import prefixAll from 'inline-style-prefixer/static' 7 | import type Container from '../vendor/postcss/container' 8 | 9 | export default (root: Container) => { 10 | root.walkDecls(decl => { 11 | /* No point even checking custom props */ 12 | if (/^--/.test(decl.prop)) return 13 | 14 | const objStyle = { [camelizeStyleName(decl.prop)]: decl.value } 15 | const prefixed = prefixAll(objStyle) 16 | Object.keys(prefixed).reverse().forEach(newProp => { 17 | const newVals = prefixed[newProp] 18 | const newValArray = Array.isArray(newVals) ? newVals : [newVals] 19 | newValArray.forEach(newVal => { 20 | decl.cloneBefore({ 21 | prop: hyphenateStyleName(newProp), 22 | value: newVal, 23 | }) 24 | }) 25 | }) 26 | decl.remove() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /src/hoc/withTheme.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* globals ReactClass */ 3 | 4 | import React from 'react' 5 | import PropTypes from 'prop-types' 6 | import { CHANNEL } from '../models/ThemeProvider' 7 | 8 | export default (Component: ReactClass) => class extends React.Component { 9 | static contextTypes = { 10 | [CHANNEL]: PropTypes.func, 11 | }; 12 | 13 | state: { theme?: ?Object } = {}; 14 | unsubscribe: () => void; 15 | 16 | componentWillMount() { 17 | if (!this.context[CHANNEL]) { 18 | throw new Error('[withTheme] Please use ThemeProvider to be able to use withTheme') 19 | } 20 | 21 | const subscribe = this.context[CHANNEL] 22 | this.unsubscribe = subscribe(theme => { 23 | this.setState({ theme }) 24 | }) 25 | } 26 | 27 | componentWillUnmount() { 28 | if (typeof this.unsubscribe === 'function') this.unsubscribe() 29 | } 30 | 31 | render() { 32 | const { theme } = this.state 33 | 34 | return 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/css-we-support.md: -------------------------------------------------------------------------------- 1 | # CSS We Support 2 | 3 | Within a styled component, we support all of CSS, including nesting – since we generate an actual stylesheet and not inline styles, whatever works in CSS works in a styled component! 4 | 5 | ```js 6 | styled.div` 7 | any: selector; 8 | something: that needs prefixes; /* will be prefixed */ 9 | &:pseudo-selectors { 10 | all good; 11 | } 12 | @media (min-width: 600px) { 13 | aint-no: thing; 14 | } 15 | > h1 { 16 | direct-descendants: fine too; /* all descendants work fine too 17 | but not recommended. */ 18 | } 19 | html.what-about-contextual & { 20 | sall: good; 21 | } 22 | ` 23 | ``` 24 | 25 | > **Note:** Ampersands (`&`) get replaced by our generated, unique classname for that styled component, making it easy to have complex logic 26 | 27 | On top of that you can always use `injectGlobal` for actually global things, like `@font-face`: 28 | 29 | ```js 30 | import { injectGlobal } from 'styled-components' 31 | 32 | injectGlobal` 33 | @font-face { 34 | font-family: 'Operator Mono'; 35 | src: url('../fonts/Operator-Mono.ttf'); 36 | } 37 | ` 38 | ``` 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | const srcPath = __dirname.split('/example')[0] + '/src'; 7 | 8 | const hotBuild = () => exec('npm run build:dist', (err, stdout, stderr) => { 9 | if (err) throw err 10 | if (stdout) { 11 | console.log(`npm run build:dist --- ${stdout}`) 12 | } 13 | if (stderr) { 14 | console.log(`npm run build:dist --- ${stderr}`) 15 | } 16 | }) 17 | 18 | watch(srcPath, (filename) => { 19 | console.log(`${filename} file has changed`) 20 | hotBuild() 21 | }) 22 | 23 | const app = new Express() 24 | const port = 3000 25 | 26 | app.use(Express.static('dist')) 27 | 28 | app.get('/with-perf.html', (req, res) => { 29 | res.sendFile(path.join(__dirname, 'with-perf.html')) 30 | }) 31 | 32 | app.get('/*', (req, res) => { 33 | res.sendFile(path.join(__dirname, 'index.html')) 34 | }) 35 | 36 | app.listen(port, error => { 37 | /* eslint-disable no-console */ 38 | if (error) { 39 | console.error(error) 40 | } else { 41 | console.info( 42 | '🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.', 43 | port, 44 | port 45 | ) 46 | } 47 | /* eslint-enable no-console */ 48 | }) 49 | -------------------------------------------------------------------------------- /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 expect from 'expect' 7 | 8 | import _styled from '../constructors/styled' 9 | import mainStyleSheet from '../models/StyleSheet' 10 | import _styledComponent from '../models/StyledComponent' 11 | import _ComponentStyle from '../models/ComponentStyle' 12 | 13 | /* Ignore hashing, just return class names sequentially as .a .b .c etc */ 14 | let index = 0 15 | const classNames = () => String.fromCodePoint(97 + index++) 16 | 17 | export const resetStyled = () => { 18 | mainStyleSheet.flush() 19 | index = 0 20 | return _styled(_styledComponent(_ComponentStyle(classNames))) 21 | } 22 | 23 | const stripWhitespace = str => str.trim().replace(/\s+/g, ' ') 24 | export const expectCSSMatches = ( 25 | expectation: string, 26 | opts: { ignoreWhitespace?: boolean, styleSheet?: Object } = {} 27 | ) => { 28 | const { ignoreWhitespace = true, styleSheet = mainStyleSheet } = opts 29 | const css = styleSheet.rules().map(rule => rule.cssText).join('\n') 30 | if (ignoreWhitespace) { 31 | expect(stripWhitespace(css)).toEqual(stripWhitespace(expectation)) 32 | } else { 33 | expect(css).toEqual(expectation) 34 | } 35 | return css 36 | } 37 | -------------------------------------------------------------------------------- /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 expect from 'expect' 3 | 4 | import _keyframes from '../keyframes' 5 | import styleSheet from '../../models/StyleSheet' 6 | import { expectCSSMatches, resetStyled } from '../../test/utils' 7 | 8 | /** 9 | * Setup 10 | */ 11 | let index = 0 12 | const keyframes = _keyframes(() => `keyframe_${index++}`) 13 | 14 | describe('keyframes', () => { 15 | beforeEach(() => { 16 | resetStyled() 17 | index = 0 18 | }) 19 | 20 | it('should return its name', () => { 21 | expect(keyframes` 22 | 0% { 23 | opacity: 0; 24 | } 25 | 100% { 26 | opacity: 1; 27 | } 28 | `).toEqual('keyframe_0') 29 | }) 30 | 31 | it('should insert the correct styles', () => { 32 | const rules = ` 33 | 0% { 34 | opacity: 0; 35 | } 36 | 100% { 37 | opacity: 1; 38 | } 39 | ` 40 | 41 | const name = keyframes`${rules}` 42 | expectCSSMatches(` 43 | @keyframes keyframe_0 { 44 | 0% { 45 | opacity: 0; 46 | } 47 | 100% { 48 | opacity: 1; 49 | } 50 | } 51 | @-webkit-keyframes keyframe_0 { 52 | 0% { 53 | opacity: 0; 54 | } 55 | 100% { 56 | opacity: 1; 57 | } 58 | } 59 | `, { styleSheet }) 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 | -------------------------------------------------------------------------------- /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/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 | /* Either execute or defer the function */ 24 | if (typeof chunk === 'function') { 25 | return executionContext 26 | ? ruleSet.concat(...flatten([chunk(executionContext)], executionContext)) 27 | : ruleSet.concat(chunk) 28 | } 29 | 30 | /* Handle objects */ 31 | // $FlowFixMe have to add %checks somehow to isPlainObject 32 | return ruleSet.concat(isPlainObject(chunk) ? objToCss(chunk) : chunk.toString()) 33 | }, []) 34 | ) 35 | 36 | export default flatten 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic Example 6 | 7 | 8 |

Basic Example

9 |
10 | 11 | 12 | 13 | 14 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/models/StyleSheet.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* Wraps glamor's stylesheet and exports a singleton for styled components 4 | to use. */ 5 | import { StyleSheet as GlamorSheet } from '../vendor/glamor/sheet' 6 | import type { GlamorRule, GlamorInsertedRule } from '../types' 7 | 8 | 9 | class StyleSheet { 10 | globalStyleSheet: GlamorSheet 11 | componentStyleSheet: GlamorSheet 12 | constructor() { 13 | /* Don't specify a maxLength for the global sheet, since these rules 14 | * are defined at initialization and should remain static after that */ 15 | this.globalStyleSheet = new GlamorSheet({ speedy: false }) 16 | this.componentStyleSheet = new GlamorSheet({ speedy: false, maxLength: 40 }) 17 | } 18 | get injected(): boolean { 19 | return this.globalStyleSheet.injected && this.componentStyleSheet.injected 20 | } 21 | inject(): void { 22 | this.globalStyleSheet.inject() 23 | this.componentStyleSheet.inject() 24 | } 25 | flush(): void { 26 | if (this.globalStyleSheet.sheet) this.globalStyleSheet.flush() 27 | if (this.componentStyleSheet.sheet) this.componentStyleSheet.flush() 28 | } 29 | insert(rule: string, opts: { global: boolean } = { global: false }): GlamorInsertedRule { 30 | const sheet = opts.global ? this.globalStyleSheet : this.componentStyleSheet 31 | return sheet.insert(rule) 32 | } 33 | rules(): Array { 34 | return this.globalStyleSheet.rules().concat(this.componentStyleSheet.rules()) 35 | } 36 | } 37 | 38 | /* Export stylesheet as a singleton class */ 39 | export default new StyleSheet() 40 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 httpsL://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 | 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/models/ComponentStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import hashStr from '../vendor/glamor/hash' 3 | 4 | import type { RuleSet, NameGenerator, GlamorInsertedRule } from '../types' 5 | import flatten from '../utils/flatten' 6 | import parse from '../vendor/postcss-safe-parser/parse' 7 | import postcssNested from '../vendor/postcss-nested' 8 | import autoprefix from '../utils/autoprefix' 9 | import styleSheet from './StyleSheet' 10 | 11 | /* 12 | ComponentStyle is all the CSS-specific stuff, not 13 | the React-specific stuff. 14 | */ 15 | export default (nameGenerator: NameGenerator) => { 16 | const inserted = {} 17 | 18 | class ComponentStyle { 19 | rules: RuleSet 20 | insertedRule: GlamorInsertedRule 21 | 22 | constructor(rules: RuleSet) { 23 | this.rules = rules 24 | if (!styleSheet.injected) styleSheet.inject() 25 | this.insertedRule = styleSheet.insert('') 26 | } 27 | 28 | /* 29 | * Flattens a rule set into valid CSS 30 | * Hashes it, wraps the whole chunk in a ._hashName {} 31 | * Parses that with PostCSS then runs PostCSS-Nested on it 32 | * Returns the hash to be injected on render() 33 | * */ 34 | generateAndInjectStyles(executionContext: Object) { 35 | const flatCSS = flatten(this.rules, executionContext).join('') 36 | .replace(/^\s*\/\/.*$/gm, '') // replace JS comments 37 | const hash = hashStr(flatCSS) 38 | if (!inserted[hash]) { 39 | const selector = nameGenerator(hash) 40 | inserted[hash] = selector 41 | const root = parse(`.${selector} { ${flatCSS} }`) 42 | postcssNested(root) 43 | autoprefix(root) 44 | this.insertedRule.appendRule(root.toResult().css) 45 | } 46 | return inserted[hash] 47 | } 48 | } 49 | 50 | return ComponentStyle 51 | } 52 | -------------------------------------------------------------------------------- /src/native/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /* eslint-disable import/no-unresolved */ 4 | import reactNative from 'react-native' 5 | 6 | import css from '../constructors/css' 7 | 8 | import styledNativeComponent from '../models/StyledNativeComponent' 9 | import ThemeProvider from '../models/ThemeProvider' 10 | import withTheme from '../hoc/withTheme' 11 | import type { Interpolation, Target } from '../types' 12 | 13 | const styled = (tag: Target) => 14 | (strings: Array, ...interpolations: Array) => 15 | styledNativeComponent(tag, css(strings, ...interpolations)) 16 | 17 | /* React native lazy-requires each of these modules for some reason, so let's 18 | * assume it's for a good reason and not eagerly load them all */ 19 | const aliases = `ActivityIndicator ActivityIndicatorIOS ART Button DatePickerIOS DrawerLayoutAndroid 20 | Image ImageEditor ImageStore KeyboardAvoidingView ListView MapView Modal Navigator NavigatorIOS 21 | Picker PickerIOS ProgressBarAndroid ProgressViewIOS ScrollView SegmentedControlIOS Slider 22 | SliderIOS SnapshotViewIOS Switch RecyclerViewBackedScrollView RefreshControl StatusBar 23 | SwipeableListView SwitchAndroid SwitchIOS TabBarIOS Text TextInput ToastAndroid ToolbarAndroid 24 | Touchable TouchableHighlight TouchableNativeFeedback TouchableOpacity TouchableWithoutFeedback 25 | View ViewPagerAndroid WebView FlatList SectionList VirtualizedList` 26 | 27 | /* Define a getter for each alias which simply gets the reactNative component 28 | * and passes it to styled */ 29 | aliases.split(/\s+/m).forEach(alias => Object.defineProperty(styled, alias, { 30 | enumerable: true, 31 | configurable: false, 32 | get() { 33 | return styled(reactNative[alias]) 34 | }, 35 | })) 36 | 37 | export { css, ThemeProvider, withTheme } 38 | export default styled 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/constructors/test/injectGlobal.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react' 3 | import expect from 'expect' 4 | import { shallow } from 'enzyme' 5 | 6 | import injectGlobal from '../injectGlobal' 7 | import styleSheet from '../../models/StyleSheet' 8 | import { expectCSSMatches, resetStyled } from '../../test/utils' 9 | 10 | let styled = resetStyled() 11 | const rule1 = 'width: 100%;' 12 | const rule2 = 'text-decoration: none;' 13 | const rule3 = 'color: blue;' 14 | 15 | describe('injectGlobal', () => { 16 | beforeEach(() => { 17 | resetStyled() 18 | }) 19 | 20 | it(`should inject rules into the head`, () => { 21 | injectGlobal` 22 | html { 23 | ${rule1} 24 | } 25 | ` 26 | expect(styleSheet.injected).toBe(true) 27 | }) 28 | 29 | it(`should non-destructively inject styles when called repeatedly`, () => { 30 | injectGlobal` 31 | html { 32 | ${rule1} 33 | } 34 | ` 35 | 36 | injectGlobal` 37 | a { 38 | ${rule2} 39 | } 40 | ` 41 | expectCSSMatches(` 42 | html { 43 | ${rule1} 44 | } 45 | a { 46 | ${rule2} 47 | } 48 | `, { styleSheet }) 49 | }) 50 | 51 | it(`should inject styles in a separate sheet from a component`, () => { 52 | const Comp = styled.div` 53 | ${rule3} 54 | ` 55 | shallow() 56 | 57 | injectGlobal` 58 | html { 59 | ${rule1} 60 | } 61 | ` 62 | // Test the component sheet 63 | expectCSSMatches(` 64 | .a { 65 | ${rule3} 66 | } 67 | `, { styleSheet: styleSheet.componentStyleSheet }) 68 | // Test the global sheet 69 | expectCSSMatches(` 70 | html { 71 | ${rule1} 72 | } 73 | `, { styleSheet: styleSheet.globalStyleSheet }) 74 | }) 75 | }); 76 | -------------------------------------------------------------------------------- /src/vendor/glamor/hash.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Stolen directly from glamor, thanks @threepointone! 3 | */ 4 | 5 | /* eslint-disable */ 6 | "use strict"; 7 | 8 | Object.defineProperty(exports, "__esModule", { 9 | value: true 10 | }); 11 | exports.default = doHash; 12 | // murmurhash2 via https://gist.github.com/raycmorgan/588423 13 | 14 | function doHash(str, seed) { 15 | var m = 0x5bd1e995; 16 | var r = 24; 17 | var h = seed ^ str.length; 18 | var length = str.length; 19 | var currentIndex = 0; 20 | 21 | while (length >= 4) { 22 | var k = UInt32(str, currentIndex); 23 | 24 | k = Umul32(k, m); 25 | k ^= k >>> r; 26 | k = Umul32(k, m); 27 | 28 | h = Umul32(h, m); 29 | h ^= k; 30 | 31 | currentIndex += 4; 32 | length -= 4; 33 | } 34 | 35 | switch (length) { 36 | case 3: 37 | h ^= UInt16(str, currentIndex); 38 | h ^= str.charCodeAt(currentIndex + 2) << 16; 39 | h = Umul32(h, m); 40 | break; 41 | 42 | case 2: 43 | h ^= UInt16(str, currentIndex); 44 | h = Umul32(h, m); 45 | break; 46 | 47 | case 1: 48 | h ^= str.charCodeAt(currentIndex); 49 | h = Umul32(h, m); 50 | break; 51 | } 52 | 53 | h ^= h >>> 13; 54 | h = Umul32(h, m); 55 | h ^= h >>> 15; 56 | 57 | return h >>> 0; 58 | } 59 | 60 | function UInt32(str, pos) { 61 | return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8) + (str.charCodeAt(pos++) << 16) + (str.charCodeAt(pos) << 24); 62 | } 63 | 64 | function UInt16(str, pos) { 65 | return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8); 66 | } 67 | 68 | function Umul32(n, m) { 69 | n = n | 0; 70 | m = m | 0; 71 | var nlo = n & 0xffff; 72 | var nhi = n >>> 16; 73 | var res = nlo * m + ((nhi * m & 0xffff) << 16) | 0; 74 | return res; 75 | } 76 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/models/InlineStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* eslint-disable import/no-unresolved */ 3 | import { StyleSheet } from 'react-native' 4 | import transformDeclPairs from 'css-to-react-native' 5 | 6 | import hashStr from '../vendor/glamor/hash' 7 | import type { RuleSet } from '../types' 8 | import flatten from '../utils/flatten' 9 | import parse from '../vendor/postcss-safe-parser/parse' 10 | 11 | const generated = {} 12 | 13 | /* 14 | InlineStyle takes arbitrary CSS and generates a flat object 15 | */ 16 | export default class InlineStyle { 17 | rules: RuleSet 18 | 19 | constructor(rules: RuleSet) { 20 | this.rules = rules 21 | } 22 | 23 | generateStyleObject(executionContext: Object) { 24 | const flatCSS = flatten(this.rules, executionContext).join('') 25 | const hash = hashStr(flatCSS) 26 | if (!generated[hash]) { 27 | const root = parse(flatCSS) 28 | const declPairs = [] 29 | root.each(node => { 30 | if (node.type === 'decl') { 31 | declPairs.push([node.prop, node.value]) 32 | } else { 33 | /* eslint-disable no-console */ 34 | console.warn(`Node of type ${node.type} not supported as an inline style`) 35 | } 36 | }) 37 | // RN currently does not support differing values for the corner radii of Image 38 | // components (but does for View). It is almost impossible to tell whether we'll have 39 | // support, so we'll just disable multiple values here. 40 | // https://github.com/styled-components/css-to-react-native/issues/11 41 | const styleObject = transformDeclPairs(declPairs, [ 42 | 'borderRadius', 43 | 'borderWidth', 44 | 'borderColor', 45 | 'borderStyle', 46 | ]) 47 | const styles = StyleSheet.create({ 48 | generated: styleObject, 49 | }) 50 | generated[hash] = styles.generated 51 | } 52 | return generated[hash] 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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('.a { transition: opacity 0.3s; -webkit-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 | .a { 31 | display: -webkit-box; 32 | display: -moz-box; 33 | display: -ms-flexbox; 34 | display: -webkit-flex; 35 | display: flex; 36 | flex-direction: column; 37 | -webkit-box-direction: normal; 38 | -webkit-box-orient: vertical; 39 | -ms-flex-direction: column; 40 | -webkit-flex-direction: column; 41 | align-items: center; 42 | -webkit-box-align: center; 43 | -ms-flex-align: center; 44 | -webkit-align-items: center; 45 | } 46 | `) 47 | }) 48 | 49 | it('should handle CSS calc()', () => { 50 | const Comp = styled.div` 51 | margin-bottom: calc(15px - 0.5rem) !important; 52 | ` 53 | shallow() 54 | expectCSSMatches(` 55 | .a { 56 | margin-bottom: -webkit-calc(15px - 0.5rem) !important; 57 | margin-bottom: -moz-calc(15px - 0.5rem) !important; 58 | margin-bottom: calc(15px - 0.5rem) !important; 59 | } 60 | `) 61 | }) 62 | 63 | it('should pass through custom properties', () => { 64 | const Comp = styled.div` 65 | --custom-prop: some-val; 66 | ` 67 | shallow() 68 | expectCSSMatches('.a { --custom-prop: some-val; }') 69 | }) 70 | }) 71 | -------------------------------------------------------------------------------- /src/constructors/test/element.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // import proxyquire from 'proxyquire' 3 | // import expect from 'expect' 4 | // 5 | // // Inject FakeRoot into the "import '../models/Root'" call in element.js with proxyquire 6 | // const injectStylesSpy = expect.createSpy() 7 | // const constructorSpy = expect.createSpy() 8 | // const generatedClassname = 'generated-classname' 9 | // class FakeRoot { 10 | // constructor(...rules) { 11 | // constructorSpy(...rules) 12 | // } 13 | // injectStyles() { 14 | // injectStylesSpy() 15 | // return generatedClassname 16 | // } 17 | // } 18 | // const element = proxyquire('../element', { '../models/Root': FakeRoot }) 19 | // 20 | // describe('element', () => { 21 | // afterEach(() => { 22 | // injectStylesSpy.restore() 23 | // constructorSpy.restore() 24 | // }) 25 | // 26 | // it('should return a stateless functional component', () => { 27 | // expect(element('div')).toBeA('function') 28 | // }) 29 | // 30 | // it('should add the rules to the style root on creation', () => { 31 | // const rule1 = 'background: "red";' 32 | // const rule2 = 'color: "blue";' 33 | // element('div', rule1, rule2) 34 | // expect(constructorSpy).toHaveBeenCalled() 35 | // expect(constructorSpy).toHaveBeenCalledWith(rule1, rule2) 36 | // }) 37 | // 38 | // it('should call injectStyles of the style root on render', () => { 39 | // // Pretend a react render is happening 40 | // element('div')({}) 41 | // expect(injectStylesSpy).toHaveBeenCalled() 42 | // }) 43 | // 44 | // it('should adopt the classname of the injectStyles call', () => { 45 | // // Pretend a react render is happening 46 | // const renderedComp = element('div')({}) 47 | // expect(renderedComp.props.className).toEqual(` ${generatedClassname}`) 48 | // }) 49 | // 50 | // it('should adopt a passed in className', () => { 51 | // const className = 'other-classname' 52 | // const renderedComp = element('div')({ 53 | // className, 54 | // }) 55 | // expect(renderedComp.props.className).toEqual(`${className} ${generatedClassname}`) 56 | // }) 57 | // }) 58 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/react-native.md: -------------------------------------------------------------------------------- 1 | # React Native 2 | 3 | 4 | `styled-components` has a ReactNative mode that works _exactly_ the same, except you import the things from `styled-components/native`: 5 | 6 | ```JSX 7 | import styled from 'styled-components/native'; 8 | 9 | const StyledView = styled.View` 10 | background-color: papayawhip; 11 | `; 12 | 13 | const StyledText = styled.Text` 14 | color: palevioletred; 15 | `; 16 | 17 | class MyReactNativeComponent extends React.Component { 18 | render() { 19 | return ( 20 | 21 | Hello World! 22 | 23 | ) 24 | } 25 | } 26 | ``` 27 | 28 | We also support more complex styles (like `transform`), which would normally be an array, and shorthands (e.g. for `margin`) thanks to [`css-to-react-native`](https://github.com/styled-components/css-to-react-native)! Imagine how you'd write the property in ReactNative, guess how you'd transfer it to CSS and you're probably right: 29 | 30 | ```JS 31 | const RotatedBox = styled.View` 32 | transform: rotate(90deg); 33 | text-shadow-offset: 10 5; 34 | font-variant: small-caps; 35 | margin: 5 7 2; 36 | ` 37 | ``` 38 | 39 | > You cannot use the `keyframes` and `injectGlobal` helpers since ReactNative doesn't support keyframes or global styles. We will also log a warning if you use media queries or nesting in your CSS. 40 | 41 | ## Animations 42 | 43 | To get React Native animations working, you'll want to define all your non-changing styles in the usual way, and then pass your `Animated.Value`s in as style props. 44 | 45 | ```js 46 | const BaseStyles = styled.View` 47 | height: 100; 48 | width: 100; 49 | background-color: red; 50 | ` 51 | 52 | class AnimateOpacity extends Component { 53 | constructor() { 54 | super() 55 | 56 | this.state = { 57 | opacity: new Animated.Value(0) 58 | } 59 | } 60 | 61 | componentWillMount() { 62 | Animated.timing(this.state.opacity, { 63 | toValue: 1, 64 | duration: 1000, 65 | }).start() 66 | } 67 | 68 | render() { 69 | const { opacity } = this.state; 70 | // Pass in your animated values here! 71 | return 72 | } 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable flowtype/require-valid-file-annotation, no-console */ 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 mode = prod ? 'production' : 'development' 16 | 17 | console.log(`Creating ${mode} bundle...`) 18 | 19 | const targets = prod ? 20 | [ 21 | { dest: 'dist/styled-components.min.js', format: 'umd' }, 22 | ] : 23 | [ 24 | { dest: 'dist/styled-components.js', format: 'umd' }, 25 | { dest: 'dist/styled-components.es.js', format: 'es' }, 26 | ] 27 | 28 | const plugins = [ 29 | // Unlike Webpack and Browserify, Rollup doesn't automatically shim Node 30 | // builtins like `process`. This ad-hoc plugin creates a 'virtual module' 31 | // which includes a shim containing just the parts the bundle needs. 32 | { 33 | resolveId(importee) { 34 | if (importee === processShim) return importee 35 | return null 36 | }, 37 | load(id) { 38 | if (id === processShim) return 'export default { argv: [], env: {} }' 39 | return null 40 | }, 41 | }, 42 | flow(), 43 | nodeResolve(), 44 | commonjs(), 45 | replace({ 46 | 'process.env.NODE_ENV': JSON.stringify(prod ? 'production' : 'development'), 47 | }), 48 | inject({ 49 | process: processShim, 50 | }), 51 | babel({ 52 | babelrc: false, 53 | presets: [ 54 | ['env', { modules: false }], 55 | 'react', 56 | ], 57 | plugins: [ 58 | 'flow-react-proptypes', 59 | 'transform-flow-strip-types', 60 | 'external-helpers', 61 | 'transform-object-rest-spread', 62 | 'transform-class-properties', 63 | ], 64 | }), 65 | json(), 66 | ] 67 | 68 | if (prod) plugins.push(uglify(), visualizer({ filename: './bundle-stats.html' })) 69 | 70 | export default { 71 | entry: 'src/index.js', 72 | moduleName: 'styled', 73 | external: ['react'], 74 | exports: 'named', 75 | targets, 76 | plugins, 77 | globals: { react: 'React' }, 78 | } 79 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/theming.md: -------------------------------------------------------------------------------- 1 | # Theming 2 | 3 | Theming is a first-class citizen in `styled-components`. We want to make it as easy as possible to use a reusable and sharable component library. 4 | 5 | ## Using theming 6 | 7 | We export a `` component that takes a `theme` prop. The `theme` you provide there is injected into your styled components via `props.theme`: 8 | 9 | ```JSX 10 | import styled, { ThemeProvider } from 'styled-components'; 11 | 12 | const Button = styled.button` 13 | /* Set the background of this button from the theme */ 14 | background: ${props => props.theme.main}; 15 | `; 16 | 17 | // Create a green theme 18 | const greenTheme = { 19 | main: 'mediumseagreen', 20 | }; 21 | 22 | // Create a red theme 23 | const redTheme = { 24 | main: 'palevioletred', 25 | }; 26 | 27 | const MyApp = () => { 28 | return ( 29 |
30 | {/* All children of this component will be green */} 31 | 32 | 33 | 34 | {/* All children of this component will be red */} 35 | 36 |
37 | 38 |
39 |
40 |
41 | ); 42 | } 43 | ``` 44 | 45 | Please make sure you sanitize user input if you accept custom themes from users! See the [security doc](./security.md) for more information. 46 | 47 | ## Function themes 48 | 49 | You can also pass a `theme` that is a function from `outerTheme => newValues`. This can be useful to make themes that are themselves contextual. 50 | 51 | ```js 52 | /* A theme that swaps the 'fg' and 'bg' colours for all its children. */ 53 | 54 | const InvertColors = ({children}) => ( 55 | ({ fg: outerTheme.bg, bg: outerTheme.fg })}> 56 | { children } 57 | 58 | ) 59 | ``` 60 | 61 | ## Getting the theme outside styled components 62 | 63 | If you ever need to get the current `theme` outside styled components (e.g. inside big components), you can use the `withTheme` Higher Order Component: 64 | 65 | ```JS 66 | import { withTheme } from 'styled-components' 67 | 68 | class MyComponent extends React.Component { 69 | render() { 70 | const { theme } = this.props 71 | 72 | console.log('Current theme: ', theme); 73 | // ... 74 | } 75 | } 76 | 77 | export default withTheme(MyComponent) 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/tagged-template-literals.md: -------------------------------------------------------------------------------- 1 | # ES6 Tagged Template Literals 2 | 3 | **For an alternate explanation see @mxstbr's blog post: [The magic behind :nail_care: styled-components](http://mxstbr.blog/2016/11/styled-components-magic-explained/)** 4 | 5 | Tagged Template Literals are a new feature in ES6 that lets you define _custom string interpolation_ rules, which is how we're able to create styled components. 6 | 7 | If you have no interpolations, they're very similar. This: 8 | 9 | ```js 10 | myFunction`some string here` 11 | ``` 12 | 13 | is equivalent to this: 14 | 15 | ```js 16 | myFunction(['some string here']) 17 | ``` 18 | 19 | When you use interpolations, a normal template string simply calls toString() on each interpolation and joins the string together: 20 | 21 | ```js 22 | const str = `1 + 2 = ${1 + 2}. Array: ${ [1,2,3] }. Object: ${ { a: 1 } }` 23 | //#> "1 + 2 = 3. Array: 1,2,3. Object: [object Object]" 24 | ``` 25 | 26 | But if you pass this to a template function, you get passed all the strings and interpolations and can do whatever you like! 27 | 28 | ```js 29 | const myFunction = (...args) => JSON.stringify([...args]) 30 | myFunction`1 + 2 = ${1 + 2}. Array: ${ [1,2,3] }. Object: ${ { a: 1 } }` 31 | //#> [ 32 | //#> ["1 + 2 = ", ". Array: ", ". Object: ", "" ], 33 | //#> 3, 34 | //#> [ 1, 2, 3 ], 35 | //#> { "a": 1 } 36 | //#> ] 37 | ``` 38 | 39 | The string chunks and interpolations are passed as follows: 40 | 41 | ```js 42 | myFunction( stringChunks, ...interpolations) 43 | ``` 44 | 45 | It's a little annoying to work with but it means that we can turn 46 | 47 | ```js 48 | styled.div` 49 | color: tomato; 50 | ${ props => props.background} 51 | ` 52 | ``` 53 | into an object and re-evaluate it whenever a StyledComponent's componentWillReceiveProps lifecycle method is called. Neat hey! 54 | 55 | ## In Styled Components 56 | 57 | Whenever you call ``styled.xyz` ... ` ``, underneath we call `css` with the CSS code. You can use `css` yourself if you ever need a chunk of CSS to work like a styled component: (kind of like a mixin!) 58 | 59 | ```js 60 | import styled, { css } from 'styled-components' 61 | 62 | const chunk = css` 63 | color: red; 64 | ${ props => props.background && 'background: white' } 65 | ` 66 | 67 | const Div = styled.div` 68 | ${ chunk } 69 | ` 70 | ``` 71 | 72 | If you leave off the `css` in `chunk` your function will be `toString()`ed and you'll not get the results you expected. 73 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/models/test/StyleSheet.test.js: -------------------------------------------------------------------------------- 1 | import styleSheet from '../StyleSheet' 2 | import { resetStyled } from '../../test/utils' 3 | import expect from 'expect' 4 | 5 | describe('stylesheet', () => { 6 | beforeEach(() => { 7 | resetStyled() 8 | }) 9 | 10 | describe('inject', () => { 11 | beforeEach(() => { 12 | styleSheet.inject() 13 | }) 14 | it('should inject the global sheet', () => { 15 | expect(styleSheet.globalStyleSheet.injected).toBe(true) 16 | }) 17 | it('should inject the component sheet', () => { 18 | expect(styleSheet.componentStyleSheet.injected).toBe(true) 19 | }) 20 | it('should specify that the sheets have been injected', () => { 21 | expect(styleSheet.injected).toBe(true) 22 | }) 23 | }) 24 | 25 | describe('flush', () => { 26 | beforeEach(() => { 27 | styleSheet.flush() 28 | }) 29 | it('should flush the global sheet', () => { 30 | expect(styleSheet.globalStyleSheet.injected).toBe(false) 31 | }) 32 | it('should flush the component sheet', () => { 33 | expect(styleSheet.componentStyleSheet.injected).toBe(false) 34 | }) 35 | it('should specify that the sheets are no longer injected', () => { 36 | expect(styleSheet.injected).toBe(false) 37 | }) 38 | }) 39 | 40 | it('should return both rules for both sheets', () => { 41 | styleSheet.insert('a { color: green }', { global: true }) 42 | styleSheet.insert('.hash1234 { color: blue }') 43 | 44 | expect(styleSheet.rules()).toEqual([ 45 | { cssText: 'a { color: green }' }, 46 | { cssText: '.hash1234 { color: blue }' } 47 | ]) 48 | }) 49 | 50 | describe('insert with the global option', () => { 51 | beforeEach(() => { 52 | styleSheet.insert('a { color: green }', { global: true }) 53 | }) 54 | it('should insert into the global sheet', () => { 55 | expect(styleSheet.globalStyleSheet.rules()).toEqual([ 56 | { cssText: 'a { color: green }' }, 57 | ]) 58 | }) 59 | it('should not inject into the component sheet', () => { 60 | expect(styleSheet.componentStyleSheet.rules()).toEqual([]) 61 | }) 62 | }) 63 | 64 | describe('insert without the global option', () => { 65 | beforeEach(() => { 66 | styleSheet.insert('.hash1234 { color: blue }') 67 | }) 68 | it('should inject into the component sheet', () => { 69 | expect(styleSheet.componentStyleSheet.rules()).toEqual([ 70 | { cssText: '.hash1234 { color: blue }' }, 71 | ]) 72 | }) 73 | it('should not inject into the global sheet', () => { 74 | expect(styleSheet.globalStyleSheet.rules()).toEqual([]) 75 | }) 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /docs/security.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | **Please do not forget to sanitize and validate input!** 4 | 5 | `styled-components` allows you to interpolate all kinds of things into your CSS. Some of these interpolations can consist of more than one declaration: 6 | 7 | ```JS 8 | // This totally works! 9 | const red = 'color: palevioletred; background: papayawhip;'; 10 | 11 | const Button = styled.button` 12 | ${red} 13 | ` 14 | ``` 15 | 16 | As powerful as this is, it's also a potential security hazard if you're not mindful because it allows CSS injection. Imagine something like this: 17 | 18 | ```JS 19 | import { someCSS } from '../utils-my-coworker-wrote'; 20 | 21 | const Box = styled.div` 22 | ${someCSS} 23 | ` 24 | ``` 25 | 26 | Now you glanced at this `someCSS` variable and somewhere inside the code this is declared: 27 | 28 | ```JS 29 | const someCSS = ` 30 | /* More styles here */ 31 | background: url(/api/withdraw-funds); 32 | /* More styles here */ 33 | ` 34 | ``` 35 | 36 | **⚠ OH NO ⚠** whenever you render this `Box` all of the users funds are withdrawn! 37 | 38 | ### Be very careful when interpolating more than a simple value. 39 | 40 | This is obviously a made-up example, but CSS injection can be unobvious and have bad repercussions. (some IE versions [execute arbitrary JavaScript within `url` declarations](http://httpsecure.org/?works=css-injection) or [within the `expression` directive](https://stackoverflow.com/questions/3607894/cross-site-scripting-in-css-stylesheets) 😱) 41 | 42 | ---- 43 | 44 | This is especially important when you take user input: 45 | 46 | Imagine you have an app which allows users to provide custom themes by pasting some CSS. Somebody posts a dark theme on their blog so users can have a "night mode". Super cool! 47 | 48 | Somewhere within this long string of CSS you let your users provide, the poster embedded our tiny declaration again: 49 | 50 | ```CSS 51 | .YourApp__navbar__item--active { 52 | background: url(/api/withdraw-funds); 53 | } 54 | ``` 55 | 56 | **⚠ OH NO ⚠** suddenly, every user that finds this random theme on Google and copy and pastes it to your app interface withdraws all their funds! 57 | 58 | ### Constrain user input 59 | 60 | If you let users input or configure themes, please make sure to constrain the inputs. The most important thing to keep in mind is to never let users provide more than simple values. As soon as you allow arbitrary CSS declarations, exploits like the one above become possible. For example, let users provide just six hex colors to configure the general skin of your app! 61 | 62 | By applying constraints to your themes, validation becomes much easier – run a short regex (like `/^#([A-F0-9]{6}|[A-F0-9]{3})$/i` for hex colors) or validation functions over the inputs to make sure what's provided contains nothing but simple values. 63 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /typings/themed-tests/mytheme-styled-components-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 | // Create a <Wrapper> react component that renders a <section> with 14 | // some padding and a papayawhip background 15 | const Wrapper = styled.section` 16 | background: ${p => p.theme.backgroundColor}; 17 | `; 18 | 19 | const Input = styled.input` 20 | font-size: 1.25em; 21 | padding: 0.5em; 22 | margin: ${p => p.theme.defaultMargin}em; 23 | color: palevioletred; 24 | background: papayawhip; 25 | border: none; 26 | border-radius: 3px; 27 | 28 | &:hover { 29 | box-shadow: inset 1px 1px 2px rgba(0,0,0,0.1); 30 | } 31 | `; 32 | 33 | interface ButtonProps { 34 | name: string; 35 | primary?: boolean; 36 | } 37 | 38 | class MyButton extends React.Component<ButtonProps, {}> { 39 | render() { 40 | return <button>Custom button</button>; 41 | } 42 | } 43 | 44 | const TomatoButton = styled(MyButton)` 45 | color: tomato; 46 | border-color: tomato; 47 | `; 48 | 49 | const CustomizableButton = styled(MyButton)` 50 | /* Adapt the colors based on primary prop */ 51 | background: ${props => props.primary ? "palevioletred" : "white"}; 52 | color: ${props => props.primary ? "white" : "palevioletred"}; 53 | 54 | font-size: 1em; 55 | margin: 1em; 56 | padding: 0.25em 1em; 57 | border: 2px solid ${props => props.theme.primaryColor}; 58 | border-radius: 3px; 59 | `; 60 | 61 | 62 | const example = css` 63 | font-size: 1.5em; 64 | text-align: center; 65 | color: ${props => props.theme.primaryColor}; 66 | border-color: ${"red"}; 67 | `; 68 | 69 | const fadeIn = keyframes` 70 | 0% { 71 | opacity: 0; 72 | } 73 | 100% { 74 | opacity: 1; 75 | } 76 | `; 77 | 78 | const theme: MyTheme = { 79 | primaryColor: "mediumseagreen", 80 | backgroundColor: "yellow", 81 | defaultMargin: .5 82 | }; 83 | 84 | injectGlobal` 85 | @font-face { 86 | font-family: 'Operator Mono'; 87 | src: url('../fonts/Operator-Mono.ttf'); 88 | } 89 | 90 | body { 91 | margin: 0; 92 | } 93 | `; 94 | 95 | class Example extends React.Component<{}, {}> { 96 | render() { 97 | return <ThemeProvider theme={theme}> 98 | <Wrapper> 99 | <Title>Hello World, this is my first styled component! 100 | 101 | 102 | 103 | ; 104 |
; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /docs/existing-css.md: -------------------------------------------------------------------------------- 1 | # Using `styled-components` with existing CSS 2 | 3 | `styled-components` generate an actual stylesheet with classes, and attaches those classes to the DOM nodes of styled components via the `className` prop. It injects the generated stylesheet at the end of the HEAD of the document. 4 | 5 | ## Styling normal React components 6 | 7 | If you use the `styled(MyNormalComponent)` notation and `MyNormalComponent` does not render the passed-in `className` prop the styles will **not** be applied. 8 | 9 | To avoid this issue, make sure your component (in this case `MyNormalComponent`) attaches the passed-in `className` to a DOM node: 10 | 11 | ```JSX 12 | class MyNormalComponent extends React.Component { 13 | render() { 14 | return ( 15 | // Attach the passed-in className to the DOM node 16 |
17 | ); 18 | } 19 | } 20 | ``` 21 | 22 | If you have pre-existing styles with a class, you can combine the global class with the `styled-components` one: 23 | 24 | ```JSX 25 | class MyNormalComponent extends React.Component { 26 | render() { 27 | return ( 28 | // Use a global class with existing styling in combination with 29 | // allowing this component to be styled with styled-components 30 |
31 | ); 32 | } 33 | } 34 | ``` 35 | 36 | ## Global class always overridden 37 | 38 | You can apply a global CSS class to a styled component by adding a `className` prop. This will work, but if a specific CSS property (e.g. `background-color`) is defined in both the global CSS _and_ the styled component the results may not be what your expecting! 39 | 40 | A contrived example: 41 | 42 | ```JS 43 | // MyComponent.js 44 | const MyComponent = styled.div`background-color: green;`; 45 | ``` 46 | 47 | ```CSS 48 | /* my-component.css */ 49 | .red-bg { 50 | background-color: red; 51 | } 52 | ``` 53 | 54 | ```JSX 55 | // For some reason this component still has a green background, 56 | // even though you're trying to override it with the "red-bg" class! 57 | 58 | ``` 59 | 60 | This is because `styled-components` injects the stylesheet at the end of the HEAD. If the CSS class you wrote is before the injected styles in the DOM, because of the cascade, the last styles targeting the same element (in this case the `styled-components` ones) will win! 61 | 62 | You can easily fix this by moving your CSS class to the beginning of the body in the DOM. 63 | 64 | Sadly, some tools (like the webpack `style-loader`) give you no control over the place they inject the CSS into, meaning you cannot move them after the `styled-components` one. 65 | 66 | The easy fix for that is bumping up the specificity of the CSS class you're overriding with, by writing it twice: 67 | 68 | ```CSS 69 | /* my-component.css */ 70 | .red-bg.red-bg { 71 | background-color: red; 72 | } 73 | ``` 74 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/utils/test/flatten.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import expect from 'expect' 3 | import flatten from '../flatten' 4 | 5 | describe('flatten', () => { 6 | it('doesnt merge strings', () => { 7 | expect(flatten(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz']) 8 | }) 9 | it('drops nulls', () => { 10 | // $FlowInvalidInputTest 11 | expect(flatten(['foo', false, 'bar', undefined, 'baz', null])).toEqual(['foo', 'bar', 'baz']) 12 | }) 13 | it('doesnt drop any numbers', () => { 14 | expect(flatten(['foo', 0, 'bar', NaN, 'baz', -1])).toEqual(['foo', '0', 'bar', 'NaN', 'baz', '-1']) 15 | }) 16 | it('toStrings everything', () => { 17 | // $FlowInvalidInputTest 18 | expect(flatten([1, true])).toEqual(['1', 'true']) 19 | }) 20 | it('hypenates objects', () => { 21 | const obj = { 22 | fontSize: '14px', 23 | WebkitFilter: 'blur(2px)', 24 | } 25 | const css = 'font-size: 14px; -webkit-filter: blur(2px);' 26 | // $FlowFixMe 27 | expect(flatten([obj])).toEqual([css]) 28 | // $FlowFixMe 29 | expect(flatten(['some:thing;', obj, 'something: else;'])).toEqual(['some:thing;', css, 'something: else;']) 30 | }) 31 | it('handles nested objects', () => { 32 | const obj = { 33 | fontSize: '14px', 34 | '@media screen and (min-width: 250px)': { 35 | fontSize: '16px', 36 | }, 37 | '&:hover': { 38 | fontWeight: 'bold', 39 | }, 40 | } 41 | const css = 'font-size: 14px; @media screen and (min-width: 250px) {\n font-size: 16px;\n} &:hover {\n font-weight: bold;\n}' 42 | // $FlowFixMe 43 | expect(flatten([obj])).toEqual([css]) 44 | // $FlowFixMe 45 | expect(flatten(['some:thing;', obj, 'something: else;'])).toEqual(['some:thing;', css, 'something: else;']) 46 | }) 47 | it('toStrings class instances', () => { 48 | class SomeClass { 49 | toString() { 50 | return 'some: thing;' 51 | } 52 | } 53 | // $FlowFixMe 54 | expect(flatten([new SomeClass()])).toEqual(['some: thing;']) 55 | }) 56 | it('flattens subarrays', () => { 57 | // $FlowFixMe 58 | expect(flatten([1, 2, [3, 4, 5], 'come:on;', 'lets:ride;'])).toEqual(['1', '2', '3', '4', '5', 'come:on;', 'lets:ride;']) 59 | }) 60 | it('defers functions', () => { 61 | const func = () => 'bar' 62 | // $FlowFixMe 63 | const funcWFunc = () => ['static', subfunc => subfunc ? 'bar' : 'baz'] 64 | expect(flatten(['foo', func, 'baz'])).toEqual(['foo', func, 'baz']) 65 | expect(flatten(['foo', funcWFunc, 'baz'])).toEqual(['foo', funcWFunc, 'baz']) 66 | }) 67 | it('executes functions', () => { 68 | const func = () => 'bar' 69 | expect(flatten(['foo', func, 'baz'], { bool: true })).toEqual(['foo', 'bar', 'baz']) 70 | }) 71 | it('passes values to function', () => { 72 | const func = ({ bool }) => bool ? 'bar' : 'baz' 73 | expect(flatten(['foo', func], { bool: true })).toEqual(['foo', 'bar']) 74 | expect(flatten(['foo', func], { bool: false })).toEqual(['foo', 'baz']) 75 | }) 76 | it('recursively calls functions', () => { 77 | // $FlowFixMe 78 | const func = () => ['static', ({ bool }) => bool ? 'bar' : 'baz'] 79 | expect(flatten(['foo', func], { bool: true })).toEqual(['foo', 'static', 'bar']) 80 | expect(flatten(['foo', func], { bool: false })).toEqual(['foo', 'static', 'baz']) 81 | }) 82 | }) 83 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /flow-typed/npm/lint-staged_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 2c993e7258d9783009c78a8fb70328cb 2 | // flow-typed version: <>/lint-staged_v^3.2.4/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'lint-staged' 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 'lint-staged' { 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 'lint-staged/src/findBin' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'lint-staged/src/generateTasks' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'lint-staged/src/index' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'lint-staged/src/resolvePaths' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'lint-staged/src/runScript' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'lint-staged/test/__fixtures__/test' { 46 | declare module.exports: any; 47 | } 48 | 49 | declare module 'lint-staged/test/findBin.spec' { 50 | declare module.exports: any; 51 | } 52 | 53 | declare module 'lint-staged/test/generateTasks.spec' { 54 | declare module.exports: any; 55 | } 56 | 57 | declare module 'lint-staged/test/resolvePaths.spec' { 58 | declare module.exports: any; 59 | } 60 | 61 | declare module 'lint-staged/test/runScript.spec' { 62 | declare module.exports: any; 63 | } 64 | 65 | declare module 'lint-staged/wallaby' { 66 | declare module.exports: any; 67 | } 68 | 69 | // Filename aliases 70 | declare module 'lint-staged/index' { 71 | declare module.exports: $Exports<'lint-staged'>; 72 | } 73 | declare module 'lint-staged/index.js' { 74 | declare module.exports: $Exports<'lint-staged'>; 75 | } 76 | declare module 'lint-staged/src/findBin.js' { 77 | declare module.exports: $Exports<'lint-staged/src/findBin'>; 78 | } 79 | declare module 'lint-staged/src/generateTasks.js' { 80 | declare module.exports: $Exports<'lint-staged/src/generateTasks'>; 81 | } 82 | declare module 'lint-staged/src/index.js' { 83 | declare module.exports: $Exports<'lint-staged/src/index'>; 84 | } 85 | declare module 'lint-staged/src/resolvePaths.js' { 86 | declare module.exports: $Exports<'lint-staged/src/resolvePaths'>; 87 | } 88 | declare module 'lint-staged/src/runScript.js' { 89 | declare module.exports: $Exports<'lint-staged/src/runScript'>; 90 | } 91 | declare module 'lint-staged/test/__fixtures__/test.js' { 92 | declare module.exports: $Exports<'lint-staged/test/__fixtures__/test'>; 93 | } 94 | declare module 'lint-staged/test/findBin.spec.js' { 95 | declare module.exports: $Exports<'lint-staged/test/findBin.spec'>; 96 | } 97 | declare module 'lint-staged/test/generateTasks.spec.js' { 98 | declare module.exports: $Exports<'lint-staged/test/generateTasks.spec'>; 99 | } 100 | declare module 'lint-staged/test/resolvePaths.spec.js' { 101 | declare module.exports: $Exports<'lint-staged/test/resolvePaths.spec'>; 102 | } 103 | declare module 'lint-staged/test/runScript.spec.js' { 104 | declare module.exports: $Exports<'lint-staged/test/runScript.spec'>; 105 | } 106 | declare module 'lint-staged/wallaby.js' { 107 | declare module.exports: $Exports<'lint-staged/wallaby'>; 108 | } 109 | -------------------------------------------------------------------------------- /docs/typescript-support.md: -------------------------------------------------------------------------------- 1 | # Typescript Support 2 | 3 | `styled-components` has typescript definitions to allow the library to be 4 | used in any Typescript project. 5 | 6 | To use the library you can import it as you normally do with any TS dependency. 7 | 8 | ``` 9 | import styled from 'styled-components' 10 | ``` 11 | 12 | ## Example 13 | 14 | A very basic example can be found [here](https://github.com/patrick91/Styled-Components-Typescript-Example). 15 | 16 | ## Define a Theme Interface 17 | 18 | By default every styled component will have the theme prop set to `any`. 19 | When building complex apps it would be better to have autocomplete and 20 | error checks everywhere. 21 | 22 | To have autocomplete and checks around the theme prop we should first define 23 | the theme interface we would like to use throught our app: 24 | 25 | ```ts 26 | // theme.ts 27 | export default interface ThemeInterface { 28 | primaryColor: string; 29 | primaryColorInverted: string; 30 | } 31 | ``` 32 | 33 | then we can re-export the styled function with our custom theme interface: 34 | 35 | ```ts 36 | // my-styled-components.ts 37 | import * as styledComponents from "styled-components"; 38 | import { ThemedStyledComponentsModule } from "styled-components"; 39 | 40 | import ThemeInterface from "./theme"; 41 | 42 | const { 43 | default: styled, 44 | css, 45 | injectGlobal, 46 | keyframes, 47 | ThemeProvider 48 | } = styledComponents as ThemedStyledComponentsModule; 49 | 50 | export default styled; 51 | export { css, injectGlobal, keyframes, ThemeProvider }; 52 | ``` 53 | 54 | Finally, instead of importing the styled functions from the `styled-components` module, 55 | we import it from our custom module. 56 | 57 | ```ts 58 | import * as React from "react"; 59 | 60 | // same for css, etc 61 | import styled from "themed-components"; 62 | 63 | 64 | const Link = styled.a` 65 | font-family: 'Cabin'; 66 | font-weight: bold; 67 | font-size: 1.2rem; 68 | letter-spacing: 0.05em; 69 | color: {props => props.theme.primaryColor}; 70 | display: block; 71 | cursor: pointer; 72 | 73 | transition: 0.3s background ease-out; 74 | 75 | &:hover { 76 | background: rgba(255, 255, 255, 0.2); 77 | } 78 | `; 79 | 80 | 81 | export default Link; 82 | ``` 83 | 84 | ## Caveats 85 | 86 | ### Class Name 87 | 88 | When defining a component you'd need to have `className` marked as optional 89 | in the propTypes interface: 90 | 91 | ```ts 92 | interface LogoProps { 93 | className?: string; 94 | } 95 | 96 | 97 | class Logo extends React.Component { 98 | render() { 99 | return
100 | Logo 101 |
; 102 | } 103 | } 104 | 105 | const LogoStyled = styled(Logo)` 106 | font-family: 'Helvetica'; 107 | font-weight: bold; 108 | font-size: 1.8rem; 109 | `; 110 | ``` 111 | 112 | This is because typescript won't understand that `LogoStyled` has already a `className` set. 113 | 114 | ### Stateless Component 115 | 116 | 117 | To use stateless components and have typechecking for the props you'd need to 118 | define the component alongside with its type, like this: 119 | 120 | ```ts 121 | interface BoxProps { 122 | theme?: ThemeInterface; 123 | borders?: boolean; 124 | className?: string; 125 | } 126 | 127 | 128 | const Box:React.StatelessComponent = (props) => 129 |
{props.children}
; 130 | 131 | 132 | const StyledBox = styled(Box)` 133 | padding: ${props => props.theme.lateralPadding}; 134 | `; 135 | ``` 136 | -------------------------------------------------------------------------------- /native/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as ReactNative from "react-native"; 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 ReactNativeStyledFunction

= StyledFunction

; 23 | 24 | export interface StyledInterface extends BaseStyledInterface { 25 | ActivityIndicator: ReactNativeStyledFunction; 26 | ActivityIndicatorIOS: ReactNativeStyledFunction; 27 | 28 | // ART: StyledFunction; 29 | Button: ReactNativeStyledFunction; 30 | DatePickerIOS: ReactNativeStyledFunction; 31 | DrawerLayoutAndroid: ReactNativeStyledFunction; 32 | Image: ReactNativeStyledFunction; 33 | 34 | KeyboardAvoidingView: ReactNativeStyledFunction; 35 | ListView: ReactNativeStyledFunction; 36 | MapView: ReactNativeStyledFunction; 37 | Modal: ReactNativeStyledFunction; 38 | Navigator: ReactNativeStyledFunction; 39 | NavigatorIOS: ReactNativeStyledFunction; 40 | Picker: ReactNativeStyledFunction; 41 | PickerIOS: ReactNativeStyledFunction; 42 | ProgressBarAndroid: ReactNativeStyledFunction; 43 | ProgressViewIOS: ReactNativeStyledFunction; 44 | ScrollView: ReactNativeStyledFunction; 45 | SegmentedControlIOS: ReactNativeStyledFunction; 46 | Slider: ReactNativeStyledFunction; 47 | SliderIOS: ReactNativeStyledFunction; 48 | SnapshotViewIOS: ReactNativeStyledFunction; 49 | RecyclerViewBackedScrollView: ReactNativeStyledFunction; 50 | RefreshControl: ReactNativeStyledFunction; 51 | StatusBar: ReactNativeStyledFunction; 52 | SwipeableListView: ReactNativeStyledFunction; 53 | Switch: ReactNativeStyledFunction; 54 | SwitchIOS: ReactNativeStyledFunction; 55 | Text: ReactNativeStyledFunction; 56 | TextInput: ReactNativeStyledFunction; 57 | TouchableHighlight: ReactNativeStyledFunction; 58 | TouchableNativeFeedback: ReactNativeStyledFunction; 59 | TouchableOpacity: ReactNativeStyledFunction; 60 | TouchableWithoutFeedback: ReactNativeStyledFunction; 61 | View: ReactNativeStyledFunction; 62 | ViewPagerAndroid: ReactNativeStyledFunction; 63 | WebView: ReactNativeStyledFunction; 64 | } 65 | 66 | declare const styled: StyledInterface; 67 | 68 | export default styled; 69 | -------------------------------------------------------------------------------- /src/vendor/postcss/warning.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a plugin’s warning. It can be created using {@link Node#warn}. 3 | * 4 | * @example 5 | * if ( decl.important ) { 6 | * decl.warn(result, 'Avoid !important', { word: '!important' }); 7 | * } 8 | */ 9 | class Warning { 10 | 11 | /** 12 | * @param {string} text - warning message 13 | * @param {Object} [opts] - warning options 14 | * @param {Node} opts.node - CSS node that caused the warning 15 | * @param {string} opts.word - word in CSS source that caused the warning 16 | * @param {number} opts.index - index in CSS node string that caused 17 | * the warning 18 | * @param {string} opts.plugin - name of the plugin that created 19 | * this warning. {@link Result#warn} fills 20 | * this property automatically. 21 | */ 22 | constructor(text, opts = { }) { 23 | /** 24 | * @member {string} - Type to filter warnings from 25 | * {@link Result#messages}. Always equal 26 | * to `"warning"`. 27 | * 28 | * @example 29 | * const nonWarning = result.messages.filter(i => i.type !== 'warning') 30 | */ 31 | this.type = 'warning'; 32 | /** 33 | * @member {string} - The warning message. 34 | * 35 | * @example 36 | * warning.text //=> 'Try to avoid !important' 37 | */ 38 | this.text = text; 39 | 40 | if ( opts.node && opts.node.source ) { 41 | let pos = opts.node.positionBy(opts); 42 | /** 43 | * @member {number} - Line in the input file 44 | * with this warning’s source 45 | * 46 | * @example 47 | * warning.line //=> 5 48 | */ 49 | this.line = pos.line; 50 | /** 51 | * @member {number} - Column in the input file 52 | * with this warning’s source. 53 | * 54 | * @example 55 | * warning.column //=> 6 56 | */ 57 | this.column = pos.column; 58 | } 59 | 60 | for ( let opt in opts ) this[opt] = opts[opt]; 61 | } 62 | 63 | /** 64 | * Returns a warning position and message. 65 | * 66 | * @example 67 | * warning.toString() //=> 'postcss-lint:a.css:10:14: Avoid !important' 68 | * 69 | * @return {string} warning position and message 70 | */ 71 | toString() { 72 | if ( this.node ) { 73 | return this.node.error(this.text, { 74 | plugin: this.plugin, 75 | index: this.index, 76 | word: this.word 77 | }).message; 78 | } else if ( this.plugin ) { 79 | return this.plugin + ': ' + this.text; 80 | } else { 81 | return this.text; 82 | } 83 | } 84 | 85 | /** 86 | * @memberof Warning# 87 | * @member {string} plugin - The name of the plugin that created 88 | * it will fill this property automatically. 89 | * this warning. When you call {@link Node#warn} 90 | * 91 | * @example 92 | * warning.plugin //=> 'postcss-important' 93 | */ 94 | 95 | /** 96 | * @memberof Warning# 97 | * @member {Node} node - Contains the CSS node that caused the warning. 98 | * 99 | * @example 100 | * warning.node.toString() //=> 'color: white !important' 101 | */ 102 | 103 | } 104 | 105 | export default Warning; 106 | -------------------------------------------------------------------------------- /src/models/test/ThemeProvider.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* eslint-disable react/no-multi-comp */ 3 | import React from 'react' 4 | import PropTypes from 'prop-types'; 5 | import expect from 'expect' 6 | import { shallow, render } from 'enzyme' 7 | import ThemeProvider, { CHANNEL } from '../ThemeProvider' 8 | 9 | describe('ThemeProvider', () => { 10 | it('should not throw an error when no children are passed', () => { 11 | const result = shallow() 12 | expect(result.html()).toEqual(null) 13 | }) 14 | 15 | it('should accept a theme prop that\'s a plain object', () => { 16 | shallow() 17 | }) 18 | 19 | it('should render its child', () => { 20 | const child = (

Child!

) 21 | const renderedComp = shallow( 22 | 23 | { child } 24 | 25 | ) 26 | expect(renderedComp.contains(child)).toEqual(true) 27 | }) 28 | 29 | it('should merge its theme with an outer theme', (done) => { 30 | const outerTheme = { main: 'black' } 31 | const innerTheme = { secondary: 'black' } 32 | // Setup Child 33 | class Child extends React.Component { 34 | componentWillMount() { 35 | this.context[CHANNEL](theme => { 36 | expect(theme).toEqual({ ...outerTheme, ...innerTheme }) 37 | done() 38 | }) 39 | } 40 | render() { return null } 41 | } 42 | Child.contextTypes = { 43 | [CHANNEL]: PropTypes.object, 44 | } 45 | 46 | render( 47 | 48 | 49 | 50 | 51 | 52 | ) 53 | }) 54 | 55 | it('should merge its theme with multiple outer themes', (done) => { 56 | const outerestTheme = { main: 'black' } 57 | const outerTheme = { main: 'blue' } 58 | const innerTheme = { secondary: 'black' } 59 | // Setup Child 60 | class Child extends React.Component { 61 | componentWillMount() { 62 | this.context[CHANNEL](theme => { 63 | expect(theme).toEqual({ ...outerestTheme, ...outerTheme, ...innerTheme }) 64 | done() 65 | }) 66 | } 67 | render() { return null } 68 | } 69 | Child.contextTypes = { 70 | [CHANNEL]: PropTypes.object, 71 | } 72 | 73 | render( 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | ) 82 | }) 83 | 84 | it('should be able to render two independent themes', (done) => { 85 | const themes = { 86 | one: { main: 'black', secondary: 'red' }, 87 | two: { main: 'blue', other: 'green' }, 88 | } 89 | let childRendered = 0 90 | // Setup Child 91 | class Child extends React.Component { 92 | componentWillMount() { 93 | this.context[CHANNEL](theme => { 94 | // eslint-disable-next-line react/prop-types 95 | expect(theme).toEqual(themes[this.props.shouldHaveTheme]) 96 | childRendered++ // eslint-disable-line no-plusplus 97 | if (childRendered === Object.keys(themes).length) { 98 | done() 99 | } 100 | }) 101 | } 102 | render() { return null } 103 | } 104 | Child.contextTypes = { 105 | [CHANNEL]: PropTypes.object, 106 | } 107 | 108 | render( 109 |
110 | 111 | 112 | 113 | 114 | 115 | 116 |
117 | ) 118 | }) 119 | }) 120 | -------------------------------------------------------------------------------- /src/vendor/postcss/at-rule.js: -------------------------------------------------------------------------------- 1 | import Container from './container'; 2 | import warnOnce from './warn-once'; 3 | 4 | /** 5 | * Represents an at-rule. 6 | * 7 | * If it’s followed in the CSS by a {} block, this node will have 8 | * a nodes property representing its children. 9 | * 10 | * @extends Container 11 | * 12 | * @example 13 | * const root = postcss.parse('@charset "UTF-8"; @media print {}'); 14 | * 15 | * const charset = root.first; 16 | * charset.type //=> 'atrule' 17 | * charset.nodes //=> undefined 18 | * 19 | * const media = root.last; 20 | * media.nodes //=> [] 21 | */ 22 | class AtRule extends Container { 23 | 24 | constructor(defaults) { 25 | super(defaults); 26 | this.type = 'atrule'; 27 | } 28 | 29 | append(...children) { 30 | if ( !this.nodes ) this.nodes = []; 31 | return super.append(...children); 32 | } 33 | 34 | prepend(...children) { 35 | if ( !this.nodes ) this.nodes = []; 36 | return super.prepend(...children); 37 | } 38 | 39 | get afterName() { 40 | warnOnce('AtRule#afterName was deprecated. Use AtRule#raws.afterName'); 41 | return this.raws.afterName; 42 | } 43 | 44 | set afterName(val) { 45 | warnOnce('AtRule#afterName was deprecated. Use AtRule#raws.afterName'); 46 | this.raws.afterName = val; 47 | } 48 | 49 | get _params() { 50 | warnOnce('AtRule#_params was deprecated. Use AtRule#raws.params'); 51 | return this.raws.params; 52 | } 53 | 54 | set _params(val) { 55 | warnOnce('AtRule#_params was deprecated. Use AtRule#raws.params'); 56 | this.raws.params = val; 57 | } 58 | 59 | /** 60 | * @memberof AtRule# 61 | * @member {string} name - the at-rule’s name immediately follows the `@` 62 | * 63 | * @example 64 | * const root = postcss.parse('@media print {}'); 65 | * media.name //=> 'media' 66 | * const media = root.first; 67 | */ 68 | 69 | /** 70 | * @memberof AtRule# 71 | * @member {string} params - the at-rule’s parameters, the values 72 | * that follow the at-rule’s name but precede 73 | * any {} block 74 | * 75 | * @example 76 | * const root = postcss.parse('@media print, screen {}'); 77 | * const media = root.first; 78 | * media.params //=> 'print, screen' 79 | */ 80 | 81 | /** 82 | * @memberof AtRule# 83 | * @member {object} raws - Information to generate byte-to-byte equal 84 | * node string as it was in the origin input. 85 | * 86 | * Every parser saves its own properties, 87 | * but the default CSS parser uses: 88 | * 89 | * * `before`: the space symbols before the node. It also stores `*` 90 | * and `_` symbols before the declaration (IE hack). 91 | * * `after`: the space symbols after the last child of the node 92 | * to the end of the node. 93 | * * `between`: the symbols between the property and value 94 | * for declarations, selector and `{` for rules, or last parameter 95 | * and `{` for at-rules. 96 | * * `semicolon`: contains true if the last child has 97 | * an (optional) semicolon. 98 | * * `afterName`: the space between the at-rule name and its parameters. 99 | * 100 | * PostCSS cleans at-rule parameters from comments and extra spaces, 101 | * but it stores origin content in raws properties. 102 | * As such, if you don’t change a declaration’s value, 103 | * PostCSS will use the raw value with comments. 104 | * 105 | * @example 106 | * const root = postcss.parse(' @media\nprint {\n}') 107 | * root.first.first.raws //=> { before: ' ', 108 | * // between: ' ', 109 | * // afterName: '\n', 110 | * // after: '\n' } 111 | */ 112 | } 113 | 114 | export default AtRule; 115 | -------------------------------------------------------------------------------- /src/test/extending.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react' 3 | import PropTypes from 'prop-types'; 4 | import expect from 'expect' 5 | import { shallow } from 'enzyme' 6 | 7 | import { resetStyled, expectCSSMatches } from './utils' 8 | 9 | let styled 10 | 11 | describe('extending', () => { 12 | /** 13 | * Make sure the setup is the same for every test 14 | */ 15 | beforeEach(() => { 16 | styled = resetStyled() 17 | }) 18 | 19 | it('should generate a single class with no styles', () => { 20 | const Parent = styled.div`` 21 | const Child = styled(Parent)`` 22 | 23 | shallow() 24 | shallow() 25 | 26 | expectCSSMatches('.a { }') 27 | }) 28 | 29 | it('should generate a single class if only parent has styles', () => { 30 | const Parent = styled.div`color: blue;` 31 | const Child = styled(Parent)`` 32 | 33 | shallow() 34 | shallow() 35 | 36 | expectCSSMatches('.a { color: blue; }') 37 | }) 38 | 39 | it('should generate a single class if only child has styles', () => { 40 | const Parent = styled.div`color: blue;` 41 | const Child = styled(Parent)`` 42 | 43 | shallow() 44 | shallow() 45 | 46 | expectCSSMatches('.a { color: blue; }') 47 | }) 48 | 49 | it('should generate a class for the child with the rules of the parent', () => { 50 | const Parent = styled.div`color: blue;` 51 | const Child = styled(Parent)`color: red;` 52 | 53 | shallow() 54 | 55 | expectCSSMatches('.a { color: blue;color: red; }') 56 | }) 57 | 58 | it('should generate different classes for both parent and child', () => { 59 | const Parent = styled.div`color: blue;` 60 | const Child = styled(Parent)`color: red;` 61 | 62 | shallow() 63 | shallow() 64 | 65 | expectCSSMatches('.a { color: blue; } .b { color: blue;color: red; }') 66 | }) 67 | 68 | it('should copy nested rules to the child', () => { 69 | const Parent = styled.div` 70 | color: blue; 71 | > h1 { font-size: 4rem; } 72 | ` 73 | const Child = styled(Parent)`color: red;` 74 | 75 | shallow() 76 | shallow() 77 | 78 | expectCSSMatches(` 79 | .a { color: blue; } 80 | .a > h1 { font-size: 4rem; } 81 | .b { color: blue; color: red; } 82 | .b > h1 { font-size: 4rem; } 83 | `) 84 | }) 85 | 86 | it('should keep default props from parent', () => { 87 | const Parent = styled.div` 88 | color: ${(props) => props.color}; 89 | ` 90 | Parent.defaultProps = { 91 | color: 'red' 92 | } 93 | 94 | const Child = styled(Parent)`background-color: green;` 95 | 96 | shallow() 97 | shallow() 98 | 99 | expectCSSMatches(` 100 | .a { color: red; } 101 | .b { color: red; background-color: green; } 102 | `) 103 | }) 104 | 105 | it('should keep prop types from parent', () => { 106 | const Parent = styled.div` 107 | color: ${(props) => props.color}; 108 | ` 109 | Parent.propTypes = { 110 | color: PropTypes.string 111 | } 112 | 113 | const Child = styled(Parent)`background-color: green;` 114 | 115 | expect(Child.propTypes).toEqual(Parent.propTypes) 116 | }) 117 | 118 | it('should keep custom static member from parent', () => { 119 | const Parent = styled.div`color: red;` 120 | 121 | Parent.fetchData = () => 1 122 | 123 | const Child = styled(Parent)`color: green;` 124 | 125 | expect(Child.fetchData).toExist() 126 | expect(Child.fetchData()).toEqual(1) 127 | }) 128 | 129 | it('should keep static member in triple inheritance', () => { 130 | const GrandParent = styled.div`color: red;` 131 | GrandParent.fetchData = () => 1 132 | 133 | const Parent = styled(GrandParent)`color: red;` 134 | const Child = styled(Parent)`color:red;` 135 | 136 | expect(Child.fetchData).toExist() 137 | expect(Child.fetchData()).toEqual(1) 138 | }) 139 | }) 140 | -------------------------------------------------------------------------------- /typings/styled-components-test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import styled from ".."; 4 | import { css, keyframes, ThemeProvider, injectGlobal, withTheme } from ".."; 5 | 6 | // Create a react component that renders an <h1> which is 7 | // centered, palevioletred and sized at 1.5em 8 | const Title = styled.h1` 9 | font-size: 1.5em; 10 | text-align: center; 11 | color: palevioletred; 12 | `; 13 | 14 | // Create a <Wrapper> react component that renders a <section> with 15 | // some padding and a papayawhip background 16 | const Wrapper = styled.section` 17 | padding: 4em; 18 | background: papayawhip; 19 | `; 20 | 21 | 22 | const Input = styled.input` 23 | font-size: 1.25em; 24 | padding: 0.5em; 25 | margin: 0.5em; 26 | color: palevioletred; 27 | background: papayawhip; 28 | border: none; 29 | border-radius: 3px; 30 | 31 | &:hover { 32 | box-shadow: inset 1px 1px 2px rgba(0,0,0,0.1); 33 | } 34 | `; 35 | 36 | interface MyTheme { 37 | primary: string; 38 | } 39 | 40 | interface ButtonProps { 41 | name: string; 42 | primary?: boolean; 43 | theme?: MyTheme; 44 | } 45 | 46 | class MyButton extends React.Component<ButtonProps, {}> { 47 | render() { 48 | return <button>Custom button</button>; 49 | } 50 | } 51 | 52 | const TomatoButton = styled(MyButton)` 53 | color: tomato; 54 | border-color: tomato; 55 | `; 56 | 57 | const CustomizableButton = styled(MyButton)` 58 | /* Adapt the colors based on primary prop */ 59 | background: ${props => props.primary ? "palevioletred" : "white"}; 60 | color: ${props => props.primary ? "white" : "palevioletred"}; 61 | 62 | font-size: 1em; 63 | margin: 1em; 64 | padding: 0.25em 1em; 65 | border: 2px solid ${props => props.theme.primary}; 66 | border-radius: 3px; 67 | `; 68 | 69 | 70 | const example = css` 71 | font-size: 1.5em; 72 | text-align: center; 73 | color: ${props => props.theme.primary}; 74 | border-color: ${"red"}; 75 | `; 76 | 77 | const fadeIn = keyframes` 78 | 0% { 79 | opacity: 0; 80 | } 81 | 100% { 82 | opacity: 1; 83 | } 84 | `; 85 | 86 | const theme = { 87 | main: "mediumseagreen", 88 | }; 89 | 90 | injectGlobal` 91 | @font-face { 92 | font-family: 'Operator Mono'; 93 | src: url('../fonts/Operator-Mono.ttf'); 94 | } 95 | 96 | body { 97 | margin: 0; 98 | } 99 | `; 100 | 101 | class Example extends React.Component<{}, {}> { 102 | render() { 103 | return <ThemeProvider theme={theme}> 104 | <Wrapper> 105 | <Title>Hello World, this is my first styled component! 106 | 107 | 108 | 109 | ; 110 | ; 111 | } 112 | } 113 | 114 | // css which only uses simple interpolations without functions 115 | const cssWithValues1 = css` 116 | font-size: ${14}${"pt"}; 117 | `; 118 | // css which uses other simple interpolations without functions 119 | const cssWithValues2 = css` 120 | ${cssWithValues1} 121 | ${[cssWithValues1, cssWithValues1]} 122 | font-weight: ${"bold"}; 123 | `; 124 | // injectGlobal accepts simple interpolations if they're not using functions 125 | injectGlobal` 126 | ${"font-size"}: ${10}pt; 127 | ${cssWithValues1} 128 | ${[cssWithValues1, cssWithValues2]} 129 | `; 130 | 131 | // css which uses function interpolations with common props 132 | const cssWithFunc1 = css` 133 | font-size: ${(props) => props.theme.fontSizePt}pt; 134 | `; 135 | const cssWithFunc2 = css` 136 | ${cssWithFunc1} 137 | ${props => cssWithFunc2} 138 | ${[cssWithFunc1, cssWithValues1]} 139 | `; 140 | // such css can be used in styled components 141 | const styledButton = styled.button` 142 | ${cssWithValues1} ${[cssWithValues1, cssWithValues2]} 143 | ${cssWithFunc1} ${[cssWithFunc1, cssWithFunc2]} 144 | ${() => [cssWithFunc1, cssWithFunc2]} 145 | `; 146 | // css with function interpolations cannot be used in injectGlobal 147 | /* 148 | injectGlobal` 149 | ${cssWithFunc1} 150 | `; 151 | */ 152 | 153 | const name = "hey"; 154 | 155 | const ThemedButton = withTheme(MyButton); 156 | 157 | ; 158 | -------------------------------------------------------------------------------- /src/test/basic.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react' 3 | import expect from 'expect' 4 | import { shallow, mount } from 'enzyme' 5 | import jsdom from 'mocha-jsdom' 6 | 7 | import styleSheet from '../models/StyleSheet' 8 | import { resetStyled, expectCSSMatches } from './utils' 9 | 10 | let styled 11 | 12 | describe('basic', () => { 13 | /** 14 | * Make sure the setup is the same for every test 15 | */ 16 | beforeEach(() => { 17 | styled = resetStyled() 18 | }) 19 | 20 | it('should not throw an error when called', () => { 21 | styled.div`` 22 | }) 23 | 24 | it('should inject a stylesheet when a component is created', () => { 25 | const Comp = styled.div`` 26 | shallow() 27 | expect(styleSheet.injected).toBe(true) 28 | }) 29 | 30 | it('should not generate any styles by default', () => { 31 | styled.div`` 32 | expectCSSMatches('') 33 | }) 34 | 35 | it('should generate an empty tag once rendered', () => { 36 | const Comp = styled.div`` 37 | shallow() 38 | expectCSSMatches('.a { }') 39 | }) 40 | 41 | /* TODO: we should probably pretty-format the output so this test might have to change */ 42 | it('should pass through all whitespace', () => { 43 | const Comp = styled.div` \n ` 44 | shallow() 45 | expectCSSMatches('.a { \n }', { ignoreWhitespace: false }) 46 | }) 47 | 48 | it('should inject only once for a styled component, no matter how often it\'s mounted', () => { 49 | const Comp = styled.div`` 50 | shallow() 51 | shallow() 52 | expectCSSMatches('.a { }') 53 | }) 54 | 55 | it('Should have the correct styled(component) displayName', () => { 56 | const CompWithoutName = () => () =>
57 | 58 | const StyledTag = styled.div`` 59 | expect(StyledTag.displayName).toBe('styled.div') 60 | 61 | 62 | const CompWithName = () =>
63 | CompWithName.displayName = null 64 | const StyledCompWithName = styled(CompWithName)`` 65 | expect(StyledCompWithName.displayName).toBe('Styled(CompWithName)') 66 | 67 | 68 | const CompWithDisplayName = CompWithoutName() 69 | CompWithDisplayName.displayName = 'displayName' 70 | const StyledCompWithDisplayName = styled(CompWithDisplayName)`` 71 | expect(StyledCompWithDisplayName.displayName).toBe('Styled(displayName)') 72 | 73 | 74 | const CompWithBoth = () =>
75 | CompWithBoth.displayName = 'displayName' 76 | const StyledCompWithBoth = styled(CompWithBoth)`` 77 | expect(StyledCompWithBoth.displayName).toBe('Styled(displayName)') 78 | 79 | 80 | const CompWithNothing = CompWithoutName() 81 | CompWithNothing.displayName = null 82 | const StyledCompWithNothing = styled(CompWithNothing)`` 83 | expect(StyledCompWithNothing.displayName).toBe('Styled(Component)') 84 | }) 85 | 86 | describe('innerRef', () => { 87 | jsdom() 88 | 89 | it('should handle styled-components correctly', () => { 90 | const Comp = styled.div` 91 | ${props => expect(props.innerRef).toExist()} 92 | ` 93 | const WrapperComp = class extends Component { 94 | testRef: any; 95 | render() { 96 | return { this.testRef = comp }} /> 97 | } 98 | } 99 | const wrapper = mount() 100 | 101 | // $FlowFixMe 102 | expect(wrapper.node.testRef).toExist() 103 | // $FlowFixMe 104 | expect(wrapper.node.ref).toNotExist() 105 | }) 106 | 107 | it('should handle inherited components correctly', () => { 108 | const StyledComp = styled.div`` 109 | class WrappedStyledComp extends React.Component { 110 | render() { 111 | return ( 112 | 113 | ) 114 | } 115 | } 116 | const ChildComp = styled(WrappedStyledComp)`` 117 | const WrapperComp = class extends Component { 118 | testRef: any; 119 | render() { 120 | return { this.testRef = comp }} /> 121 | } 122 | } 123 | const wrapper = mount() 124 | 125 | // $FlowFixMe 126 | expect(wrapper.node.testRef).toExist() 127 | // $FlowFixMe 128 | expect(wrapper.node.ref).toNotExist() 129 | }) 130 | }) 131 | }) 132 | -------------------------------------------------------------------------------- /flow-typed/npm/mocha-jsdom_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: da2b5df44c1b606a49f651a0d9902a9f 2 | // flow-typed version: <>/mocha-jsdom_v^1.1.0/flow_v0.37.1 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'mocha-jsdom' 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 'mocha-jsdom' { 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 'mocha-jsdom/browser' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'mocha-jsdom/examples/basic/setup' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'mocha-jsdom/examples/basic/test' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'mocha-jsdom/examples/failures/one' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'mocha-jsdom/examples/failures/two' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'mocha-jsdom/test/fixtures/rerequirable' { 46 | declare module.exports: any; 47 | } 48 | 49 | declare module 'mocha-jsdom/test/globalize' { 50 | declare module.exports: any; 51 | } 52 | 53 | declare module 'mocha-jsdom/test/jquery' { 54 | declare module.exports: any; 55 | } 56 | 57 | declare module 'mocha-jsdom/test/rerequire_test' { 58 | declare module.exports: any; 59 | } 60 | 61 | declare module 'mocha-jsdom/test/robust' { 62 | declare module.exports: any; 63 | } 64 | 65 | declare module 'mocha-jsdom/test/setup' { 66 | declare module.exports: any; 67 | } 68 | 69 | declare module 'mocha-jsdom/test/simple' { 70 | declare module.exports: any; 71 | } 72 | 73 | declare module 'mocha-jsdom/test/skip_window_check' { 74 | declare module.exports: any; 75 | } 76 | 77 | declare module 'mocha-jsdom/test/standard_test' { 78 | declare module.exports: any; 79 | } 80 | 81 | declare module 'mocha-jsdom/test/use_each' { 82 | declare module.exports: any; 83 | } 84 | 85 | // Filename aliases 86 | declare module 'mocha-jsdom/browser.js' { 87 | declare module.exports: $Exports<'mocha-jsdom/browser'>; 88 | } 89 | declare module 'mocha-jsdom/examples/basic/setup.js' { 90 | declare module.exports: $Exports<'mocha-jsdom/examples/basic/setup'>; 91 | } 92 | declare module 'mocha-jsdom/examples/basic/test.js' { 93 | declare module.exports: $Exports<'mocha-jsdom/examples/basic/test'>; 94 | } 95 | declare module 'mocha-jsdom/examples/failures/one.js' { 96 | declare module.exports: $Exports<'mocha-jsdom/examples/failures/one'>; 97 | } 98 | declare module 'mocha-jsdom/examples/failures/two.js' { 99 | declare module.exports: $Exports<'mocha-jsdom/examples/failures/two'>; 100 | } 101 | declare module 'mocha-jsdom/index' { 102 | declare module.exports: $Exports<'mocha-jsdom'>; 103 | } 104 | declare module 'mocha-jsdom/index.js' { 105 | declare module.exports: $Exports<'mocha-jsdom'>; 106 | } 107 | declare module 'mocha-jsdom/test/fixtures/rerequirable.js' { 108 | declare module.exports: $Exports<'mocha-jsdom/test/fixtures/rerequirable'>; 109 | } 110 | declare module 'mocha-jsdom/test/globalize.js' { 111 | declare module.exports: $Exports<'mocha-jsdom/test/globalize'>; 112 | } 113 | declare module 'mocha-jsdom/test/jquery.js' { 114 | declare module.exports: $Exports<'mocha-jsdom/test/jquery'>; 115 | } 116 | declare module 'mocha-jsdom/test/rerequire_test.js' { 117 | declare module.exports: $Exports<'mocha-jsdom/test/rerequire_test'>; 118 | } 119 | declare module 'mocha-jsdom/test/robust.js' { 120 | declare module.exports: $Exports<'mocha-jsdom/test/robust'>; 121 | } 122 | declare module 'mocha-jsdom/test/setup.js' { 123 | declare module.exports: $Exports<'mocha-jsdom/test/setup'>; 124 | } 125 | declare module 'mocha-jsdom/test/simple.js' { 126 | declare module.exports: $Exports<'mocha-jsdom/test/simple'>; 127 | } 128 | declare module 'mocha-jsdom/test/skip_window_check.js' { 129 | declare module.exports: $Exports<'mocha-jsdom/test/skip_window_check'>; 130 | } 131 | declare module 'mocha-jsdom/test/standard_test.js' { 132 | declare module.exports: $Exports<'mocha-jsdom/test/standard_test'>; 133 | } 134 | declare module 'mocha-jsdom/test/use_each.js' { 135 | declare module.exports: $Exports<'mocha-jsdom/test/use_each'>; 136 | } 137 | --------------------------------------------------------------------------------