├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── babel.config.js ├── dist ├── index.js └── utils │ ├── CSSProperty.js │ ├── CSSPropertyOperations.js │ ├── dangerousStyleValue.js │ ├── fbjs.js │ └── index.js ├── lib ├── __tests__ │ ├── fixtures.js │ ├── lib.test.js │ └── utils.test.js ├── index.js └── utils │ ├── CSSProperty.js │ ├── CSSPropertyOperations.js │ ├── dangerousStyleValue.js │ ├── fbjs.js │ └── index.js ├── package-lock.json ├── package.json └── stilr.d.ts /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "browser": true, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "parserOptions": { 9 | "ecmaVersion": 6, 10 | "sourceType": "module" 11 | }, 12 | "extends": "eslint:recommended", 13 | "rules": { 14 | "quotes": [2, "single"], 15 | "strict": [2, "never"], 16 | "curly": [0], 17 | "no-underscore-dangle": [0], 18 | "prefer-const": [2] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | .tern* 5 | dist/__tests__ 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/__tests__ 2 | lib/__tests__ 3 | dist/__tests__ 4 | example 5 | .tern* 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'node' 4 | - '6' 5 | - '5' 6 | - '4' 7 | script: make build 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | > **Tags:** 4 | > - [New Feature] 5 | > - [Bug Fix] 6 | > - [Breaking Change] 7 | > - [Documentation] 8 | > - [Internal] 9 | > - [Polish] 10 | 11 | _Note: Gaps between patch versions are faulty/broken releases._ 12 | 13 | ## 1.2.1 14 | * Feature 15 | * Exposes the Map class that's used internally to create 16 | stylesheet. 17 | Usage: `import Stylesheet from 'stilr'` `Stylesheet.Map` 18 | * Bug 19 | * Fixed stylesheet instanceof check 20 | 21 | ## 1.1.0 22 | * __Internal__ 23 | * Added babel-runtime as a dependency. 24 | 25 | ## 1.0.0 26 | __Yeah, 1.0.0!__ 27 | The Api have been solidified, It's used in production, there's good test 28 | coverage, let's :shipit: ! 29 | 30 | * __Feature__ 31 | * It's now possible to use pseudo selectors inside media queries. 32 | 33 | ## 0.3.0 34 | * __Internal__ 35 | * Media queries are now inserted after normal CSS 36 | * Null and empty classes are now removed from rendered CSS 37 | 38 | ## 0.2.2 39 | * __Bug Fix__ 40 | * Media queries are now inserted after parent entry. Thanks @MicheleBertoli 41 | ! 42 | * New entries in existing media queries don't overwrite existing entries 43 | 44 | ## 0.2.0 45 | 46 | * **Internal** 47 | * Implemented extentedToString, now we have even shorter class names! 48 | 49 | ## 0.1.0 50 | 51 | * **Internal** 52 | * createHash was split into 3 helpers. `createHash`, `stringifyObject`, `createClassName` 53 | * Optimized stringifyObject. 54 | * renamed normalizeObj to sortObject. 55 | 56 | 57 | ## 0.0.1 58 | 59 | * Initial Release 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-present Kodyl ApS 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN = ./node_modules/.bin 2 | PATH := $(BIN):$(PATH) 3 | LIB = $(shell find lib -name "*.js") 4 | DIST = $(patsubst lib/%.js,dist/%.js,$(LIB)) 5 | 6 | MOCHA_ARGS = --require mocha-clean 7 | 8 | MOCHA_DEV = $(MOCHA_ARGS) \ 9 | --require @babel/polyfill \ 10 | --compilers js:@babel/register \ 11 | ./lib/__tests__/*.test.js 12 | 13 | MOCHA_DIST = $(MOCHA_ARGS) \ 14 | ./dist/__tests__/*.test.js 15 | 16 | define release 17 | VERSION=`node -pe "require('./package.json').version"` && \ 18 | NEXT_VERSION=`node -pe "require('semver').inc(\"$$VERSION\", '$(1)')"` && \ 19 | git flow release start $$NEXT_VERSION && \ 20 | make build && \ 21 | npm --no-git-tag-version version $(1) -m 'release %s' && \ 22 | git add . && \ 23 | git commit -m 'make build and release' && \ 24 | git flow release finish -m $$NEXT_VERSION $$NEXT_VERSION 25 | endef 26 | 27 | dist: $(DIST) 28 | dist/%.js: lib/%.js 29 | @echo "Building $<" 30 | @mkdir -p $(@D) 31 | @$(BIN)/babel $< -o $@ 32 | 33 | clean: 34 | @echo "\nRemove existing build files..." 35 | @rm -rf ./dist 36 | 37 | link: 38 | @npm link 39 | 40 | lint: 41 | @echo "\nLinting source files..." 42 | @$(BIN)/eslint lib/ 43 | 44 | test: 45 | @echo "\nTesting source files, hang on..." 46 | @$(BIN)/mocha $(MOCHA_DEV) 47 | 48 | test-watch: 49 | @echo "\nStarting test watcher..." 50 | @$(BIN)/mocha $(MOCHA_DEV) --watch 51 | 52 | test-dist: 53 | @echo "\nTesting build files, almost there..!" 54 | @$(BIN)/mocha $(MOCHA_DIST) 55 | 56 | build: lint test clean dist test-dist 57 | 58 | build-local: build link 59 | 60 | release-patch: 61 | $(call release,patch) 62 | 63 | release-minor: 64 | $(call release,minor) 65 | 66 | release-major: 67 | $(call release,major) 68 | 69 | .PHONY: \ 70 | build \ 71 | build-local \ 72 | install \ 73 | link \ 74 | release-major \ 75 | release-minor \ 76 | release-patch \ 77 | test \ 78 | test-dist \ 79 | test-watch \ 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stilr [![Build Status](https://travis-ci.org/kodyl/stilr.svg)](https://travis-ci.org/kodyl/stilr) [![npm version](https://badge.fury.io/js/stilr.svg)](http://badge.fury.io/js/stilr) 2 | 3 | Encapsulated styling for your javascript components with all the power of 4 | javascript and CSS combined. 5 | 6 | - Unique class names (Content Hash Based) 7 | - Useable on the server 8 | - Allows nested pseudo selectors 9 | - Allows nested media queries 10 | - No namespacing / Class name collisions. 11 | - Plays nicely with React Hot Loader and autoprefixer. 12 | 13 | ...oh, and did I mention you get duplicate style elimination for free? 14 | 15 | __Note__: This library fits really nice with [React](https://facebook.github.io/react/) but should work with other libraries like [Angular 2](https://angular.io/) or [Deku](https://github.com/dekujs/deku) 16 | 17 | ## API 18 | 19 | #### `object StyleSheet.create(object spec)` 20 | Stilr extracts the styles from the style object and returns an object with the 21 | same keys mapped to class names. 22 | 23 | __Example__ 24 | ```javascript 25 | import StyleSheet from 'stilr'; 26 | 27 | const palm = '@media screen and (max-width:600px)'; 28 | 29 | const styles = StyleSheet.create({ 30 | container: { 31 | color: '#fff', 32 | ':hover': { // Pseudo Selectors are allowed 33 | color: '#000' 34 | }, 35 | [palm]: { // Media Queries are allowed 36 | fontSize: 16, 37 | ':hover': { 38 | color: 'blue' // Pseudo selectors inside media queries. 39 | } 40 | } 41 | } 42 | }); 43 | 44 | console.log(styles.container); // => '_xsrhhm' -- (The class name for this style.) 45 | ``` 46 | 47 | #### `string StyleSheet.render()` 48 | Stilr outputs the contents of its internal stylesheet as a string of css 49 | 50 | __Example__ 51 | ```javascript 52 | import StyleSheet from 'stilr'; 53 | 54 | StyleSheet.create({ 55 | container: { 56 | color: '#fff' 57 | } 58 | }); 59 | 60 | const CSS = StyleSheet.render(); 61 | 62 | console.log(CSS); // => '._yiw79c{color:#fff;}' 63 | ``` 64 | 65 | #### `bool StyleSheet.clear()` 66 | Clear Stilr internal stylesheet 67 | 68 | __Example__ 69 | ```javascript 70 | import StyleSheet from 'stilr'; 71 | 72 | const styles = StyleSheet.create({ 73 | container: { 74 | color: '#fff' 75 | } 76 | }); 77 | 78 | StyleSheet.clear(); 79 | 80 | const CSS = StyleSheet.render(); 81 | 82 | console.log(CSS); // => '' 83 | ``` 84 | 85 | 86 | ## Examples 87 | 88 | #### Basic Button Component Example. 89 | Let's start of by creating our styles. If you have ever used React Native, this 90 | will be familiar to you: 91 | 92 | ```javascript 93 | import StyleSheet from 'stilr'; 94 | import { palm } from './breakpoints'; 95 | import { color, font } from './theme'; 96 | 97 | const styles = StyleSheet.create({ 98 | base: { 99 | transition: 'background-color .25s', 100 | borderRadius: 2, 101 | textAlign: 'center', 102 | fontSize: 20, 103 | padding: 6, 104 | color: '#fff', 105 | border: `${ color.border } 1px solid`, 106 | [palm]: { 107 | fontSize: 18 108 | } 109 | }, 110 | primary: { 111 | backgroundColor: color.primary, 112 | ':hover': { 113 | color: 'tomato' 114 | } 115 | }, 116 | secondary: { 117 | backgroundColor: 'tomato', 118 | color: '#eee' 119 | } 120 | }); 121 | ``` 122 | 123 | Stilr will now generate a set of class names based on the content of your styles 124 | and return an object with the same keys mapped to those classes. 125 | 126 | Note that you're able to use pseudo selectors and media queries. 127 | Pseudo selectors are written like you normally would in CSS, e.g.: `:hover`, `:active`, 128 | `:before` etc. 129 | Media queries are the same, e.g. `palm` in the example is just a string: `@media screen and (max-width:600px)`. Any valid media query is allowed. 130 | 131 | Since we just have a bunch of class names now, we can use these in our React 132 | Component. 133 | 134 | ```javascript 135 | import React, { PropTypes } from 'react'; 136 | 137 | class Button extends React.Component { 138 | static propTypes = { 139 | type: PropTypes.oneOf(['primary', 'secondary']) 140 | } 141 | 142 | render() { 143 | const { type, children } = this.props; 144 | const buttonStyles = [ 145 | styles.base, 146 | styles[ type ] 147 | ].join(' '); 148 | 149 | return ( 150 | 153 | ); 154 | } 155 | ``` 156 | 157 | Next up, let's render our css and mount our app: 158 | 159 | ```javascript 160 | import React from 'react'; 161 | import Button from './button'; 162 | import StyleSheet from 'stilr'; 163 | 164 | React.render( 165 |