npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

bem-react-core

v1.1.0

Published

BEM React Core

Downloads

56

Readme

BEM React Core Build Status GitHub Release devDependency Status

What is it?

The BEM React Core is a library for working with React components according to the BEM methodology. The library runs on top of the regular React components and provides an API for defining declarations of blocks, elements, and modifiers. Blocks and elements created with bem-react-core are fully compatible with standard React components and can be used in the same project.

Why?

If you are familiar with the BEM methodology and want to get the functionality of the i-bem.js framework and a template engine in a single lightweight library.

If you are using React and want to take advantage of the BEM methodology: redefinition levels, mixes, and the class naming scheme for CSS.

To explain why you need bem-react-core, we have described the types of tasks that a combination of BEM and React can handle more efficiently than other existing methods.

Library features

The library extends the capabilities of the classic React approach and allows you to:

Examples are compared with the classic code for React components.

Generating CSS classes

A declarative description of a component reduces syntactic noise.

React.js

import React from 'react';

export default class Button extends React.Component {
    render() {
        const { size, theme, children } = this.props;
        return (
            <button className={`Button Button_size_${size} Button_theme_${theme}`}>
                {children}
            </button>
        );
    }
};

BEM React Core

import { decl } from 'bem-react-core';

export default decl({
    block : 'Button',
    tag: 'button',
    mods({ size, theme }) {
        return { size, theme };
    }
});

Redefining components declaratively using modifiers

To modify a React component, you have to add conditions to the core code of this component. As the modifications grow, the conditions multiply and become more complex. In order to avoid complex code conditions, either inherited classes or High Order Components are used. Both methods have their own limitations.

In bem-react-core, the states and appearance of universal components are changed with modifiers. The functionality of modifiers is declared in separate files. An unlimited number of modifiers can be set per component. To add a modifier, specify its name and value in the component declaration.

Redefining a component declaratively by using modifiers allows you to:

  • Avoid chains of conditions with if or switch in the render() method, which prevent you from flexibly changing the component.
  • Include only the necessary modifiers in the build.
  • Create an unlimited number of modifiers without overloading the core code of the component.
  • Combine multiple modifiers in a single component for each specific case.

React.js

import React from 'react';

export default class Button extends React.Component {
    render() {
        const { size, theme, children } = this.props;
        let className = 'Button',
            content = [children];

        if(size === 'large') {
            className += `Button_size_${size}`;
            content.unshift('Modification for size with value \'large\'.');
        }

        if(theme === 'primary') {
            className += `Button_theme_${theme}`;
            content.unshift('Modification for theme with value \'primary\'.');
        }

        return (
            <button className={className}>
                {content}
            </button>
        );
    }
};

BEM React Core

// Button.js

import { decl } from 'bem-react-core';

export default decl({
    block : 'Button',
    tag: 'button',
    mods({ size, theme }) {
        return { size, theme };
    }
});

// Button_size_large.js

import { declMod } from 'bem-react-core';

export default declMod({ size : 'large' }, {
    block : 'Button',
    content() {
        return [
            'Modification for size with value \'large\'.',
            this.__base(...arguments)
        ];
    }
});

// Button_theme_primary.js

import { declMod } from 'bem-react-core';

export default declMod({ theme : 'primary' }, {
    block : 'Button',
    content() {
        return [
            'Modification for theme with value \'primary\'.',
            this.__base(...arguments)
        ];
    }
});

The Inherit library is used for creating declarations. Unlike classes from ES2015, it allows you to create a dynamic definition of a class and modify it. It also provides the ability to make a "super" call (this.__base(...arguments)) without explicitly specifying the method name (super.content(...arguments)).

Using redefinition levels

Redefinition levels are used in BEM for dividing and reusing code.

The bem-react-core library allows you to declare React components on different redefinition levels.

Examples of using redefinition levels

The example below looks at a case when the code is divided by platform. Part of the code describes general functionality (common.blocks) and part of it is platform-specific (desktop.blocks and touch.blocks):

// common.blocks/Button/Button.js

import { decl } from 'bem-react-core';

export default decl({
    block : 'Button',
    tag : 'button',
    attrs({ type }) {
        return { type };
    }
});

// desktop.blocks/Button/Button.js

import { decl } from 'bem-react-core';

export default decl({
    block : 'Button',
    willInit() {
        this.state = {};
        this.onMouseEnter = this.onMouseEnter.bind(this);
        this.onMouseLeave = this.onMouseLeave.bind(this);
    },
    mods() {
        return { hovered : this.state.hovered };
    }
    attrs({ type }) {
        return {
            ...this.__base(...arguments),
            onMouseEnter : this.onMouseEnter,
            onMouseLeave : this.onMouseLeave
        };
    },
    onMouseEnter() {
        this.setState({ hovered : true });
    },
    onMouseLeave() {
        this.setState({ hovered : false });
    }
});

// touch.blocks/Button/Button.js

import { decl } from 'bem-react-core';

export default decl({
    block : 'Button',
    willInit() {
        this.state = {};
        this.onPointerpress = this.onPointerpress.bind(this);
        this.onPointerrelease = this.onPointerrelease.bind(this);
    },
    mods() {
        return { pressed : this.state.pressed };
    },
    attrs({ type }) {
        return {
            ...this.__base(...arguments),
            onPointerpress : this.onPointerpress,
            onPointerrelease : this.onPointerrelease
        };
    },
    onPointerpress() {
        this.setState({ pressed : true });
    },
    onPointerrelease() {
        this.setState({ pressed : false });
    }
});

Dividing the code into separate redefinition levels allows you to configure the build so that the component functionality from desktop.blocks is only in the desktop browser build (common.blocks + desktop.blocks) and is not included in the build for mobile devices (common.blocks + touch.blocks).

Usage

There are different ways to use the bem-react-core library:

Installation

Using npm:

npm i -S bem-react-core

Using Yarn:

yarn add bem-react-core

CDN

Copy the links to the pre-compiled library files to the HTML pages:

<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react.js"></script>

Connect BEM React Core using CDN links

Build

webpack

Use the loader for the webpack.

npm i -D webpack-bem-loader babel-core

webpack.config.js

// ...
module : {
    loaders : [
        {
            test : /\.js$/,
            exclude : /node_modules/,
            loaders : ['webpack-bem', 'babel']
        },
        // ...
    ],
    // ...
},
bemLoader : {
    techs : ['js', 'css'], // Technologies used for implementing components
    levels : [            // Levels used in the project
        `${__dirname}/common.blocks`,
        `${__dirname}/desktop.blocks`,
        // ...
    ]
}
// ...

Babel

Use the plugin for Babel.

npm i -D babel-plugin-bem-import

.babelrc

{
  "plugins" : [
    ["bem-import", {
      "levels" : [              
        "./common.blocks",
        "./desktop.blocks"
      ],
      "techs" : ["js", "css"]   
    }]
  ]
}

Development

Getting sources:

git clone git://github.com/bem/bem-react-core.git
cd bem-react-core

Installing dependencies:

npm i

Reviewing code:

npm run lint

Running tests:

npm test

How to make changes to a project

License

© 2018 YANDEX LLC. The code is licensed under the Mozilla Public License 2.0.