# All files / src/utils bem.ts

100% Statements 109/109
100% Branches 20/20
100% Functions 3/3
100% Lines 109/109

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    1101x
    1x
    1x
    1x
    13409x
    13409x
    158x
    158x
    13251x
    13251x
    13251x
    68728x
    11824x
    11824x
    68728x
    68728x
    13251x
    13251x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    405x
    405x
    1x
    1x
    1x
    1x
    405x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    404x
    14166x
    14166x
    14166x
    14166x
    14148x
    1x
    1x
    1x
    1x
    14148x
    14165x
    14166x
    756x
    756x
    13409x
    14158x
    9732x
    9732x
    3677x
    3677x
    3677x
    404x
     export type Block = string;
    export type Element = string;
    export type Modifier = Record<string, unknown>;

    function modify(base: string, modifier?: Modifier): string {
      if (!modifier) {
        return base;
      }

      const hasOwn = Object.prototype.hasOwnProperty;
      return Object.keys(modifier).reduce((s, mod) => {
        if (hasOwn.call(modifier, mod) && modifier[mod]) {
          s = `${s} ${base}--${mod}`;
        }

        return s;
      }, base);
    }

    export type BEMResult = (
      elementOrModifier?: Element | Modifier,
      modifier?: Modifier
    ) => string;

    /**
     * Applies the BEM styled class name to an element.
     *
     * @example
     * Simple Example
     * ```jsx
     * import { Bem } from "@react-md/core":
     *
     * const styles = bem("my-component"):
     *
     * export function MyComponent(props) {
     *   const className = styles({
     *     always: true,
     *     never: false,
     *     "some-condition": props.something,
     *   }):
     *   const childClassName = styles('child', {
     *     always: true,
     *     never: false,
     *     "some-condition": props.something,
     *   });
     *
     *   // With a false-like `props.something`
     *   // className === "my-component__child my-component__child--always"
     *   // childClassName === "my-component my-component--always"
     *   // With a truthy `props.something`
     *   // className === "my-component my-component--always my-component--some-condition"
     *   // childClassName === "my-component__child my-component__child--always my-component__child--some-condition"
     *
     *   return (
     *     <div className={className}>
     *       <div className={childClassName} />
     *     </div>
     *   ):
     * }
     * ```
     *
     * @see https://en.bem.info/methodology/css/
     * @param base - The base class to use
     * @returns a function to call that generates the full class name
     */
    export function bem(base: Block): BEMResult {
      if (process.env.NODE_ENV !== "production") {
        if (!base) {
          throw new Error(
            "bem requires a base block class but none were provided."
          );
        }
      }

      /**
       * Creates the full class name from the base block name. This can be called
       * without any arguments which will just return the base block name (kind of
       * worthless), or you can provide a child element name and modifiers.
       *
       * @param elementOrModifier - This is either the child element name or an
       * object of modifiers to apply. This **must** be a string if the second
       * argument is provided.
       * @param modifier - Any optional modifiers to apply to the block and optional
       * element.
       * @returns the full class name
       */
      return function block(
        elementOrModifier?: Element | Modifier,
        modifier?: Modifier
      ): string {
        if (process.env.NODE_ENV !== "production") {
          if (typeof elementOrModifier !== "string" && modifier) {
            throw new TypeError(
              "bem does not support having two modifier arguments."
            );
          }
        }

        if (!elementOrModifier) {
          return base;
        }

        if (typeof elementOrModifier !== "string") {
          return modify(base, elementOrModifier);
        }

        return modify(`${base}__${elementOrModifier}`, modifier);
      };
    }