Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

j2c

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

j2c

A JavaScript object to CSS compiler.

  • 0.3.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
76
increased by11.76%
Maintainers
1
Weekly downloads
 
Created
Source

j2c

JavaScript object to CSS compiler. ~720 bytes mingzipped.

Think SASS, but in JSONish syntax.

Inspired by restlye.js and JSS, but smaller :-).


##Table of Contents

TOC generated with DocToc, then tweaked a bit.


Why?

  • Send small, compact, SASS-like data down the line
  • Simplify your asset pipeline
  • Use the full power of JavaScript for mixins, variables, macros and feature detection
  • Stop worrying about vendor prefixes
  • Good fit for virtual DOM frameworks like React or Mithril
  • I like writing compilers :-)

But, seriously...

This is mostly intended as a client-side helper to generate styles for Virtual DOM (React, Mithril, Mercury...) components.

Whether or not this is useful as a general CSS replacement remains to be seen.

For that use case, it trades off file size down the line for time lost because the rendering is blocked by executing JS. Benchmarks, especially on underpowered devices are yet to be performed.

Installation

$ npm install j2c

Please send a PR if you want to see it inclueded in other package systems.

Usage

For building a style sheet

j2c.vendors = [] // for the sake of this demo
                 // defaults to ["o", "ms", "moz", "webkit"].

r = j2c("ul.my_root_class")

r.add({
    "@media condition": {
        color: "red"
    },
    // properties for the main ul.my_root_class elements
    font: { 
        size: "2em",
        family: "sans-serif"
    },
    // underscores in property names are converted to dashes.
    background_color: "#44f", 

    // sub-selector for children element, notice the mandatory initial space
    // signifying a child element.
    " li": { 
        padding:{
            left: "5px"
            top: "10px"
        },
        // convenient shortcut.
        border: {"left/right": {width: 2px}}
    }
})

console.log(r.toString())

Output (beautified):

@media condition {
  ul.my_root_class {
    color:red;
  }
}
ul.my_root_class  li {
  padding-left:5px;
  padding-top:10px;
  border-left-width:2px;
  border-right-width:2px;
}
ul.my_root_class {
  font-size:2em;
  font-family:sans-serif;
  background-color:#44f;
}
-vendor-prefixes

If you don't truncate the vendors list as I did in the example above, you'll get each property prefixed for each vendor.

Most of the resulting combinations don't make any sense (-moz-color FTW), and they are simply ignored by browsers. That's the price to pay for the small code size.

Alternatively, you can specify the prefixes by hand using the "/" operator where needed:

j2c.vendors = []
j2c("p").add({
  // Notice the trailing slash, required for the unprefixed property.
  "-o/-ms/-moz/-webkit/": {foo: "bar"},
  hello: "world"
}).toString()

Compiles to

p {
  -o-foo:bar;
  -ms-foo:bar;
  -moz-foo:bar;
  -webkit-foo:bar;
  foo:bar;
  hello:world;
}
root selector

If no root selector is provided, J2C creates one (a unique class).

r = j2c()
r.prefix // --> ".j2c_$token_$counter" where `$token` is unique per
         //     j2c instance, and `$counter` is incremented to 
         //     ensure that these classes are unique.
Telling selectors and properties apart

j2c considers that object keys matching /^[-_0-9A-Za-z\/]+$/ as properties, and everything else as (sub-)selectors.

Selectors are concatenated as is, while properties are concatenated with hyphens. {" ul": {" li": {padding: {left:10}}}} becomes ul li{padding-left:10px;}. {" p":{".foo":{color:"red"}}}, is translated to p.foo:{color:red;}.

Overloading properties
r = j2c("ul.my_root_class")

r.add({
    "font-size": ["2em", "2rem"]
})

console.log(r.toString())

becomes

.foo {
  font-size:2em;
  font-size:2rem;
}

Alternatively

r = j2c("ul.my_root_class")

r.add([
    {
        "font-size": "2em"
    },
    {
        "font-size": "2rem"
    }
])

console.log(r.toString())

becomes

ul.my_root_class {
  font-size:2em;
}
ul.my_root_class {
  font-size:2rem;
}
At-rules

Most At-rules are handled out of the box by sheet.add(). However, @font-face and @keyframes have are not covered and they are implemented respectively by sheet.font(definitions) and sheet.keyframes(name, definitions). The latter automatically generates browser-specific @-vendor-keyframes blocks.

