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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.