react-bem-helper
Advanced tools
Comparing version 1.0.0 to 1.1.0
22
index.js
@@ -16,4 +16,4 @@ function isObject(obj) { | ||
function objectToArray(object) { | ||
var keys = Object.keys(object), | ||
output = []; | ||
var keys = Object.keys(object); | ||
var output = []; | ||
@@ -52,7 +52,17 @@ keys.forEach(function(key) { | ||
return function(element, modifiers, extraClassNames) { | ||
var blockName = options.name, | ||
rootName = blockName, | ||
classNames = []; | ||
return function(first, modifiers, extraClassNames) { | ||
var blockName = options.name; | ||
var rootName = blockName; | ||
var classNames = []; | ||
var element; | ||
// This means the first parameter is not the element, but a configuration variable | ||
if (isObject(first)) { | ||
element = first.element; | ||
modifiers = first.modifiers || first.modifier; | ||
extraClassNames = first.extra; | ||
} else { | ||
element = first; | ||
} | ||
if (element) { | ||
@@ -59,0 +69,0 @@ rootName += '__' + element; |
{ | ||
"name": "react-bem-helper", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "allows you to easily add BEM-style element and modifier classes to React elements, while hopefully making it easier to scan.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "jasmine", | ||
"lint": "eslint ." | ||
"test": "jasmine" | ||
}, | ||
@@ -13,4 +12,3 @@ "author": "Marco Hamersma", | ||
"devDependencies": { | ||
"jasmine": "^2.2.1", | ||
"eslint": "^0.20.0" | ||
"jasmine": "^2.2.1" | ||
}, | ||
@@ -26,3 +24,4 @@ "repository": { | ||
"modifier", | ||
"classes" | ||
"classes", | ||
"react-component" | ||
], | ||
@@ -29,0 +28,0 @@ "bugs": { |
186
readme.md
# React BEM helper | ||
… is an NPM module making it easier to name React.js components according to [BEM conventions](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/). It removes the repetition from writing the component name multiple times for elements and elements with modifier classes on them. | ||
[](http://badge.fury.io/js/react-bem-helper) | ||
A helper making it easier to name React.js components according to [BEM conventions](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/). It removes the repetition from writing the component name multiple times for elements and elements with modifier classes on them. | ||
## Why? | ||
@@ -19,12 +21,12 @@ I found myself writing code like this a lot in my React components: | ||
```scss | ||
.c-componentName { | ||
background: red; | ||
.c-componentName { | ||
background: red; | ||
&__button { | ||
text-transform: uppercase; | ||
&__button { | ||
text-transform: uppercase; | ||
&--left { float: left; } | ||
&--right { float: right; } | ||
} | ||
&--left { float: left; } | ||
&--right { float: right; } | ||
} | ||
} | ||
``` | ||
@@ -35,3 +37,3 @@ | ||
## How does it work? | ||
A new helper is initialized with a an options object or a string representing the name of the component (`componentName`) in this example. The instantiated helper receives up to three arguments (element, modifiers, extra classes). When called, it generates a simple object with props that should be applied to the DOM element. | ||
A new helper instance is created with a an options object or a string representing the name of the component (`componentName`) in this example. The instantiated helper receives up to three arguments (element, modifiers, extra classes). When called, it generates a simple object with props that should be applied to the DOM element, for example ` { classNames: 'componentName' }`. If you want, a prefix like `c-` can be automatically added by supplying an [options object](#preparing-the-helper). | ||
@@ -41,17 +43,21 @@ You can use the spread operator (`{...object}`) to apply the classes to the DOM element. Even though this is an ES6 feature, React compiles this to it's own ES5 compatible version. | ||
## Example | ||
Here's how you would return the example's HTML structure when using the helper. | ||
Here's how you would return [the example HTML structure](#why) when using the helper. | ||
```js | ||
var React = require('react'), | ||
BEMHelper = require('react-bem-helper'), | ||
bemHelper = new BEMHelper('componentName'); | ||
var React = require('react'); | ||
var BEMHelper = require('react-bem-helper'); | ||
module.exports = React.createClass({ | ||
render: function() { | ||
var classes = new BEMHelper({ | ||
name: 'componentName', | ||
prefix: 'c-' | ||
}); | ||
return ( | ||
<div {...bemHelper()}> | ||
<div {...bemHelper('inner')}> | ||
<div {...classes()}> | ||
<div {...classes('inner')}> | ||
Some test | ||
<button {...bemHelper('button', 'left')}>Button</button> | ||
<button {...bemHelper('button', 'right')}>Button</button> | ||
<button {...classes('button', 'left')}>Button</button> | ||
<button {...classes('button', 'right')}>Button</button> | ||
</div> | ||
@@ -64,2 +70,18 @@ </div> | ||
For optimization reasons, you might want to move `new BEMHelper` out of the render function. On occasions I've done something like this: | ||
```js | ||
… | ||
module.exports = React.createClass({ | ||
bemHelper: new BEMHelper('componentName'), | ||
render: function() { | ||
var classes = this.bemHelper; | ||
return ( | ||
<div {...classes()}> | ||
… | ||
) | ||
} | ||
}) | ||
``` | ||
## Usage | ||
@@ -72,13 +94,9 @@ ### Installation | ||
**by default, a prefix `c-` is added to the block class**, this can be changed by passing an options object with a `prefix` key: | ||
```javascript | ||
var BEMhelper = require('react-bem-helper'); | ||
// Passing an options object while clearing the prefix | ||
var bemHelper = new BEMHelper({ | ||
name: 'componentName', | ||
prefix: null | ||
}); | ||
// Make 'componentName' the base name | ||
var bemHelper = new BEMHelper('componentName') | ||
// Passing an options object with a custom prefix | ||
// Or pass an options object with a prefix to be applied to all components | ||
var bemHelper2 = new BEMHelper({ | ||
@@ -91,21 +109,60 @@ name: 'componentName', | ||
### Using the helper | ||
When executed, the helper returns an object with a `className` property. When the helper was called without any arguments, it's value will consist of the block name and a prefix: | ||
When executed, the helper returns an object with a `className` property. When the helper is called without any arguments, its value will consist of the block name and a prefix: | ||
```js | ||
var BEMHelper = require('react-bem-helper'), | ||
bemHelper = new BEMHelper('componentName'); | ||
var React = require('react'), | ||
BEMHelper = require('react-bem-helper'); | ||
bemHelper(); // returns { className: 'c-componentName' } | ||
module.exports = React.createClass({ | ||
render: function() { | ||
var classes = new BEMHelper('componentName'); | ||
return ( | ||
<div {...classes('element', 'modifier', 'extra')} /> | ||
); | ||
// Returns <div className='componentName__element componentName__element--modifier extra'/> | ||
} | ||
}); | ||
``` | ||
The bemHelper supports up to three arguments: element, modifiers, and extra classes: | ||
The bemHelper supports up to three arguments: `element`, `modifiers`, and `extra` classes, although _an object containing any of these parameters is also supported:_ | ||
#### Alternate Syntax | ||
```js | ||
var React = require('react'), | ||
BEMHelper = require('react-bem-helper'); | ||
module.exports = React.createClass({ | ||
render: function() { | ||
var classes = new BEMHelper('componentName'); | ||
var options = { | ||
element: 'element', | ||
modifiers: 'modifier', | ||
extra: 'extra' | ||
}; | ||
return ( | ||
<div {...classes(options)} /> | ||
); | ||
// Returns <div className='componentName__element componentName__element--modifier extra'/> | ||
} | ||
}); | ||
``` | ||
#### Element | ||
To generate a class like `c-componentName__header`, pass `"header"` as the first argument to the bemHelper: | ||
To generate a class like `componentName__header`, pass `"header"` as the first argument to the bemHelper: | ||
```js | ||
bemHelper('header'); // returns { className: 'c-componentName__header' } | ||
var BEMHelper = require('react-bem-helper'); | ||
var bemHelper = new BEMHelper('componentName'); | ||
bemHelper('header'); // returns { className: 'componentName__header' } | ||
``` | ||
The element argument only supports strings. | ||
The element argument only supports strings, but a configuration object replacing the element, modifiers and 'extra' paramers can be passed instead: | ||
```js | ||
bemHelper({ element: 'header' }); // returns { className: 'componentName__header' } | ||
``` | ||
#### Modifiers | ||
@@ -115,20 +172,31 @@ Modifiers can be added as a `String`, `Array`, or `Object`. For every modifier an additional class is generated, based upon either the block name or element name: | ||
```js | ||
bemHelper(null, 'active'); | ||
// { className: 'c-componentName--active'} | ||
var BEMHelper = require('react-bem-helper'); | ||
var bemHelper = new BEMHelper('componentName'); | ||
bemHelper('lol', 'active'); | ||
// { className: 'c-componentName__lol--active'} | ||
bemHelper('lol', ['active', 'funny']); | ||
// { className: 'c-componentName__lol c-componentName__lol--active c-componentName__lol--funny'} | ||
bemHelper(null, 'active'); | ||
// { className: 'componentName--active'} | ||
bemHelper('lol', { | ||
active: true, | ||
funny: false, | ||
playing: function() { return false;} | ||
}); | ||
// { className: 'c-componentName__lol--active'} | ||
bemHelper('lol', 'active'); | ||
// { className: 'componentName__lol--active'} | ||
bemHelper('lol', ['active', 'funny']); | ||
// { className: 'componentName__lol componentName__lol--active componentName__lol--funny'} | ||
bemHelper('lol', { | ||
active: true, | ||
funny: false, | ||
playing: function() { return false;} | ||
}); | ||
// { className: 'componentName__lol--active'} | ||
``` | ||
If you pass an object as the modifiers argument, the helper will add the keys as classes for which their corresponding values are true. If a function is passed as a value, this function is executed. | ||
If you're not using arguments, but a configuration object, add modifiers by adding a `modifier` or `modifiers` property to the configuration object: | ||
```js | ||
bemHelper({ modifiers: 'active' }); // returns { className: 'componentName--active' } | ||
``` | ||
As when using arguments, this syntax also supports arrays and objects as different ways of defining modifiers. | ||
#### Extra classes | ||
@@ -138,12 +206,24 @@ This argument allows you to do add extra classes to the element. Like the modifiers, extra classes can be added as a `String`, `Array`, or `Object`. The behaviour is the same, except that the classes are added as passed, and no prefix or block name is added. | ||
```js | ||
bemHelper('', '', ['one', 'two']); | ||
// { className: 'c-componentName one two'} | ||
bemHelper('', '', { | ||
active: true, | ||
funny: false, | ||
playing: function() { return false;} | ||
}); | ||
// { className: 'c-componentName active'} | ||
var BEMHelper = require('react-bem-helper'); | ||
var bemHelper = new BEMHelper('componentName'); | ||
bemHelper('', '', ['one', 'two']); | ||
// { className: 'componentName one two'} | ||
bemHelper('', '', { | ||
active: true, | ||
funny: false, | ||
playing: function() { return false;} | ||
}); | ||
// { className: 'componentName active'} | ||
``` | ||
If you're not using arguments, but a configuration object, add extra classes by adding a `extra` property to the configuration object: | ||
```js | ||
bemHelper({ extra: ['one', 'two'] }); // { className: 'componentName one two'} | ||
``` | ||
As when using arguments, this syntax also supports arrays and objects as different ways of defining extra classes. | ||
## License | ||
@@ -150,0 +230,0 @@ MIT License |
41
tests.js
@@ -42,2 +42,40 @@ /*global it, describe, expect */ | ||
describe('when using object as arguments', function() { | ||
it ('should return className for the block when empty object given', function() { | ||
expect(bemhelper({})).toEqual(resultWithClassName('block')); | ||
}); | ||
it('should return className for the element when element is given', function() { | ||
expect(bemhelper({ | ||
element: 'element' | ||
})).toEqual(resultWithClassName('block__element')); | ||
}); | ||
it('should return classNames for the block and modifier when modifier given', function() { | ||
expect(bemhelper({ | ||
modifier: 'modifier' | ||
})).toEqual(resultWithClassName('block block--modifier')); | ||
}); | ||
it('should return classNames for the block and modifier when modifier given as object', function() { | ||
expect(bemhelper({ | ||
modifiers: { 'modifier': true } | ||
})).toEqual(resultWithClassName('block block--modifier')); | ||
}); | ||
it('should return classNames for the element and the modifier when a modifier is given', function() { | ||
expect(bemhelper({ | ||
element: 'element', | ||
modifier: 'modifier' | ||
})).toEqual(resultWithClassName('block__element block__element--modifier')); | ||
}); | ||
it('should return classNames for the element and the modifier when a modifier is given', function() { | ||
expect(bemhelper({ | ||
element: 'element', | ||
modifier: 'modifier' | ||
})).toEqual(resultWithClassName('block__element block__element--modifier')); | ||
}); | ||
}); | ||
describe(', when given multiple modifiers', function() { | ||
@@ -60,2 +98,3 @@ it('as an array, should return classNames for the element and each modifier given', function() { | ||
expect(bemhelper(null, modifiers)).toEqual(resultWithClassName('block block--two block--five')); | ||
expect(bemhelper({ modifiers: modifiers })).toEqual(resultWithClassName('block block--two block--five')); | ||
}); | ||
@@ -69,2 +108,3 @@ }); | ||
expect(bemhelper('element', '', extraClasses)).toEqual(resultWithClassName('block__element one two')); | ||
expect(bemhelper({ extra: extraClasses })).toEqual(resultWithClassName('block one two')); | ||
}); | ||
@@ -80,2 +120,3 @@ | ||
expect(bemhelper('', '', extraClasses)).toEqual(resultWithClassName('block two')); | ||
expect(bemhelper({ extra: extraClasses })).toEqual(resultWithClassName('block two')); | ||
}); | ||
@@ -82,0 +123,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
69780
1
11
193
225