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

react-bem-helper

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-bem-helper - npm Package Compare versions

Comparing version 1.3.1 to 1.4.0

yarn.lock

146

index.d.ts

@@ -7,37 +7,129 @@ /**

interface BEMHelper {
(element?: string, modifiers?: BEMHelper.List, extra?: BEMHelper.List): {className: string};
(args: BEMHelper.Arguments): {className: string};
}
interface BEMHelper<TReturn extends (string | BEMHelper.ReturnObject)> extends
BEMHelper.HelperFunction<TReturn> { }
declare namespace BEMHelper {
interface PredicateList {
[key: string]: boolean | (() => boolean);
}
/**
* A mapping of strings to predicate functions or booleans.
*
* The values define whether the keys should be included in the list.
*/
interface PredicateSet {
[key: string]: boolean | (() => boolean);
}
type List = string | string[] | PredicateList;
/**
* Several ways to define a set of strings words.
*
* It can be:
* * A string of words separated by spaces.
* * An array of space-separated word strings.
* * A predicate set of space-separated word strings.
*/
type WordSet = string | string[] | PredicateSet;
interface Arguments {
element?: string;
modifier?: List;
modifiers?: List;
extra?: List;
}
interface ElementArguments {
/**
* The name of the BEM element.
*/
element?: string;
}
interface ConstructorOptions {
name: string;
prefix?: string;
modifierDelimiter?: string;
}
interface ModifierArguments extends ElementArguments {
/**
* A set of one or more modifiers.
*/
modifier?: WordSet;
interface Constructor {
new(name: string): BEMHelper;
new(options: ConstructorOptions): BEMHelper;
(name: string): BEMHelper;
(options: ConstructorOptions): BEMHelper;
}
/**
* A set of one or more modifiers.
*/
modifiers?: WordSet;
}
interface HelperArguments extends ModifierArguments {
/**
* A set of extra plain classes to add without BEM prefixing.
*/
extra?: WordSet;
}
interface ReturnObject {
className: string;
}
/**
* A function for creating BEM classes for a block.
*/
interface HelperFunction<TReturn extends (string | ReturnObject)> {
/**
* @param {?string} element The name of the BEM element.
* @param {?List} modifiers A list of BEM modifiers to be applied to the element.
* @param {?List} extra A list of plain classes to add to the final classList.
*/
(element?: string, modifiers?: WordSet, extra?: WordSet): TReturn;
(args: HelperArguments): TReturn;
}
interface BaseConstructorOptions {
/**
* The name of the BEM block.
*/
name: string;
/**
* A string to prefix the block with.
*/
prefix?: string;
/**
* A string to use to separate the element name from the modifier.
*/
modifierDelimiter?: string;
}
interface StringConstructorOptions extends BaseConstructorOptions {
/**
* Whether to return a string or an object containing a classList field.
*/
outputIsString: true;
}
interface ObjectConstructorOptions extends BaseConstructorOptions {
/**
* Whether to return a string or an object containing a classList field.
*/
outputIsString: false;
}
type ConstructorOptions = StringConstructorOptions | ObjectConstructorOptions;
interface Constructor<TDefaultReturn extends (string | ReturnObject)> {
new (name: string): BEMHelper<TDefaultReturn>;
new (options: BaseConstructorOptions): BEMHelper<TDefaultReturn>;
new (options: StringConstructorOptions): BEMHelper<string>;
new (options: ObjectConstructorOptions): BEMHelper<ReturnObject>;
(name: string): BEMHelper<TDefaultReturn>;
(options: BaseConstructorOptions): BEMHelper<TDefaultReturn>;
(options: StringConstructorOptions): BEMHelper<string>;
(options: ObjectConstructorOptions): BEMHelper<ReturnObject>;
}
/**
* Create a new helper object for a BEM block.
*/
interface RootConstructor extends Constructor<ReturnObject> {
/**
* Return a new constructor with the given defaults.
*/
withDefaults(defaults: Partial<StringConstructorOptions>): Constructor<string>;
/**
* Return a new constructor with the given defaults.
*/
withDefaults(defaults: Partial<ObjectConstructorOptions>): Constructor<ReturnObject>;
}
}
declare var BEMHelper: BEMHelper.Constructor;
declare var BEMHelper: BEMHelper.RootConstructor;
export = BEMHelper;

