Skip to content

Commit

Permalink
Rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
jxnblk committed Jul 22, 2017
1 parent 37d8157 commit 06a0e6e
Show file tree
Hide file tree
Showing 72 changed files with 470 additions and 3,079 deletions.
3 changes: 1 addition & 2 deletions .babelrc
@@ -1,7 +1,6 @@
{
"presets": [
"es2015",
"stage-0",
"env",
"react"
]
}
4 changes: 2 additions & 2 deletions .gitignore
@@ -1,3 +1,3 @@

coverage
.nyc_output
dist
example/bundle.js
7 changes: 4 additions & 3 deletions .npmignore
@@ -1,7 +1,8 @@

example
docs
src
test
test.js
.travis.yml
.babelrc
webpack.config.js
coverage
.nyc_output
224 changes: 78 additions & 146 deletions README.md
Expand Up @@ -4,20 +4,19 @@
[![Build Status](https://travis-ci.org/jxnblk/cxs.svg?branch=master)](https://travis-ci.org/jxnblk/cxs)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)

Functional CSS for functional UI components
High performance, lightweight CSS-in-JS

```js
const className = cxs({ color: 'tomato' })
const className = cxs(`color: tomato`)
```

CXS is a functional CSS-in-JS solution that uses atomic styles
to maximize deduplication and help with dead code elimination.
CXS is a minimal CSS-in-JS solution that uses
an API that closely follows the native CSSStyleSheet API
to maximize performance and reduce bloat.

## Features

- Three different [modes](#modes) of operation: Atomic, Lite, & Monolithic
- < 5KB
- Avoids collisions with atomic rulesets
- < 1.5KB
- Deduplicates repeated styles
- Dead-code elimination
- Framework independent
Expand All @@ -26,8 +25,7 @@ to maximize deduplication and help with dead code elimination.
- Pseudoclasses
- Nested selectors
- Avoid maintaining separate stylesheets
- Use plain JS objects and types
- No tagged template literals
- Use plain CSS strings

## Install

Expand All @@ -49,50 +47,38 @@ const Box = (props) => {
)
}

const className = cxs({
padding: 32,
backgroundColor: 'tomato'
})
const className = cxs(`
padding: 32px;
backgroundColor: tomato;
`)

export default Box
```

### Pseudoclasses

```js
cxs({
color: 'tomato',
':hover': {
color: 'red'
}
})
cxs('color: tomato')
.hover('color: red')
```

### Media Queries

```js
cxs({
color: 'tomato',
'@media (min-width: 40em)': {
color: 'red'
}
cxs('color: tomato')
.media('@media (min-width: 40em)', 'color: red')
})
```

### Nested Selectors

```js
cxs({
color: 'tomato',
h1: {
color: 'red'
}
})
cxs('color: tomato', ' > h1')
```

### Server-Side Rendering

To use CXS in server environments, use the `getCss()` function to get the static CSS string *after* rendering a view.
To use CXS in server environments, use the `css` getter to get the static CSS string *after* rendering a view.

```js
import React from 'react'
Expand All @@ -101,170 +87,116 @@ import cxs from 'cxs'
import App from './App'

const html = ReactDOMServer.renderToString(<App />)
const css = cxs.getCss()
const css = cxs.css

const doc = `<!DOCTYPE html>
<style>${css}</style>
${html}
`

// Optionally reset the cache for the next render
// Reset the cache for the next render
cxs.reset()

```

## Modes

CXS offers three different modes of operation, which produce different rules and class names.
## API

```js
import cxsAtomic from 'cxs'
import cxsMonolithic from 'cxs/monolithic'
import cxsLite from 'cxs/lite'

const styles = {
margin: 0,
marginBottom: 32,
padding: 16,
color: 'tomato',
':hover': {
color: 'orangered'
},
'@media (min-width: 40em)': {
padding: 32
}
}
const rule = cxs(cssDeclarations, descendantSelector, mediaQuery, className)
// cxsRuleObject

// Each mode returns a different set of class names
// className
rule.toString() // '_0'

cxsAtomic(styles)
// m-0 mb-32 p-16 c-tomato -hover-c-orangered _zsp35u
// The following methods all return a rule object,
// which allows them to be chained together

cxsMonolithic(styles)
// _q5nmba
// Adds a pseudoclass rule with the same className
rule.hover()
rule.focus()
rule.active()
rule.disabled()

cxsLite(styles)
// a b c d e f
```
// Adds a media query rule with the same className
rule.media(mediaQuery, cssDeclarations)

### Atomic Mode (Default)

```js
import cxs from 'cxs'
// Adds another rule with the same className
rule.push()
```

The default mode is the atomic mode.
This creates atomic rulesets and attempts to create human readable classnames.
If a classname is longer than 24 characters, a hashed classname will be used instead.

### Lite Mode

```js
import cxs from 'cxs/lite'
```
import cxs from 'cxs'

For super fast performance, use the `cxs/lite` module.
Lite mode creates alphabetic class names in a sequential order and does not support nested selectors.
// Creates styles and returns micro classnames
cxs('color: tomato')

Since the class names in cxs/lite are *not* created in a functional manner,
when using cxs/lite on both the server and client, the styles will need to be rehydrated.
// Gets a CSS string of attached rules. Useful for server-side rendering
cxs.css

```js
// Server
const css = cxs.getCss()
// Clear the cache and flush the stylesheet.
// This is useful for cleaning up in server-side contexts.
cxs.reset()

const html = `<!DOCTYPE html>
<style id='cxs-style'>${css}</style>
${body}
`
```

```js
// Client
import cxs from 'cxs/lite'

const styleTag = document.getElementById('cxs-style')
const serverCss = styleTag.innerHTML
Additional exports

cxs.rehydrate(serverCss)
```

### Monolithic Mode

```js
import cxs from 'cxs/monolithic'
import {
Sheet, // create stylesheet function
sheet, // cxs stylesheet instance
css, // string of rendered CSS - same as cxs.css
reset // same as cxs.reset
} from 'cxs'
```

To create encapsulated monolithic styles with CXS and use single hashed class names, import the monolithic module.
## React Components

The monolithic module also accepts custom selectors for styling things like the body element.
CXS also has a higher order component for creating styled React components, similar to [styled-components][0] API.

```js
cxs('body', {
fontFamily: '-apple-system, sans-serif',
margin: 0,
lineHeight: 1.5
})
```
import cxs from 'cxs/component'

## API

```js
import cxs from 'cxs'
const Heading = cxs(`
margin: 0;
font-size: 32px;
line-height: 1.25;
`).component('h1')
```

// Creates styles and returns micro classnames
cxs({ color: 'tomato' })
Unlike styled-components, CXS components can be composed with other higher order components and works seamlessly with libraries like [Recompose][1]

// Returns a CSS string of attached rules. Useful for server-side rendering
cxs.getCss()
## JS Objects

// Clear the cache and flush the glamor stylesheet.
// This is useful for cleaning up in server-side contexts.
cxs.reset()
```
T/K

Additional exports
```js
import cxs from 'cxs/object'

```
import {
// The threepointone/glamor StyleSheet instance
// See https://github.com/threepointone/glamor
sheet,
// Same as cxs.getCss
getCss,
// Same as cxs.reset
reset
} from 'cxs'
const style = cxs({
color: 'tomato'
})
```

### Vendor prefixes

CXS **does not** handle vendor prefixing to keep the module size at a minimum.
To add vendor prefixes, use a prefixing module like [`inline-style-prefixer`](https://github.com/rofrischmann/inline-style-prefixer)

```js
import cxs from 'cxs'
import prefixer from 'inline-style-prefixer/static'

const prefixed = prefixer({
display: 'flex'
})
const cx = cxs(prefixed)
```

### Browser support
<!--
```js
import cxs from 'cxs'
import prefixer from 'inline-style-prefixer/static'
IE9+, due to the following:
- `Array.filter`
- `Array.map`
- `Array.forEach`
const prefixed = prefixer({
display: 'flex'
})
const cx = cxs(prefixed)
```
-->

## Related

- [cxs-components](https://github.com/jxnblk/cxs/tree/master/packages/cxs-components)
- [react-cxs](https://github.com/jxnblk/cxs/tree/master/packages/react-cxs)
- [react-cxs-hoc](https://github.com/jxnblk/cxs/tree/master/packages/react-cxs-hoc)
[0]: https://www.styled-components.com (styled-components)
[1]: https://github.com/acdlite/recompose (Recompose)

[MIT License](LICENSE.md)

1 change: 0 additions & 1 deletion atomic.js

This file was deleted.

1 change: 1 addition & 0 deletions component.js
@@ -0,0 +1 @@
module.exports = require('./dist/component')
18 changes: 0 additions & 18 deletions example/App.js

This file was deleted.

0 comments on commit 06a0e6e

Please sign in to comment.