Skip to content
This repository has been archived by the owner on Jul 28, 2024. It is now read-only.
/ class-name Public archive

๐Ÿ– Create and format BEM class names for React components

License

Notifications You must be signed in to change notification settings

wavevision/class-name

Repository files navigation

Wavevision s.r.o.

Class Name

CI Coverage Status npm

Create and format BEM class names for React components. The formatter uses simplified BEM syntax.

Installation

Via Yarn

yarn add @wavevision/class-name

or npm

npm install --save @wavevision/class-name

Usage

Simple React component

import React, { useState, FunctionComponent } from 'react';
import className, { USE_VALUE } from '@wavevision/class-name';

interface ComponentProps {
  align: string;
  booleanProp: boolean;
  nullableProp: string | null;
  stringProp: string;
}

interface ComponentState {
  visible: boolean;
}

// Define base class name with props and state behaving as modifiers
const componentClassName = className<ComponentProps, ComponentState>(
  'component-class',
  () => ({
    // if booleanProp value is truthy, 'booleanProp' will be used as modifier
    booleanProp: true,
    // if stringProp value is truthy then the value will be used
    stringProp: USE_VALUE,
    // use callback for custom modifiers, string returned will be used
    customModifier: ({ props }) => (props.nullableProp ? 'custom' : null),
    // if a non-string truthy value is returned, key will be used
    anotherModifier: ({ state }) => state.visible,
  }),
);

// We can also have modifiers defined only if some condition is met
const anotherClassName = className<ComponentProps, ComponentState>(
  'another-class',
  ({ props, state }) => {
    if (props.nullableProp !== null) {
      // the whole set of modifiers will be created only if nullableProp is not null
      return { stringProps: USE_VALUE, customModifier: () => true };
    }
    if (state.visible) {
      // this set will be created only if state.visible is true
      return { customModifier: () => true };
    }
  },
);

const Component: FunctionComponent<ComponentProps> = props => {
  const [visible] = useState<ComponentState['visible']>(false);
  const className = componentClassName({ props, state: { visible } });
  const nextClassName = anotherClassName({ props, state: { visible } });
  return (
    <div className={className.block('inline-modifier')}>
      <div className={nextClassName.block()} />
      <div
        className={className.compose(
          className.element('child'),
          // extra class name with optional prefix (e.g. Bootstrap text utility)
          className.extra(props.align, 'text'),
        )}
      />
      // modifiers can be nullable and will be used only if not null
      <div className={className.element('element', props.nullableProp)} />
      <div className={className.element('another', 'element-modifier')} />
    </div>
  );
};

will output following when rendered

<Component
  align="right"
  booleanProp={true}
  nullableProp={null}
  stringProp="something"
/>
<div
  class="component-class component-class--boolean-prop component-class--something component-class--inline-modifier"
>
  <div class="another-class"></div>
  <div class="component-class__child text-right"></div>
  <div class="component-class__element"></div>
  <div
    class="component-class__another component-class__another--element-modifier"
  ></div>
</div>