├── .travis.yml ├── .npmignore ├── .gitignore ├── index.js ├── tests ├── atomize.test.js └── lib │ └── AtomicStyler.test.js ├── package.json ├── LICENSE ├── lib └── AtomicStyler.js └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - iojs 4 | - '0.12' 5 | - '0.11' 6 | - '0.10' 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | artifacts/ 3 | **/npm-debug.log 4 | .DS_Store 5 | *~ 6 | test/ 7 | tests/ 8 | docs/ 9 | examples/ 10 | Makefile 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | artifacts/ 3 | node_modules/ 4 | **/npm-debug.log 5 | tmp/ 6 | CVS/ 7 | .DS_Store 8 | .*.swp 9 | .svn 10 | *~ 11 | .com.apple.timemachine.supported 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015, Yahoo Inc. 3 | * Copyrights licensed under the MIT License. 4 | * See the accompanying LICENSE file for terms. 5 | */ 6 | 'use strict'; 7 | 8 | var AtomicStyler = require('./lib/AtomicStyler'); 9 | 10 | module.exports = new AtomicStyler(); 11 | -------------------------------------------------------------------------------- /tests/atomize.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe, it */ 2 | 3 | 'use strict'; 4 | 5 | var atomize = require('../index'); 6 | var AtomicStyler = require('../lib/AtomicStyler'); 7 | var assert = require('assert'); 8 | 9 | describe('atomize', function () { 10 | it('is a singlethon instance of AtomicStyler', function () { 11 | assert(AtomicStyler.prototype.isPrototypeOf(atomize)); 12 | }); 13 | 14 | it('starts with a empty list of styles', function () { 15 | assert.deepEqual(atomize._styles, {}); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atomic-style", 3 | "version": "0.3.2", 4 | "description": "Atomic classSets and dedupe", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "scripts": { 8 | "cover": "COVERAGE=true jenkins-mocha tests/**/*.test.js", 9 | "test": "jenkins-mocha --no-coverage tests/**/*.test.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/yahoo/atomic-style.git" 14 | }, 15 | "keywords": [ 16 | "atomic", 17 | "style", 18 | "atomizer", 19 | "css", 20 | "styles" 21 | ], 22 | "bugs": { 23 | "url": "https://github.com/yahoo/jsx-test/issues" 24 | }, 25 | "author": "Marcelo Eden", 26 | "homepage": "https://github.com/yahoo/atomic-style", 27 | "dependencies": { 28 | "lodash": "^4.0" 29 | }, 30 | "devDependencies": { 31 | "jenkins-mocha": "^2.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2015, Yahoo Inc. 4 | Author: Marcelo Eden 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/AtomicStyler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015, Yahoo Inc. 3 | * Copyrights licensed under the MIT License. 4 | * See the accompanying LICENSE file for terms. 5 | */ 6 | 'use strict'; 7 | 8 | var SPLIT_REGEX = /\s+/g; 9 | var VALUE_REGEX = /\(.+\)/; 10 | 11 | var _ = { 12 | assign: require('lodash/assign') 13 | }; 14 | 15 | function AtomicStyler(styles) { 16 | this._styles = {}; 17 | styles && this.set(styles); 18 | } 19 | 20 | function classesFromObject(obj) { 21 | var classNames = ''; 22 | var key; 23 | 24 | for (key in obj) { 25 | if (obj.hasOwnProperty(key) && obj[key]) { 26 | classNames += ' ' + key; 27 | } 28 | } 29 | 30 | return classNames; 31 | } 32 | 33 | function sanitizeArray(classes) { 34 | if (!classes) { 35 | return []; 36 | } 37 | 38 | if (Array.isArray(classes)) { 39 | classes = classes.join(' '); 40 | } 41 | 42 | if (typeof classes === 'object') { 43 | classes = classesFromObject(classes); 44 | } 45 | 46 | return classes.trim().split(SPLIT_REGEX); 47 | } 48 | 49 | function _reduceClassSet(result, className) { 50 | result[className.replace(VALUE_REGEX, '')] = className; 51 | return result; 52 | } 53 | 54 | function buildClassSet(classes) { 55 | return sanitizeArray(classes).reduce(_reduceClassSet, {}); 56 | } 57 | 58 | function getClassNames(styles) { 59 | return Object.keys(styles).map(function (key) { 60 | return styles[key]; 61 | }).join(' '); 62 | } 63 | 64 | function set(styles) { 65 | if (Array.isArray(styles)) { 66 | return styles.forEach(set, this); 67 | } 68 | 69 | Object.keys(styles).forEach(function(key) { 70 | this._styles[key] = _.assign( 71 | this._styles[key] || {}, 72 | buildClassSet(styles[key]) 73 | ); 74 | }, this); 75 | } 76 | 77 | function get(styles, overrides) { 78 | var classes = {}; 79 | 80 | sanitizeArray(styles).forEach(function(key) { 81 | _.assign(classes, this._styles[key]); 82 | }, this); 83 | 84 | overrides && _.assign(classes, buildClassSet(overrides)); 85 | return getClassNames(classes); 86 | } 87 | 88 | function mergeStyles(result, style) { 89 | return _.assign(result, buildClassSet(style)); 90 | } 91 | 92 | function dedupe() { 93 | return getClassNames([].reduce.call(arguments, mergeStyles, {})); 94 | } 95 | 96 | AtomicStyler.prototype = { 97 | set: set, 98 | get: get, 99 | dedupe: dedupe 100 | }; 101 | 102 | module.exports = AtomicStyler; 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AtomicStyle 2 | 3 | This lib provides atomic classSets and dedupes atomic classes, it is an Atomizer friendly replacement for the [classNames](https://github.com/JedWatson/classnames) module. 4 | 5 | The atomic style class sets helps to remove duplication when there are many components repeating the same style over and over but it should not be overused the Atomic prefered way it to have reusable components with explicit atomic classes, the dedupe feature provided by this lib is very usefull for that. 6 | 7 | ## Install 8 | 9 | ``` 10 | npm install --save atomic-style 11 | ``` 12 | 13 | ## How To Use? 14 | 15 | Create some classSets to group atomic styles that are duplicated on your app. 16 | 17 | ```js 18 | // config/styles/btn.json 19 | // the AtomicStyle is a simple object where the keys is the style name, 20 | // and the values can be eather a string, object or array. 21 | { 22 | // you can use an Array 23 | 'btn': [ 24 | 'H(30px) Lh(30px)', 25 | 'Bgc(#ccc)', 26 | 'C(#000)', 27 | ... // more styles 28 | ], 29 | 30 | // you can use an String 31 | 'btn-blue': "Bgc(blue) C(#fff)", 32 | 33 | // or you can use an object 34 | 'btn-lg': { 35 | 'H(50px)': true, 36 | 'Lh(50px)': true 37 | } 38 | } 39 | ``` 40 | 41 | Create a config file that load your classes. 42 | 43 | ```js 44 | // config/atomize.js 45 | 'use strict'; 46 | 47 | // atomize-style return a singlethon object where all your styles will be merged 48 | var atomize = require('atomic-style'); 49 | 50 | atomize.set([ 51 | require('./styles/btn.json'), 52 | require('./styles/foobar.json'), 53 | ... // all other styles 54 | ]); 55 | 56 | module.exports = atomize; 57 | ``` 58 | 59 | Now you can use your config/atomize to get classSets and dedupe stuff. 60 | 61 | ```jsx 62 | // components/SomeComponent.jsx 63 | var atomize = require('../config/atomize'); 64 | 65 | module.exports = React.createClass({ 66 | displayName: 'SomeComponent', 67 | 68 | ... 69 | 70 | render: function () { 71 | // #dedupe can be used to merge classes 72 | var divClasses = atomize.dedupe('W(500px)', this.props.divClassName, { 73 | 'W(100%)': this.props.isFullScreen 74 | }); 75 | 76 | var customBtnClasses = atomize.get('btn btn-lg', { 77 | 'C(#fff) Bgc(pink)': this.props.hasPinkBtn 78 | }); 79 | 80 | return ( 81 |