Coder Social home page Coder Social logo

martinandert / babel-plugin-css-in-js Goto Github PK

View Code? Open in Web Editor NEW
300.0 300.0 11.0 81 KB

A plugin for Babel v6 which transforms inline styles defined in JavaScript modules into class names so they become available to, e.g. the `className` prop of React elements. While transforming, the plugin processes all JavaScript style definitions found and bundles them up into a CSS file, ready to be requested from your web server.

License: MIT License

Makefile 2.02% Ruby 0.61% Shell 0.13% CSS 3.86% JavaScript 92.59% HTML 0.78%

babel-plugin-css-in-js's People

Contributors

b6pzeusbc54tvhw5jgpyw8pwz2x6gs avatar martinandert avatar menelaos avatar steadicat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

babel-plugin-css-in-js's Issues

context would be nice to take in an entry point file to be require'd

In react-inline it was possible to -t, --context <name=path> Add context item (require'd from path) as name and it was possible to define complex data structures in the required file etc but it appears this functionality has been removed here. With context defined in the .babelrc it's very inflexible. The use case I'm talking about is defining colors and using darken or lighten from color.js to define some more colors and then to use this in the style sheet definitions.

nested selector

Hello,

I wonder if there is a way to do something like

cssInJS({
  Title: {
     color: "red"
  },
  '$.my-webfont Title: {
      font-family: webfont'
   }
})

When dealing with async font loading, a common technique is to use a font-observer like https://github.com/bramstein/fontfaceobserver and decorate the body tag with specific classes once font are available.

CSS specificity

All generated classes have the same specificity, but that complicates extending generic styles with custom styles for a specific theme.

Example:

// Button.jsx

import React from 'react';
import classNames from 'classnames';

const Button = ({ className, children }) => (<button className={classNames(styles.button, className)}>{children}</button>);

const styles = cssInJS({
  button: {
    color: 'blue';
  }
});

export default Button;

// CustomButton.jsx

import React from 'react';
import Button from 'Button';

const CustomButton = () => (<Button className={styles.customButton}>Click me!</Button>);

const styles = cssInJS({
  customButton: {
    color: 'green'
  }
});

export default CustomButton;

When I render CustomButton, the color: 'blue' still takes precedence over color: 'green', but I want my green theming to override the default styling. Is there a mechanism to do that without resorting to specificity hacks?

Should not split media query blocks

Single media query blocks in the source JS are currently split up into multiple blocks, one per selector, in the output CSS. This creates larger files and also potentially slows down browser rendering.

var x = cssInJS({
  foo: { margin: 10 },
  bar: { border: '2px solid black' },
  baz: { padding: '0 20px' },
  '@media only screen and (min-width: 500px)': {
    foo: { margin: 5 },
    bar: { border: '1px solid black' },
    baz: { padding: '0 10px' },
  }
});

becomes:

{
  .foo { margin: 10px }
  @media only screen and (min-width: 500px) {
    .foo { margin: 5px }
  }
  .bar { border: 2px solid black }
  @media only screen and (min-width: 500px) {
    .bar { border: 1px solid black }
  }
  .baz { padding: 0 20px }
  @media only screen and (min-width: 500px) {
    .baz { padding: 0 10px }
  }
}

instead of:

{
  .foo { margin: 10px }
  .bar { border: 2px solid black }
  .baz { padding: 0 20px }
  @media only screen and (min-width: 500px) {
    .foo { margin: 5px }
    .bar { border: 1px solid black }
    .baz { padding: 0 10px }
  }
}

About more universal Nested Rules

Currently babel-plugin-css-in-js support some nested rules using global selectors $, but they are very limited. I'm considering implementing nested rules for a universal case used in css pre-processes such as less and stylus. ( see the example below )

Component:

<div className={ st.box }>
  <div className={ st.hiddenBtn }/>
</div>

css-in-js

const st = cssInJS({
  box: {
    color: 'red',
  },

  hiddenBtn: {
    opacity: 0
  },

  // I want to follow Nested Rules
  'box:hover': {
    '.hiddenBtn': {
      opacity: 1,
    }
  }
})

