apjames93/mui-storyblok

View on GitHub
src/lib/components/PageGrid/templates/GridItem/GridItem.js

Summary

Maintainability
A
0 mins
Test Coverage
A
96%
import React, { Suspense } from 'react';
import PropTypes from 'prop-types';
import Grid from '@material-ui/core/Grid';
import sizeGrid from 'lib/utils/sizeGrid';
import Storyblok from 'lib/utils/Storyblok';
import { muiStringProp, muiGridProp, muiBlokNumberProp } from 'lib/utils/customProps';
import { renderComponentsWithBridge } from 'lib/utils/customComponents';
import { Box, Hidden } from '@material-ui/core';
import { useInView } from 'react-intersection-observer';

const GridItem = ({
  components,
  alignContent,
  alignItems,
  rootClass,
  direction,
  justify,
  lg,
  md,
  sm,
  wrap,
  spacing,
  xs,
  xl,
  content,
  dataBlokC,
  dataBlokUid,
  storyblokClass,
  transition,
  only,
  backgroundImageUrl,
}) => {
  let heroClass;
  const { ref, inView } = useInView({ threshold: 0.2, triggerOnce: true });
  const gridClass = window?.Storyblok?.inEditor ? {
    borderStyle: 'solid',
    borderColor: '#3889FF',
    borderWidth: '.1em',
  } : {};


  if (backgroundImageUrl) {
    heroClass = {
      ...{
        backgroundImage: `url(${backgroundImageUrl})`,
        backgroundPosition: 'center',
        backgroundRepeat: 'no-repeat',
        backgroundSize: 'cover',
        position: 'relative',
        padding: 0,
        margin: 0,
      },
    };
  }

  const styles = Storyblok.arrayToMuiStyles(rootClass, { ...heroClass });

  return (
    <Hidden only={only}>
      <Grid
        item
        container
        alignContent={alignContent}
        alignItems={alignItems}
        direction={direction}
        justify={justify}
        wrap={wrap}
        spacing={Number(spacing)}
        xs={sizeGrid(xs)}
        sm={sizeGrid(sm)}
        md={sizeGrid(md)}
        lg={sizeGrid(lg)}
        xl={sizeGrid(xl)}
        data-blok-c={dataBlokC}
        data-blok-uid={dataBlokUid}
        className={`${styles.root} ${storyblokClass} ${inView && transition}`}
        style={{ ...gridClass, opacity: inView ? 1 : 0 }}
        inView={inView}
        ref={ref}
      >
        {!content.length && <Box minHeight={200} width={{ xs: '100%' }} />}
        {content.length > 0
          && content.map((component, key) => (
            <Suspense fallback={<></>} key={key}>
              {renderComponentsWithBridge({ ...components }, {
                ...component,
                components,
                key,
              }, key)}
            </Suspense>
          ))
        }
      </Grid>
    </Hidden>
  );
};

export default GridItem;

