apjames93/mui-storyblok

View on GitHub
src/lib/utils/customProps.js

Summary

Maintainability
A
35 mins
Test Coverage
C
77%
/* eslint-disable no-restricted-globals */
/* eslint-disable max-len */
export const muiStringProp = (props, propName, componentName, validProps) => {
  /**
   * mui accepts strings of specific values pass array of valid Props to validate
   * ex:
   * const validProps = ['stretch', 'center', 'flex-start', 'flex-end', 'space-between', 'space-around'];
    return muiStringProp(props, propName, componentName, validProps);
   */
  const propType = typeof props[propName];
  if (propType !== 'string') {
    return new Error(`${componentName}: ${propName} expected type of string but recived type ${propType}`);
  }
  if (!validProps.includes(props[propName])) {
    return new Error(
      `${componentName}: ${props[propName]} is a invalid Prop for ${propName}.
          Must be string value of ${validProps.toString()}
        `,
    );
  }

  return undefined;
};

export const muiGridProp = (props, propName, componentName) => {
  /** mui is expecting a 'string', 'number', 'boolean' value
   * storyblok is returns all values as strings
   * checks for what storyblok will pass down and what mui is looking for
   *  */
  if (!['string', 'number', 'boolean'].includes(typeof props[propName])) {
    return new Error(
      `${componentName}: ${propName} must be of type "string", "number" or "boolean". received ${typeof props[propName]} of ${props[propName]}`,
    );
  }

  const validProps = [
    false, 'auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
    'false', 'true', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12',
  ];

  if (!validProps.includes(props[propName])) {
    return new Error(
      `${componentName}: ${props[propName]} is a invalid Prop for ${propName}. Must be string value of ${validProps.toString()}`,
    );
  }

  return undefined;
};

export const muiBlokNumberProp = (
  props,
  propName,
  componentName,
  numberArray,
) => {
  /**
   * takes array of numbers and pushes the numbers back as a string to validProps
   * to validate for mui numbers and storyblok returning props as strings
   */
  if (!['string', 'number'].includes(typeof props[propName])) {
    return new Error(
      `${componentName}: ${propName} must be of type "string" or "number" received ${typeof props[propName]}`,
    );
  }

  const validProps = [...numberArray, ...numberArray.map(number => number.toString())];
  if (!validProps.includes(props[propName])) {
    return new Error(
      `${componentName}: ${props[propName]} is a invalid Prop for ${propName}.  Must be string value of ${validProps.toString()}`,
    );
  }

  return undefined;
};


export const nestedComponentsProps = (
  props,
  propName,
  componentName,
  components,
) => {
  /**
   * used for nested grid and typographyText to see if the componets passed down are able to render
   */
  let error;
  const content = props[propName].map(x => x.content).flat().map(x => x.content).flat();
  content.forEach((comp) => {
    if (!components.includes(comp.component)) {
      error = new Error(
        `${componentName}: ${propName} must be included in components ${components.toString()} but recived ${comp.component}`,
      );
    }
  });
  return error;
};

export const dimensionProp = (props, propName, componentName) => {
  // use 'px', 'em', '%' 'vh', 'vw', as unit of measurement for height and width prop
  let error;

  if (propName === 'height' || propName === 'width') {
    if (propName === 'height' && !props[propName].includes('px')
      && !props[propName].includes('em')
      && !props[propName].includes('%')
      && !props[propName].includes('vh')) {
      error = new Error(
        `${componentName}: ${propName} has to be one of these units of size px, em, %, vh`,
      );
    } else if (propName === 'width' && !props[propName].includes('px')
      && !props[propName].includes('em')
      && !props[propName].includes('%')
      && !props[propName].includes('vw')) {
      error = new Error(
        `${componentName}: ${propName} has to be one of these units of size px, em, %, vw`,
      );
    }
  } else if (!['height', 'width'].includes(propName)) {
    error = new Error(
      'dimensionProp needs to be used on proptype with name height or width',
    );
  }

  return error;
};

export const muiDimensionProp = (props, propName, componentName) => {
  // mui accepts numbers as a number of measurement and
  // 'px', 'em', '%' 'vh', 'vw', as unit of measurement for height and width prop.
  let error;
  const propToNum = props[propName];
  if (
    (propName === 'height' && isNaN(propToNum))
    || (propName === 'width' && isNaN(propToNum))
  ) {
    error = dimensionProp(props, propName, componentName);
  }
  return error;
};

export const validComponents = (
  props,
  propName,
  componentName,
  components,
  length = undefined,
) => {
  if (!isNaN(length) && props[propName].length > length) {
    return new Error(
      `${componentName}: ${propName} can only have a length of ${length} but recived length of ${props[propName].length}`,
    );
  }

  props[propName].forEach((comp) => {
    if (!components.includes(comp.component)) {
      return new Error(
        `${componentName}: ${propName} must be included in components ${components.toString()} but recived ${comp.component}`,
      );
    }
    return undefined;
  });

  return undefined;
};

export const componentsRequired = (
  props,
  propName,
  componentName,
  length,
) => {
  if (props[propName].length !== length) {
    return new Error(
      `${componentName}: ${propName} is required to have a length of ${length} but recived length of ${props[propName].length}`,
    );
  }

  return undefined;
};

export const validComponentsRequired = (props, propName, componentName, components, length) => {
  let error;
  error = componentsRequired(props, propName, componentName, length);
  if (error) return error;
  error = validComponents(props, propName, componentName, components);
  if (error) return error;
  return undefined;
};