# 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
    13338x
    13338x
    150x
    150x
    13188x
    13188x
    13188x
    68457x
    11794x
    11794x
    68457x
    68457x
    13188x
    13188x
    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
    392x
    392x
    1x
    1x
    1x
    1x
    392x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    391x
    14093x
    14093x
    14093x
    14093x
    14075x
    1x
    1x
    1x
    1x
    14075x
    14092x
    14093x
    754x
    754x
    13338x
    14085x
    9699x
    9699x
    3639x
    3639x
    3639x
    391x
     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);
      };
    }