GridItem.propTypes = {
  /**
   * storyblok multiselect of css classes
   * Mui Override or extend the styles applied to the component.
   */
  rootClass: PropTypes.arrayOf(PropTypes.string),
  /**
   * mui prop: 'stretch', 'center', 'flex-start', 'flex-end', 'space-between', 'space-around'
   * Defines the align-content style property. It's applied for all screen sizes.
   */
  alignContent(props, propName, componentName) {
    const validProps = ['stretch', 'center', 'flex-start', 'flex-end', 'space-between', 'space-around'];
    return muiStringProp(props, propName, componentName, validProps);
  },
  /**
   * mui prop: 'flex-start' , 'center' , 'flex-end' , 'stretch' , 'baseline'
   * Defines the align-items style property. It's applied for all screen sizes.
   */
  alignItems(props, propName, componentName) {
    const validProps = ['flex-start', 'center', 'flex-end', 'stretch', 'baseline'];
    return muiStringProp(props, propName, componentName, validProps);
  },
  /*
  * mui prop: 'row' , 'row-reverse' , 'column' , 'column-reverse'
  * Defines the flex-direction style property. It is applied for all screen sizes.
  */
  direction(props, propName, componentName) {
    const validProps = ['row', 'row-reverse', 'column', 'column-reverse'];
    return muiStringProp(props, propName, componentName, validProps);
  },
  /**
   * mui prop:
   'flex-start' , 'center' , 'flex-end' , 'space-between' , 'space-around' , 'space-evenly'
   * Defines the justify-content style property. It is applied for all screen sizes.
   */
  justify(props, propName, componentName) {
    const validProps = ['flex-start', 'center', 'flex-end', 'space-between', 'space-around', 'space-evenly'];
    return muiStringProp(props, propName, componentName, validProps);
  },
  /**
   * mui prop:
   false , 'auto' , true , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12
   * Defines the number of grids the component is going to use.
    It's applied for the breakpoint and wider screens if not overridden.
   */
  lg(props, propName, componentName) {
    return muiGridProp(props, propName, componentName);
  },
  /**
   * mui prop: false , 'auto' , true , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12
   * Defines the number of grids the component is going to use.
   It's applied for the breakpoint and wider screens if not overridden.
   */
  md(props, propName, componentName) {
    return muiGridProp(props, propName, componentName);
  },
  /**
   * mui prop: false , 'auto' , true , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12
   * Defines the number of grids the component is going to use.
   It's applied for the breakpoint and wider screens if not overridden.
   */
  sm(props, propName, componentName) {
    return muiGridProp(props, propName, componentName);
  },
  /**
   * mui prop:  0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10
   * Defines the space between the type item component.
   * It can only be used on a type container component.
   */
  // spacing: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  spacing(props, propName, componentName) {
    const validProps = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    return muiBlokNumberProp(props, propName, componentName, validProps);
  },
  /**
   * mui prop: 'nowrap' , 'wrap' , 'wrap-reverse'
   * Defines the flex-wrap style property. It's applied for all screen sizes.
   */
  wrap(props, propName, componentName) {
    const validProps = ['nowrap', 'wrap', 'wrap-reverse'];
    return muiStringProp(props, propName, componentName, validProps);
  },
  /**
   * mui prop: false , 'auto' , true , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12
   * Defines the number of grids the component is going to use.
   It's applied for the breakpoint and wider screens if not overridden.
   */
  xs(props, propName, componentName) {
    return muiGridProp(props, propName, componentName);
  },
  /**
   * mui prop: false , 'auto' , true , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12
   * Defines the number of grids the component is going to use.
   It's applied for the breakpoint and wider screens if not overridden.
   */
  xl(props, propName, componentName) {
    return muiGridProp(props, propName, componentName);
  },

  /**
   * Content passed to from api
   * can also render any customCompnent passed in
   * will render any component in components prop
   */
  content: PropTypes.arrayOf(PropTypes.shape({
    component: PropTypes.string.isRequired,
  })).isRequired,

  /** storyblok prop for when in editor to allow click bridge */
  dataBlokC: PropTypes.string,
  /** storyblok prop for when in editor to allow click bridge */
  dataBlokUid: PropTypes.string,
  /** storyblok prop for when in editor to allow click bridge */
  storyblokClass: PropTypes.string,
  /** Transition desired to apply on grid item. */
  transition: PropTypes.string,
  /**  components to render in the GridItem */
  components: PropTypes.shape(),
  /**
   * mui prop array of: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
   * Hide the given breakpoint(s).
   * */
  only: PropTypes.arrayOf(PropTypes.string),
  /** url for background img */
  backgroundImageUrl: PropTypes.string,
};

GridItem.defaultProps = {
  alignContent: 'stretch',
  alignItems: 'center',
  rootClass: [],
  direction: 'row',
  justify: 'center',
  lg: false,
  md: false,
  sm: false,
  spacing: '0',
  wrap: 'wrap',
  xl: false,
  xs: false,
  dataBlokC: '',
  dataBlokUid: '',
  storyblokClass: '',
  components: {},
  transition: '',
  only: [],
  backgroundImageUrl: '',
};