babel:

const st = {
  box: 'dir_filename_js-styles-box',
  hiddenBtn: 'dir_filename_js-styles-hiddenBtn'
}

css

.dir_filename_js-styles-box {
  color: red;
}
.dir_filename_js-styles-hiddenBtn {
  opacity: 0;
}
.dir_filename_js-styles-box:hover .dir_filename_js-styles-hiddenBtn {
  opacity: 1;
}

screen shot 2017-03-27 at 8 22 18 pm
[Image1]

In the First box in Image1 .box .hiddenBtn selector works well. But in the second box, .box .hiddenBtn selector will select all .hiddenBtn in the box.
it might be a bug. (Because developers always can write .box .hiddenBtn selector instead of .box > .hiddenBtn selector, I don't mention about .box > .hiddenBtn selector here )

So I like the globally unique (randomized) className this plugin creates. Ever since I use this plugin, no matter how big the application was, there was no bug affected by the unintentional css rule. In order to keep this benefit, in nested rules, both box and hiddenBtn must be uniqued.

The global selector concept is great for theme, but I want to implement nested rules with a more universal concept that is used by other pre-processors that operate independently of the global selector nested rules.

Could I make some PR?

Support specific platform or theme?

Suppose I have a below button style.

const styles = cssInJS({
  button: {
    width: 57,
    height: 57,
  },
})

I wanna make some css properties changes on the specific platform ios.

// case1)
const styles = cssInJS({
  button: {
    width: __IOS__ ? 40 : 57,
    height: 57,
  },
})

or wanna make changes in some classes,

// case2)
const styles = cssInJS({
  button: __IOS__ ? {
    width: 40,
    height: 57,
  } : {
    width: 57,
    height: 57,
  }
})

In the above examples, __IOS__ will be defined by webpack definePlugin, or It will be just normal variable.

Now, I have to add another class, like button_ios.
but that way make a bundle with all classes even useless.

Do you have any plan about that feature supporting specific platform or theme style using condition statement?
If you are not available now, It wouldn't be easy to do, but I cound make a PR.

Single letter class names cause an error

I had the following in a cssInJS block

a: {
  width: 150,
  margin: 'auto'
}

and got the error:

Module build failed: AssertionError: /Users/Developer/workspace/projects/formulagrid/website/src/containers/HomePage.js: style name is invalid
    at initStyleSpec (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-plugin-css-in-js/lib/transformStyleSheetObjectIntoSpecification.js:162:24)
    at processStyle (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-plugin-css-in-js/lib/transformStyleSheetObjectIntoSpecification.js:83:15)
    at /Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-plugin-css-in-js/lib/transformStyleSheetObjectIntoSpecification.js:50:7
    at forEach (/Users/Developer/workspace/projects/formulagrid/website/node_modules/foreach/index.js:17:20)
    at transformStyleSheetObjectIntoSpecification (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-plugin-css-in-js/lib/transformStyleSheetObjectIntoSpecification.js:35:25)
    at PluginPass.CallExpression (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-plugin-css-in-js/lib/index.js:116:76)
    at newFn (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-traverse/lib/visitors.js:293:19)
    at NodePath._call (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-traverse/lib/path/context.js:74:18)
    at NodePath.call (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-traverse/lib/path/context.js:46:17)
    at NodePath.visit (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-traverse/lib/path/context.js:104:12)
    at TraversalContext.visitQueue (/Users/Developer/workspace/projects/formulagrid/website/node_modules/babel-traverse/lib/context.js:156:16)
 @ ./src/containers/App.js 13:16-37

This was also the case with any other single letter names I tried out. Changing it to two letters fixes the problem.

Dynamic style objects

I tried

var item = {
  color: 'red'
};
var styles = cssInJS({
  item: item
});

But I got the warning "Top level value must be an object expression".

I'm assuming that's what you mean in the caveats about not being able to do dynamic stuff in the stylesheet. Am I right? Is there any plan on adding dynamic functionality? It'd be great to use this if it did.

Is there any support for sub-selectors currently?

Hello, I wonder if subselectors are supported at the moment, since either of following syntax seems to throw syntax errors,

// Either 
const classes = ({
  'wrapper title': {
    margin: 1,
  }
})

// Or
const classes = ({
  'wrapper': {
    'title': {
      margin: 1,
    }
  }
})

Despite the second syntax being a SASS style and might not be the focus of this project, the first syntax actually belongs to CSS syntax and is quite useful, or actually irreplaceably necessary, in practice.

feature request: support template literal

I love inline-css, but I don't like the mental gymnastics I need to do to convert css into a js object.

Could we add template literal support to allow us to write more vanilla css?

for example we could convert this:

const styles =  cssInJs({
  myButton: {
    border: 'solid 1px #ccc',
    backgroundColor: 'lightgray',

    ':hover': {
      borderColor: '#ddd',

      ':active': {
        borderColor: '#eee'
      }
    },

    '[disabled]': {
      opacity: .5,
    }
  },

  '@media only screen and (max-width: 480px)': {
    myButton: {
      borderWidth: 0
    }
  }
})

to

const styles =  cssInJs(`
  .myButton {
    border: solid 1px #ccc
    background-color: lightgray

    &:hover {
      border-color: #ddd

      &:active {
        border-color: #eee
      }
    }

    &[disabled] {
      opacity: .5
    }

    @media only screen and (max-width: 480px) {
      border-width: 0
    }
  }
`)

the output would be the same

const styles = {
  myButton: 'example_js_styles_button'
}

Not Getting Expressions To Work AssertionError

Im getting and error:

AssertionError: /PATH/TO/PAGE : invalid value expression type while parsing file /PATH/TO/SAME/PAGE

I have a simple CSS:

main.js

var colors = require('../styles/colors'); var pageCss = cssInJS({ 'default' : { 'backgroundColor' : colors.greys._1 } });

colors.js

var colors = { 'greys' : { _1 : '#F2F5F8' } }; module.exports = colors;

Support global style rules

It would be great if it were an escape hatch that would allow you to specify global style rules in JS as well, without having to use a separate syntax and pipeline for it.

There could be a special syntax that would opt a rule out of the selector rewriting. For example:

const globalStyles = cssInJS({
  '$body': {margin: 0},
  '$.small-caps': {textTransform: 'uppercase', fontSize: '0.9%'},
});

This would inject the following into the generated stylesheet:

body {margin: 0px}
.small-caps {text-transform: uppercase; font-size: 0.9%}

nth-of-type example

For stuff like this in css

p:nth-of-type(1) {}
p:nth-of-type(2) {}
p:nth-of-type(3) {}

you basically need to create object with styling for every p and then attach it to that element? What's the best practice for this stuff?

Usage in a webpack dev environment

I am wondering how one would go about setting a webpack dev environment up with this plugin? All my efforts have so far ended up with the styles of the last saved file overwriting the content of the bundled file.

String value cannot be blank

On this line of transformObjectExpressionIntoStyleSheetObject, the string value is checked to see if it is blank, which is currently matching all whitespace characters.

This disallows CSS that looks like this:

const stylesheet = cssInJS({
    default: {
        ':after': {
            content: " "    // There is a an empty space here so that the pseudo element renders
        }
    }
});

This is needed to do some styling things where content is not necessary for the pseudo element. A change that would fix this problem is simply:

    assert(val.length >= 1, 'string value cannot be blank');

instead of the isBlank call. This still prevents empty strings, but allows deliberately white space strings for CSS properties.

Is there any solution about universal app?

Recently, I'm working on the study about universal app like react-redux-universal-hot-example. As far as I know, in universal app, js files are loaded from different ways on each server and client side. Server side use the babel-register but client side use a bundle js file from webpack.

I have a question. Assuming that my code state haven't changed and use the same babelrc and options, regardless of the loading method(babel-register or webpack), does babel-plugin-css-in-js always guarantee to create the same class name? Even when I use compressClassName option, always guarantee it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.