115

index.js

@@ -0,4 +1,10 @@

var assign = require('object-assign');
function pushArray(array, newElements) {
Array.prototype.push.apply(array, newElements);
}
function isObject(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
return type === 'function' || (type === 'object' && !!obj);
}

@@ -10,7 +16,10 @@

function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
function isFunction(func) {
return typeof func === 'function';
}
function stringToArray(string) {
return string.split(/\s+/g).filter(function(c) {return c.length !== 0});
}
function objectToArray(object) {

@@ -28,3 +37,3 @@ var keys = Object.keys(object);

if (predicate) {
output.push(key);
pushArray(output, stringToArray(key));
}

@@ -38,5 +47,7 @@ });

if (isString(list) && list !== '') {
return list.split(' ');
return stringToArray(list);
} else if (list && list.length) {
return list;
return list.reduce(function (array, string) {
return array.concat(stringToArray(string));
}, []);
} else if (isObject(list)) {

@@ -49,49 +60,63 @@ return objectToArray(list);

module.exports = function(options) {
if (isString(options)) {
options = { name: options };
}
function withDefaults(defaults) {
return function(options) {
if (isString(options)) {
options = { name: options };
}
return function(first, modifiers, extraClassNames) {
var blockName = options.name;
var rootName = blockName;
var classNames = [];
var modifierDelimiter = options.modifierDelimiter || '--';
var element;
var rootDefaults = {
prefix: '',
modifierDelimiter: '--',
outputIsString: false,
};
// 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;
}
// Copy options on top of defaults
options = assign(rootDefaults, defaults, options);
if (element) {
rootName += '__' + element;
}
var blockName = options.prefix + options.name;
var modifierDelimiter = options.modifierDelimiter;
var outputIsString = options.outputIsString;
classNames.push(rootName);
return function(first, modifiers, extraClassNames) {
var element;
// Compose an array of modifiers
listToArray(modifiers).forEach(function(modifier) {
classNames.push(rootName + modifierDelimiter + modifier);
});
// 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;
}
// Add a prefix to all the classes in the classNames array
if (options.prefix) {
for (var i = 0; i < classNames.length; i++) {
classNames[i] = options.prefix + classNames[i];
var rootName;
if (element) {
rootName = blockName + '__' + element;
} else {
rootName = blockName;
}
}
// Compose an array of extraClassNames
listToArray(extraClassNames).forEach(function(extraClassName) {
classNames.push(extraClassName);
});
return {
className: classNames.join(' ').trim()
// Always include the root name first
var classNames = [rootName];
// Push on modifiers list and extraClassNames list
pushArray(classNames, listToArray(modifiers).map(function(modifier) {
return rootName + modifierDelimiter + modifier;
}));
pushArray(classNames, listToArray(extraClassNames));
var classNameString = classNames.join(' ').trim();
if (outputIsString) {
return classNameString;
} else {
return { className: classNameString };
}
};
};
};
}
var BEMHelper = withDefaults({});
BEMHelper.withDefaults = withDefaults;
module.exports = BEMHelper;
{
"name": "react-bem-helper",
"version": "1.3.1",
"version": "1.4.0",
"description": "allows you to easily add BEM-style element and modifier classes to React elements, while hopefully making it easier to scan.",

@@ -8,3 +8,3 @@ "main": "index.js",

"scripts": {
"test": "jasmine && tsc"
"test": "jasmine && tsc && echo 'TypeScript declarations compiled successfully.\n'"
},

@@ -32,3 +32,6 @@ "author": "Marco Hamersma",

},
"homepage": "https://github.com/marcohamersma/react-bem-helper"
"homepage": "https://github.com/marcohamersma/react-bem-helper",
"dependencies": {
"object-assign": "^4.1.1"
}
}

@@ -8,3 +8,3 @@ # React BEM helper

I found myself writing code like this a lot in my React components:
```html
```jsx
<div className="c-componentName">

@@ -37,5 +37,5 @@ <div className="c-componentName__inner">

## How does it work?
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).
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 React element: ` { classNames: 'componentName' }`. You can use the spread operator (`{...object}`) to apply this object to the React element.
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.
You can supply an [options object](#preparing-the-helper) to change helper's behaviour. For example, you can set the `outputIsString` option to `true`, and receive a plain string for the classname. A className prefix (like `c-`) option can be added as well.

@@ -45,3 +45,3 @@ ## Example

```js
```jsx
var React = require('react');

@@ -78,3 +78,3 @@ var BEMHelper = require('react-bem-helper');

```javascript
```jsx
var BEMhelper = require('react-bem-helper');

@@ -85,13 +85,16 @@

// Or pass an options object with a prefix to be applied to all components
// Or pass an options object with a prefix to be applied to all components and output set to return
// a string instead of an object
var bemHelper2 = new BEMHelper({
name: 'componentName',
name: 'componentName', // required
prefix: 'mh-',
modifierDelimiter: false
modifierDelimiter: false,
outputIsString: false
});
```
Options can be shared throughout a project by using [withDefaults()](#withdefaults).
### Using the helper
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
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 (prefixed if applicable)
```jsx
var React = require('react'),

@@ -112,7 +115,6 @@ BEMHelper = require('react-bem-helper');

#### Alternate Syntax
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
```jsx
var React = require('react'),

@@ -142,3 +144,3 @@ BEMHelper = require('react-bem-helper');

```js
```jsx
var BEMHelper = require('react-bem-helper');

@@ -152,3 +154,3 @@ var bemHelper = new BEMHelper('componentName');

```js
```jsx
bemHelper({ element: 'header' }); // returns { className: 'componentName__header' }

@@ -160,7 +162,7 @@ ```

```js
```jsx
var BEMHelper = require('react-bem-helper');
var bemHelper = new BEMHelper('componentName');
bemHelper(null, 'active');
bemHelper(null, 'active');
// or

@@ -170,2 +172,5 @@ bemHelper({ modifiers: 'active' });

bemHelper('lol', 'active funny');
// { className: 'componentName__lol componentName__lol--active componentName__lol--funny'}
bemHelper('lol', 'active');

@@ -178,7 +183,8 @@ // { className: 'componentName__lol componentName__lol--active'}

bemHelper('lol', {
active: true,
funny: false,
playing: function() { return false;}
'active': true,
'funny': false,
'playing': function() { return false; }
'stopped notfunny': function() { return true; }
});
// { className: 'componentName__lol componentName__lol--active'}
// { className: 'componentName__lol componentName__lol--active componentName__lol--stopped componentName__lol--notfunny'}
```

@@ -191,3 +197,3 @@

```js
```jsx
var BEMHelper = require('react-bem-helper');

@@ -198,3 +204,3 @@ var bemHelper = new BEMHelper('componentName');

// or
bemHelper({ extra: ['one', 'two'] });
bemHelper({ extra: ['one', 'two'] });
// { className: 'componentName one two'}

@@ -212,8 +218,28 @@

### Output as string
By default, the helper outputs an object (e.g. `{ className: 'yourBlock' }`). By supplying a constructor option or by [setting custom defaults](#withdefaults), you can have the helper return plain strings. It is a stylistic choice, but it can come in handy when you need to pass a class name in under a different property name, such as with [react-router's Link](https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#activeclassname) component.
```jsx
var React = require('react'),
Link = require('react-router/lib/Link'),
BEMHelper = require('react-bem-helper');
var classes = new BEMHelper({ name: 'componentName', outputIsString: true });
module.exports = React.createClass({
render: function() {
return (
<Link className={classes('link')} activeClassName={classes('link', 'active')} />
);
// Returns <Link className='componentName__link' activeClassName='componentName__link componentName__link--active' />
}
});
```
### Modifier Delimiter / Default BEM naming scheme
For this project, I've chosen to use the `.block__element--modifier` naming scheme, because this seems to be the most common implementation. However, the official website on BEM [considers this to be an alternative naming scheme](https://en.bem.info/methodology/naming-convention/#modifier-name).
If you like to use the default naming scheme, you can set the `modifierDelimiter` option to `_` when creating the bemHelper:
If you like to use the official naming scheme, you can set the `modifierDelimiter` option to `_` when creating the bemHelper, or [set it as the default](#withdefaults):
```js
```jsx
var classes = new BEMHelper({

@@ -224,3 +250,3 @@ name: 'componentName',

// ...

@@ -237,3 +263,45 @@ module.exports = React.createClass({

### withDefaults
Often, you will need to set defaults for your whole project, or maybe just one part of it. That's where `BEMHelper.withDefaults()` comes in. It creates a new constructor with one or more base defaults overridden. For example:
```js
// custom-bem-helper.js
var withDefaults = require('react-bem-helper').withDefaults;
module.exports = withDefaults({
// You don't need to override all defaults. If you want to (for example) keep the original '--'
// modifier delimiter, just omit that field here.
prefix: 'pfx-',
modifierDelimiter: '_',
outputIsString: true
});
```
Now, we just require our custom helper instead of `'react-bem-helper'`.
```jsx
// MyComponent.jsx
var React = require('react'),
BEMHelper = require('./custom-bem-helper');
var classes = new BEMHelper('MyComponent');
module.exports = React.createClass({
render: function() {
return (
<div className={classes('element', 'modifier')} />
);
// Returns <div className='pfx-MyComponent__element pfx-MyComponent__element_modifier'/>
}
});
```
## Related projects
* [bem-classnames](https://github.com/pocotan001/bem-classnames)
* [react-bem](https://github.com/cuzzo/react-bem)
* [bem-cn](https://github.com/albburtsev/bem-cn)
* [b_](https://github.com/azproduction/b_)
## License
MIT License
/*global it, describe, expect */
var BEMhelper = require('./index');
var BEMHelper = require('./index');

@@ -11,6 +11,6 @@ function resultWithClassName(className) {

describe('react-bem-helper', function() {
var bemhelper = new BEMhelper('block');
var bemhelper = new BEMHelper('block');
it('should return className for the block when no arguments given', function() {
var bemhelperWithoutPrefix = new BEMhelper({
var bemhelperWithoutPrefix = new BEMHelper({
name: 'block',

@@ -20,11 +20,4 @@ prefix: ''

var bemhelperWithoutPrefix2 = new BEMhelper({
name: 'block',
prefix: null
});
expect(bemhelper('')).toEqual(resultWithClassName('block'));
expect(bemhelper()).toEqual(resultWithClassName('block'));
expect(bemhelperWithoutPrefix('')).toEqual(resultWithClassName('block'));
expect(bemhelperWithoutPrefix2('')).toEqual(resultWithClassName('block'));
});

@@ -84,4 +77,4 @@

it('as an array, should return classNames for the element and each modifier given', function() {
var modifiers = ['one', 'two'];
expect(bemhelper('', modifiers)).toEqual(resultWithClassName('block block--one block--two'));
var modifiers = ['one', 'two three'];
expect(bemhelper('', modifiers)).toEqual(resultWithClassName('block block--one block--two block--three'));
});

@@ -95,8 +88,10 @@

'four': function() { return false; },
'five': function() { return true; }
'five': function() { return true; },
'six seven': true
};
expect(bemhelper('', modifiers)).toEqual(resultWithClassName('block block--two block--five'));
expect(bemhelper(null, modifiers)).toEqual(resultWithClassName('block block--two block--five'));
expect(bemhelper({ modifiers: modifiers })).toEqual(resultWithClassName('block block--two block--five'));
var result = 'block block--two block--five block--six block--seven';
expect(bemhelper('', modifiers)).toEqual(resultWithClassName(result));
expect(bemhelper(null, modifiers)).toEqual(resultWithClassName(result));
expect(bemhelper({ modifiers: modifiers })).toEqual(resultWithClassName(result));
});

@@ -117,11 +112,12 @@ });

'two': true,
'three': false
'three': false,
'four five': true
};
expect(bemhelper('', '', extraClasses)).toEqual(resultWithClassName('block two'));
expect(bemhelper({ extra: extraClasses })).toEqual(resultWithClassName('block two'));
expect(bemhelper('', '', extraClasses)).toEqual(resultWithClassName('block two four five'));
expect(bemhelper({ extra: extraClasses })).toEqual(resultWithClassName('block two four five'));
});
it('when given a prefix, should append generated BEM classes with that', function() {
var prefixedBEM = new BEMhelper({
var prefixedBEM = new BEMHelper({
name: 'block',

@@ -138,3 +134,3 @@ prefix: 'mh-'

it('when modifierDelimiter option is set, should prefix modifier with that', function() {
var modifierBem = new BEMhelper({
var modifierBem = new BEMHelper({
name: 'block',

@@ -146,3 +142,3 @@ modifierDelimiter: '_'

var modifierBem = new BEMhelper({
var modifierBem = new BEMHelper({
name: 'block',

@@ -154,2 +150,42 @@ modifierDelimiter: '🐘'

});
it('should return a string instead of an object when outputIsString is set true', function() {
var stringBem = new BEMHelper({
name: 'block',
outputIsString: true
});
expect(stringBem('')).toBe('block');
expect(stringBem('element')).toBe('block__element');
expect(stringBem('element', 'modifier')).toBe('block__element block__element--modifier');
});
describe('when using withDefaults', function() {
var HelperWithDefaults = BEMHelper.withDefaults({
prefix: 'pfx-',
modifierDelimiter: '_',
outputIsString: true
});
it('should apply the defaults', function() {
var bem1 = new HelperWithDefaults('block')
var bem2 = new HelperWithDefaults({
name: 'block'
});
expect(bem1('element', 'modifier')).toBe('pfx-block__element pfx-block__element_modifier');
expect(bem2('element', 'modifier')).toBe('pfx-block__element pfx-block__element_modifier');
});
it('should be able to override the defaults', function() {
var bem = new HelperWithDefaults({
name: 'block',
prefix: '',
modifierDelimiter: '@',
outputIsString: false
});
expect(bem('element', 'modifier')).toEqual(resultWithClassName('block__element block__element@modifier'));
});
});
});
/**
* @file react-bem-helper/test.d.ts
* @file react-bem-helper/typings-tests.ts
*
* Created by Zander Otavka on 2/11/17.
*
* @license
* Copyright (C) 2016 Zander Otavka
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

@@ -25,30 +9,57 @@

let helper = new BEMHelper("foo");
helper = new BEMHelper({
name: "bar",
prefix: "foo",
modifierDelimiter: "_",
let BEMStringHelper: BEMHelper.Constructor<string> = BEMHelper.withDefaults({
outputIsString: true,
});
helper = BEMHelper("foo");
helper = BEMHelper({
name: "bar",
prefix: "foo",
modifierDelimiter: "_",
let BEMObjectHelper: BEMHelper.Constructor<BEMHelper.ReturnObject> = BEMHelper.withDefaults({
outputIsString: false,
});
helper("foo", "bar baz", ["zing", "zong"]);
helper("zip", {foo: false, elzo: () => true});
helper("elf");
helper();
let objectHelper: BEMHelper<BEMHelper.ReturnObject> = new BEMHelper("foo");
objectHelper = new BEMHelper({
name: "bar",
modifierDelimiter: "_",
});
objectHelper = BEMHelper("foo");
objectHelper = BEMHelper({
name: "bar",
prefix: "foo",
});
objectHelper = BEMStringHelper({
name: "bar",
outputIsString: false,
});
helper({
element: "foo",
modifier: ["more", "than", "one"],
modifiers: "classes other classes",
extra: {
other: true,
class: () => false,
},
let stringHelper: BEMHelper<string> = new BEMStringHelper("foo");
stringHelper = new BEMHelper({
name: "bar",
outputIsString: true,
});
stringHelper = new BEMObjectHelper({
name: "bar",
outputIsString: true,
});
helper({});
let returnObject: BEMHelper.ReturnObject = objectHelper("foo", "bar baz", ["zing", "zong"]);
returnObject = objectHelper("zip", { foo: false, elzo: () => true });
returnObject = objectHelper("elf");
returnObject = objectHelper();
returnObject = objectHelper({
element: "foo",
modifier: ["more", "than", "one"],
modifiers: "classes other classes",
extra: {
other: true,
class: () => false,
},
});
returnObject = objectHelper({});
let string: string = stringHelper("foo", "bar baz", ["zing", "zong"]);
string = stringHelper("zip", { foo: false, elzo: () => true });
string = stringHelper("elf");
string = stringHelper();
string = stringHelper({
element: "foo",
});
string = stringHelper({});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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