3
\$\begingroup\$

I have taken someone else's HTML and CSS code for grid layouts and reactified it. When converting the code to React, I tried to make it as simpler. I would like to learn from community, if any improvement can be done in the below code or not. If there is any suggestion, improvement, enhancement that can be done, please do suggest me on improving my code which will help me to learn the best practices.

Here is my code

import Cell from './Cell'
import {GridWrapper} from './styled'

const Grid = ({children, ...props}) => {
  return (
    <GridWrapper {...props} data-id="Grid">
      {children}
    </GridWrapper>
  )
}

Grid.propTypes = {
  children  : PropTypes.node.isRequired,
  full      : PropTypes.bool,
  gridAlign : PropTypes.oneOf(['top', 'bottom', 'center', 'right', 'left']),
  gutters   : PropTypes.bool,
  textCenter: PropTypes.bool,
}

Grid.defaultProps = {
  gutters   : true,
  full      : false,
  textCenter: false,
  gridAlign : 'left',
}

Grid.displayName = 'Grid'

Grid.Cell = Cell

Cell.js

const Cell = ({children}) => {
  return <GridCell data-id="GridCell">{children}</GridCell>
}

Cell.propTypes = {
  children: PropTypes.node.isRequired,
}

Cell.displayName = 'Grid.Cell'

styled.js

import styled from 'styled-components'

const colsFirstOfType = ['cols-1of3', 'cols-1of4', 'cols-1of6']

function styleGridAlign(position) {
  // may be hAlign and vAlign tersm will sound best
  switch (position) {
  case 'top':
    return 'align-items: flex-start;'
  case 'bottom':
    return 'align-items: flex-end'
  case 'right':
    return 'justify-content: flex-end'
  case 'left':
    return 'justify-content: flex-start'
  case 'center':
    return 'justify-content: center; align-items: center'
  default:
    return 'flex-start'
  }
}

export const GridCell = styled.div`
  flex: 1;
`

function styleColumn(column, firstOfType) {
  if (firstOfType) {
    switch (column) {
    case 'cols-1of4':
    case 'cols-1of3':
      return '0 0 100%'
    case 'cols-1of6':
      return '0 0 50%'
    default:
      return '0 0 100%'
    }
  } else {
    switch (column) {
    case 'cols-2':
    case 'cols-3':
    case 'cols-4':
      return '0 0 100%'
    case 'cols-6':
      return '0 0 calc(50% - 1em)'
    case 'cols-12':
      return '0 0 calc(33.3333% - 1em)'
    case 'cols-1of2':
      return '0 0 50%'
    default:
      return '0 0 100%'
    }
  }
}

function styleColumnForTablet(column, firstOfType) {
  if (firstOfType) {
    switch (column) {
    case 'cols-1of4':
      return '0 0 50%'
    case 'cols-1of3':
      return '0 0 100%'
    case 'cols-1of6':
      return '0 0 30%'
    default:
      return ''
    }
  } else {
    switch (column) {
    case 'cols-4':
      return '0 0 calc(50% - 1em)%'
    case 'cols-6':
      return '0 0 calc(33.3333% - 1em)'
    case 'cols-12':
      return '0 0 calc(16.6666% - 1em)'
    case 'cols-1of2':
      return '0 0 50%'
    default:
      return ''
    }
  }
}

/* Large screens */
function styleColumnForLargeScreen(column, firstOfType) {
  if (firstOfType) {
    switch (column) {
    case 'cols-1of4':
      return '0 0 25%'
    case 'cols-1of3':
      return '0 0 30%'
    case 'cols-1of6':
      return '0 0 16.6666%'
    default:
      return ''
    }
  } else {
    switch (column) {
    case 'cols-2':
    case 'cols-3':
    case 'cols-4':
    case 'cols-6':
    case 'cols-12':
      return '1'
    case 'cols-1of2':
      return '0 0 50%'
    default:
      return '1'
    }
  }
}

export const GridWrapper = styled.div`
  display: flex;
  flex-flow: row;
  flex-wrap: wrap;

  ${props =>
    props.full &&
    `
    flex: 0 0 100%;
  `}
  ${props =>
    props.nested &&
    `
    ${GridCell}:first-of-type {
      margin-right: 1em;
    }
  `}
  ${props =>
    props.textCenter &&
    `
    text-align: center;
  `}
  ${props =>
    props.gutters &&
    `
    margin-left: -1em;
    ${GridCell} {
      padding-left: 1em;
    }
  `}
  ${props => props.gridAlign && `${styleGridAlign(props.gridAlign)}`};
  ${props =>
    props.col && colsFirstOfType.includes(props.col)
      ? `
      > ${GridCell}:first-of-type {
        flex: ${styleColumn(props.col, true)}
      }
    `
      : `
      > ${GridCell} {
        flex: ${styleColumn(props.col, false)}
      }
    `};
  @media (min-width: 30em) {
    ${props =>
    props.col && colsFirstOfType.includes(props.col)
      ? `
      > ${GridCell}:first-of-type {
        flex: ${styleColumnForTablet(props.col, true)}
      }
    `
      : `
      > ${GridCell} {
        flex: ${styleColumnForTablet(props.col, false)}
      }
    `}
  }
  @media (min-width: 48em) {
    ${props =>
    props.col && colsFirstOfType.includes(props.col)
      ? `
      > ${GridCell}:first-of-type {
        flex: ${styleColumnForLargeScreen(props.col, true)}
      }
    `
      : `
      > ${GridCell} {
        flex: ${styleColumnForLargeScreen(props.col, false)}
      }
    `}
  }
`

Here is the CodeSandbox for demo: https://codesandbox.io/s/ov6k5xnn4q

\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.