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

bemgular

v1.0.2

Published

Easy and powerful BEM helper for Angular2+

Downloads

2

Readme

Lightweight, easy to use BEM helper.

(1) Import and re-export Bemgular in your SharedModule

import { NgModule } from '@angular/core';
import { BemgularModule } from 'bemgular';

@NgModule({
  imports: [
    ...,
    BemgularModule,
  ],
  exports: [
    BemgularModule,
  ],
})
export class SharedModule {}

(2) Add the two Bemgular tokens to the list of providers where you need to scope your CSS

In a lazy loaded module...

import { SharedModule } from './../shared.module';
import { BEMGULAR_BLOCK } from 'bemgular';

@NgModule({
  imports: [
    SharedModule,
  ],
  providers: [
    { provide: BEMGULAR_BLOCK, useValue: 'block' },
  ],
})
export class LazyLoadedModule {}

...or in a component

import { Component } from '@angular/core';
import { BEMGULAR_MODIFIERS } from 'bemgular';

@Component({
  selector: 'my-component',
  providers: [
    { provide: BEMGULAR_MODIFIERS, useValue: [ 'modifier-1', 'modifier-2' ] },
  ],
})
export class MyComponent {}

(3) Use it in a simple, declarative directive that does all the heavy lifting for you

<div bem="container">
</div>

becomes

<div class="block__container block--modifier-1__container block--modifier2__container">
</div>

Bemgular operates in ngOnInit

So it won't recalculate the classes at every single change detection tick. Performance win!

If you need to change classes dynamically, Bemgular interacts seamlessly with ngClass

This won't work, because Bemgular fires only on ngOnInit.

<div bem="element,{{specialModifier()}}">

This will work: ngClass and Bemgular interact without interfering with each other

<div bem="element" [ngClass]="specialModifier()">

How does it work?

Bemgular takes advantage of Angular's inheritance of injectors: when you inject, in a lazy loaded module or in a component, one of the tokens

  • BEMGULAR_BLOCK
  • BEMGULAR_MODIFIER

the value you injected will apply automatically to that component / module and all its children. You can easily tune which components are contained in which block, and which modifiers apply to them, simply by letting them inherit the parent block or overriding it.

<!-- BEMGULAR_BLOCK = 'root-component'; BEMGULAR_MODIFIERS = [ 'active' ] -->
<div class="root-component__container root-component--active__container">
  <!-- BEMGULAR_BLOCK = 'first-component'; BEMGULAR_MODIFIERS inherits from parent injector -->
  <div class="first-component__container first-component--active__container">
    <!-- BEMGULAR_BLOCK = inherits from parent injector; BEMGULAR_MODIFIERS = [] -->
    <div class="first-component__subtitle">
    </div>
  </div>
</div>

Don't inject tokens in modules, unless they are lazy loaded

If you do it, they will be attached to the root injector and override your BEM settings everywhere

Bonus feature: add element's modifiers too

<div bem="container,red,thin">
</div>

becomes

<div class="some-block__container some-block__container--red some-block__container--thin">
</div>

You can add as many elements modifiers as you want; just add them separated by comma after the element.

Angular's automatic CSS scoping is slow in rendering; stick to the safe solution, use Bemgular!

This is how Angular converts your CSS to scope it

<div _ng-content-xxx class="container">
  <div _ng-content-xxx class="title">
  </div>
</div>

And this is how it would work with a flat, performing BEM class

<div class="xxx__container">
  <div class="xxx__title">
  </div>
</div>

Flat class are quite more performing than Angular's scoping via attributes. It's because of the way in which CSS is computed by the browser: it starts always from right to left, from more specific to less specific selector.

So, when you style

_ng-content-xxx.container {
  background-color: white;
}

The browser will first pick all elements that match the selector .container, and then filter out the ones that are not attached to a div containing the attribute _ng-content-xxx.

You can measure the difference yourself: run the following ruby script, that generates two different HTML and CSS files

def generate_htmls
  angular_style_css = File.open('angular-stile.css', 'w')
  bem_style_css = File.open('bem-style.css', 'w')
  angular_style_html = File.open('angular-stile.html', 'w')
  bem_style_html = File.open('bem-style.html', 'w')
  (0...10000).to_a.each do |index|
    randomised = (0...15).map { ('a'..'z').to_a[rand(26)] }.join
    [ 1, 2, 3, 4, 5, 6 ].each do |sub_index|
      angular_style_css.write "\nh1[#{randomised}].selector#{sub_index} {\n  background-color: rgb(#{rand(200)},#{rand(200)},#{rand(200)});\n  width: 100px;\n  height: 100px;\n  float: left; display: block\n}\n"
      angular_style_html.write "<h1 #{randomised} class=\"selector#{sub_index}\">Content</h1>"
      bem_style_css.write "\n.#{randomised}__#{sub_index} {\n  background-color: rgb(#{rand(200)},#{rand(200)},#{rand(200)});\n  width: 100px;\n height: 100px;\n  float: left; display: block\n}\n"
      bem_style_html.write "<h1 class=\"#{randomised}__#{sub_index}\">Content</h1>"
    end
    puts index
  end
  angular_style_css.close
  angular_style_html.close
  bem_style_css.close
  bem_style_html.close
end

Now, open with a text editor the two HTML files, and require the corresponding CSS in it. Then, open both using your browser and you'll see the difference.

The file bem-style.html takes 2-5 seconds to render. The file angular-style.html takes a couple of minutes instead.

Of course, your application doesn't contain 10.000 elements that use the same class, but if you can improve performance it's better to do it, even for small details.