GithubHelp home page GithubHelp logo

ember-cli-bem's Introduction

ember-cli-bem Build Status Ember Observer Score

This addon helps you define class names in BEM way. Make your templates shorter with a help of elem helper. Save your lifetime and use convenient modifier definitions in BEM mixin. ember-cli-bem encapsulates all BEM naming logic so you don't have to reinvent the wheel.

Installation

The addon requires Ember version to be 2.4 or newer. It doesn't touch CSS bundling, so it may be used with any CSS preprocessor.

ember install ember-cli-bem

Motivation

When you decide to use BEM in your project, your code often turns into something like this:

  {{!-- Don't do this! --}}
  <div class="
    {{componentCssClassName}}__item
    {{if someCondition (concat componentCssClassName '__item_disabled')}}
    {{componentCssClassName}}__item_type_highlighted
  "></div>

Or like this:

import Component from '@ember/component';
import { computed } from '@ember/object';

/**
 *  Please don't do like this
 */
export default Component.extend({
  classNameBindings: ['typeMod'],
  type: 'highlighted',
  typeMod: computed('componentCssClassName', 'type', function() {
    const type = this.get('type');
    if (type) {
      return `${this.get('componentCssClassName')}_type_${type}`
    } else {
      return '';
    }
  }),
});

This breaks DRY principle, you duplicate BEM naming logic everywhere in your code. Now with ember-cli-bem this problem is solved.

Blocks

Block, according to the official documentation, is a logically and functionally independent component. There is no other functionally independent component as button, so let's create it for example.

// app/components/b-button/component.js
import Component from '@ember/component';
import BEM from 'ember-cli-bem/mixins/bem';

export default Component.extend(BEM, {
  // Mandatory field
  blockName: 'button',

  // Mods has the same syntax as `classNameBindings`,
  // so you can use something like `someProperty:modifier-name`
  mods: ['disabled:is-disabled', 'size'],
});

In these lines a great power is being contained. Now look what happens when you use the button in your template:

{{b-button disabled=true size='m'}}

{{!-- turns into --}}

<div class="button button_is-disabled button_size_m"></div>

All modifiers defined in mods array turned into separate classes. It's a great opportunity to split your styles into small and reusable chunks.

Elements

Sometimes you need to define an inline entity, which won't be used outside a block. In BEM we call such entity an element. Let's define some header block first:

// app/components/h-header/component.js
import Component from '@ember/component';
import BEM from 'ember-cli-bem/mixins/bem';

export default Component.extend(BEM, {
  blockName: 'header',
});

Then add a template for it. Just look what happens then:

  {{!-- app/components/h-header/template.hbs --}}
  {{#b-button
    size='m'
    className=(elem 'tab' active=true type='link')
  }}
    <div class={{elem 'caption'}}></div>
  {{/b-button}}

  {{!-- turns into --}}

  <div class="button button_size_m header__tab header__tab_active header__tab_type_link">
    <div class="header__caption"></div>
  </div>

Under the hood, elem helper obtained its wrapping component's blockName and composed an element name from it. Every named property passed to elem helper turned into a modifier.

While the caption element looks pretty straightforward, the tab isn't that simple. When we assign an element class name to the block, we call it a mix in BEM. In our example, we used a mix to make the button look different exactly at one place โ€” at the header.

Configuring Addon

BEM-naming can be configured.

// config/environment.js
ENV['ember-cli-bem'] = {
  elemDelimiter: '__',
  modDelimiter: '_',
  useKeyValuedMods: true,
}

elemDelimiter

Default value: '__'

Defines how to separate block and element names.

modDelimiter

Default value: '_'

It defines how to separate modifier name from the rest of the class name.

useKeyValuedMods

Default value: true

If false, addon will not create key-value modifiers. Refer to the following table to understand what class will be generated with this option enabled or disabled:

Modifier Value With useKeyValuedMods Without useKeyValuedMods
true 'block_disabled' 'block_disabled'
'force' 'block_disabled_force' 'block_disabled'
false '' ''
'' '' ''

Note the case with 'force' modifier value.

ember-cli-bem's People

Contributors

ember-tomster avatar nikityy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ember-cli-bem's Issues

Missing module ember-get-config

After updating to v1.0.0-beta.1 i get the following error:
Error: Could not find module 'ember-get-config' imported from 'ember-cli-bem/mixins/bem'

Custom Delimiters in v1.0.0-beta.1+

Using custom delimiters (elemDelimiter and modDelimiter) only work in v1.0.0-beta.1+

When downloading via Installation heading in the readme (ember install ember-cli-bem), it only downloads the latest stable, which as of this writing does not include the custom delimiters.

Either update the readme to include a note about custom delimiter option is only available in v1.0.0-beta.1+, or create a new release so users can use it when running the ember install command.

PS: Great job on this, I knew there had to be a better way instead of using {{concat cssClassName "__element"}} everywhere, lol!

Suggestion rename helper from "elem" to "bem"

Hi, looks like a great plugin thanks!

I think the elem helper would probably be better if called bem instead, because elem is very generic. It is less likely to collide with other helpers and easier to understand what it is doing.

Edit: Might also be a good idea to rename mods to bemMods.

Just a suggestion, thanks for reading!

Minimum supported Ember version

What is the minimum supported Ember version? I tried to use this addon with Ember 1.12.2 but seems it doesn't work.

It would be nice to add the info about minimum version to Readme.

Use BEM modifier syntax

Hey, why do you use one underscore instead of the two dashes for the modifier?

Your naming:
button__container_collapsed

BEM naming:
button__container--collapsed

Block-scoped declarations in lib/htmlbars-plugin.js

After installing ember-cli-bem plugin I get the following error during build:
Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

which is caused by the file in the subject. Could you please add 'use strict'; to the top of the file? I know this error will be gone once I upgrade node but right now in our corporate development environment we are using v4.8.0 and it's not gonna change in the nearest future.

Looks like a minor change...

Accessing a component with BEM mixin in Ember inspector causes ember inspector to crash

When I try and load up a component in the Ember inspector that has the ember-cli-bem/mixins/bem applied to it, it causes the Ember inspector to error out with the following in the console:

VM38853:92 Ember Inspector has errored.
This is likely a bug in the inspector itself.
You can report bugs at https://github.com/emberjs/ember-inspector.
Error message: Assertion Failed: You attempted to access `modsClassNames.type` (on `<ceannate-web@component:consent-documents/document-list::ember1447>`), but `modsClassNames` is a computed property.

Due to certain internal implementation details of Ember, the `modsClassNames` property previously contained a private "descriptor" object, therefore `modsClassNames.type` would have been `undefined`.

This implementation detail has now changed and the "descriptor" object is no longer present at this location. Soon, accessing `modsClassNames` on this object will return the computed property's current value (see RFC #281 for more details).

If you are seeing this error, you are likely using an addon that relies on this now-defunct private implementation detail. If you can, identify the addon from the stack trace below and report this bug to the addon authors. If you feel stuck, the Ember Community Slack (https://ember-community-slackin.herokuapp.com/) may be able to offer some help.

If you are an addon author and need help transitioning your code, please get in touch in the #dev-ember channel in the Ember Community Slack.
Stack trace: Error: Assertion Failed: You attempted to access `modsClassNames.type` (on `<ceannate-web@component:consent-documents/document-list::ember1447>`), but `modsClassNames` is a computed property.

Due to certain internal implementation details of Ember, the `modsClassNames` property previously contained a private "descriptor" object, therefore `modsClassNames.type` would have been `undefined`.

This implementation detail has now changed and the "descriptor" object is no longer present at this location. Soon, accessing `modsClassNames` on this object will return the computed property's current value (see RFC #281 for more details).

If you are seeing this error, you are likely using an addon that relies on this now-defunct private implementation detail. If you can, identify the addon from the stack trace below and report this bug to the addon authors. If you feel stuck, the Ember Community Slack (https://ember-community-slackin.herokuapp.com/) may be able to offer some help.

If you are an addon author and need help transitioning your code, please get in touch in the #dev-ember channel in the Ember Community Slack.
    at new EmberError (http://localhost:4200/assets/vendor.js:28634:25)
    at Object.assert (http://localhost:4200/assets/vendor.js:28877:15)
    at Object.get (http://localhost:4200/assets/vendor.js:38317:42)
    at addProperties (<anonymous>:3106:40)
    at mixin.mixins.forEach.mixin (<anonymous>:3077:11)
    at Array.forEach (<anonymous>)
    at propertiesForMixin (<anonymous>:3075:20)
    at Class.mixinsForObject (<anonymous>:2965:22)
    at Class.sendObject (<anonymous>:2884:26)
    at Class.inspectById (<anonymous>:2808:16)

Any ideas as to how I could refactor the library to play nicely with the latest Ember Inspector?

Here's what I'm currently running:

Ember Inspector | 3.3.2
Ember | 3.0.0
Ember Data | 3.0.2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.