Skip to content

Instantly share code, notes, and snippets.

@SiegeSailor
Last active May 27, 2021 11:42
Show Gist options
  • Save SiegeSailor/66a6a5de0fd5c08525a1d31d9ca7959c to your computer and use it in GitHub Desktop.
Save SiegeSailor/66a6a5de0fd5c08525a1d31d9ca7959c to your computer and use it in GitHub Desktop.
Create and maintain classes with BEM.

Overview

Create and maintain classes with BEM.

Example

import React from 'react';
import { BEN as HandleBEM } from './HandleBEM';

export default function Demostration({ isWarning }: { isWarning: boolean }) {
  const BEM = new HnadleBEM(Demostration.name);
  
  return (
    <div className={BEM.block}>
      <h1 className={BEM.create('title')}>Title</h1>
      {isWarning && <span className={BEM.create(['title'], 'warning')}>WARNING</span>}
    </div>
  );
}
/**
* Create and maintain classes with [BEM](http://getbem.com/).
* @since Feature
*/
export default class BEM {
private _block: string;
private elementArray: string[];
private modifierArray: string[];
private _record: { [element: string]: string[] };
/**
* Input the block name.
* @param {string} block - The block name.
*/
constructor(block: string) {
this._block = BEM.convertStringIntoKebabCase(block);
this.elementArray = [];
this.modifierArray = [];
this._record = {};
}
get block() {
return this._block;
}
get element() {
return BEM.excludeDuplicatedFromArray(this.elementArray);
}
get modifier() {
return BEM.excludeDuplicatedFromArray(this.modifierArray);
}
get infoElement() {
return BEM.countTimesForEachArrayMember(this.elementArray);
}
get infoModifier() {
return BEM.countTimesForEachArrayMember(this.modifierArray);
}
get record() {
const handledRecord: { [key: string]: string[] } = {};
Object.entries(this._record).forEach(([element, modifierArray]) => {
handledRecord[element] = BEM.excludeDuplicatedFromArray(modifierArray);
});
return handledRecord;
}
/**
* Convert a string into `kebab-case`.
* @param {string} input - The string.
* @return {string} The input in `kebab-case` format.
* @see See {@link https://stackoverflow.com/a/63116134/13564651 StackOverFlow} for the origin of this method.
*/
static convertStringIntoKebabCase(input: string): string {
return input
.split('')
.map((letter, index) => {
return letter.toUpperCase() === letter ? `${index !== 0 ? '-' : ''}${letter.toLowerCase()}` : letter;
})
.join('');
}
/**
* Exclude duplicated value from a string array.
* @param {string[]} inputArray - A string array.
* @return {string[]} A string array without duplicated value.
*/
static excludeDuplicatedFromArray(inputArray: string[]): string[] {
return inputArray.filter((element, index) => inputArray.indexOf(element) === index);
}
/**
* Count each shown times for the array members.
* @param {string[]} inputArray - A string array.
* @return {Record<string, number>} An object with key from the array members and value for their shown times.
*/
static countTimesForEachArrayMember(inputArray: string[]): Record<string, number> {
return inputArray.reduce((accumulator, currentValue) => {
accumulator[currentValue] = (accumulator[currentValue] ?? 0) + 1;
return accumulator;
}, {} as Record<string, number>);
}
/**
* Create a valid `className` with BEM standard.
* @param {string[]} element - Element name list.
* @param {string} modifier - Modifier name. Optional.
* @return {string} A valid `className` with BEM standard..
*/
create(elementList: string[], modifier?: string): string {
elementList.forEach((element) => {
this.elementArray.push(element);
if (!this._record[element]) {
this._record[element] = [];
}
if (modifier) {
elementList.forEach((element) => {
this._record[element].push(modifier);
});
}
});
if (modifier) {
this.modifierArray.push(modifier);
}
let elementFull = '';
return `${this._block}${elementList
.map((element) => {
elementFull = elementFull + `__${element}`;
return `__${element}`;
})
.join('')}${modifier ? ` ${this._block}${elementFull}--${modifier}` : ''}`;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment