# All files / mixins triangle.js

100% Statements 10/10
100% Branches 5/5
100% Functions 2/2
100% Lines 9/9

    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

    1x
    7x
    1x
    1x
    1x
    3x

    1x

    1x

    7x

     // @flow

    /**
     * CSS to represent triangle with any pointing direction.
     *
     * @example
     * // Styles as object usage
     *
     * const styles = {
     *   ...triangle({ pointing: 'right', width: '100px', height: '100px', color: 'red' })
     * }
     *
     *
     * // styled-components usage
     * const div = styled.div`
     *   ${triangle({ pointing: 'right', width: '100px', height: '100px', color: 'red' })}
     *
     *
     * // CSS as JS Output
     *
     * div: {
     *  'border-color': 'transparent',
     *  'border-left-color': 'red !important',
     *  'border-style': 'solid',
     *  'border-width': '50px 0 50px 100px',
     *  'height': '0',
     *  'width': '0',
     * }
     */

    type PointingDirection = 'top' | 'right' | 'bottom' | 'left'

    type BorderWidthArgs = {
      height: number,
      width: number,
      pointingDirection: PointingDirection,
    }

    type TriangleArgs = BorderWidthArgs & {
      color: string,
    }

    const getBorderWidth = ({ pointingDirection, height, width } : BorderWidthArgs) => {
      switch (pointingDirection) {
        case 'top': return `0 ${width / 2}px ${height}px ${width / 2}px`
        case 'left': return `${height / 2}px ${width}px ${height / 2}px 0`
        case 'bottom': return `${height}px ${width / 2}px 0 ${width / 2}px`
        case 'right': return `${height / 2}px 0 ${height / 2}px ${width}px`

        default: throw new Error('Passed invalid argument to triangle, please pass correct poitingDirection e.g. \'right\'.')
      }
    }

    // needed for border-color
    const reverseDirection = {
      left: 'right',
      right: 'left',
      top: 'bottom',
      bottom: 'top',
    }

    const triangle = ({ pointingDirection, width, height, color } : TriangleArgs) => ({
      'border-color': 'transparent',
      'width': '0',
      'height': '0',
      'border-width': getBorderWidth({ height, width, pointingDirection }),
      'border-style': 'solid',

      /*
      * javascript Object sorting orders 'border-color' after 'border-bottom-color'
      * (bottom-b) is before (bottom-c) - !important is needed
      * { border-bottom-color: 'red', border-color: 'transparent' }
      */

      [`border-${reverseDirection[pointingDirection]}-color`]: `${color} !important`,
    })

    export default triangle