Combining multiple selectors

Here's a excerpt from the j2c port of the PocketGrid.

j2c("").add({
  ".block,.blockgroup":{
    ",:before,:after":{          // Notice the initial coma.
      "box-sizing":"border-box"
    }
  }
}

Nesting ",:before,:after" inside the ".block,.blockgroup" block combines [".block", ".blockgroup"] with ["", ":before", ":after"], giving

.block,.block:before,.block:after,.blockgroup,.blockgroup:before,.blockgroup:after{
    box-sizing:border-box
}

Mathy folks call this as a Cartesian product.

CSS Hacks

Since sheet.add only accepts property names that match /^[-_0-9A-Za-z]+$/, it is not possible to express CSS hacks using objects. You can, however, work around the issue by using arrays and strings instead.

Here's another modified excerpt from the PocketGrid port:

j2c("").add({
  ".blockgroup": [
    "*zoom: 1; /* hack */",
    {
      "list-style-type":"none",
      padding:0,
      margin:0
    }
  ]
})

Array elements are inserted in sequence, and string literals are treated as a list of properties, and inserted as is.

Result:

.blockgroup{
*zoom: 1; /* hack */
}
.blockgroup{
  list-style-type:none;
  padding:0;
  margin:0;
}

You can also pass th result of j2c.inline which is less picky about property names.

For building inline styles

Here's an example that demonstrates most of the j2c.inline capabilities:

j2c.vendors = []
j2c.inline({
  background_image: "url(bg.png)",
  border: {
    color: ["#33e", "rgba(64,64,255,0.8)"],
    "top/left": {width: "1px"},
  }
  color: ,
  font: {
    size: "2em",
    weight: 700
  },
  "*zoom": 1
})

Result (paired items are guaranteed to appear in order):

background-image: url(bg.png);

border-color: #33e;
border-color: rgba(64,64,255,0.8);

border-top-width: 1px;
border-left-width: 1px;

font-size: 2em;

font-weight: 700;

*zoom: 1;

If order is iportant, use Arrays:

j2c.inline([
  "margin:0",
  {
    margin_left:{
      width: "2px",
      color: "red"
    }
  }
])

Becomes

margin: 0;

// the above is guaranteed to occur before the next two

margin-left-color:red;
margin-left-width:2px;

Also, provided the vendors list isn't empty, each property ends up prefixed by each vendor.

console.log(j2c.inline({
    float:"left";
}));

... outputs ...

-o-float:left;
-ms-float:left;
-moz-float:left;
-webkit-float:left;
float:left;

API Reference

j2c and static fields

  • j2c([root:String]) : Sheet: Creates a Sheet object.
  • j2c.inline(props:(Object|Array|String)) : String: returns a declaration list suitable for inline styles
  • j2c.vendors = ["o", "ms", "moz", "webkit"] (r/w): list of vendor prefixes.

Sheet methods

  • sheet.add(statements:(Object|Array|String)) : Sheet: add a series of statements to the style sheet. Returns the Sheet for chaining.
  • sheet.font(definitions:(Object|Array|String)) : Sheet: creates a @font-face block. Returns the Sheet for chaining.
  • sheet.keyframes(name:String, statements:(Object|Array|String)) : Sheet: creates a @keyframes block. Returns the Sheet for chaining.
  • sheet.toString() : String: the stylesheet in string form.

Limitations

Selectors and properties order

j2c relies on JS objects to define selectors and properties. As a consequence, the source order cannot be guaranteed to be respected in the output.

j2c(".hello").add({
  foo:"bar",
  baz:"qux"
}).toString()

This may produce either .hello{foo:bar;baz:qux;} or .hello{baz:qux;foo:bar;}.

If you need some elements to happen in order, use an array of objects.

j2c(".hello").add([
  {foo:"bar"},
  {baz:"qux"}
]).toString()

This will always yield .hello{foo:bar;}.hello{baz:qux;}.

No input validation

j2c knows the bare minimum to output a valid stylesheet when provided with valid input. It will hapily accept invalid selectors, properties and values, and could in that case produce a broken stylesheet.

I may get around and write a validator companion, but I'm not there yet :-).

No pretty printing

For debugging purposes, I recommend that you pipe j2c's output through a be-au-ti-fier

License: MIT

Keywords

FAQs

Package last updated on 22 Apr 2015

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc