All files / mixins radialGradient.js

100% Statements 15/15
100% Branches 22/22
100% Functions 3/3
100% Lines 14/14
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 81 82                        4x       5x 5x 25x   25x 4x 4x   21x 1x   20x 7x     5x                                                                                   6x 5x              
// @flow
 
/** */
type RadialGradientConfiguration = {
  colorStops: Array<string>;
  extent?: string;
  fallback?: string;
  position?: string;
  shape?: string;
};
 
function parseFallback(colorStops: Array<string>) {
  return colorStops[0].split(' ')[0]
}
 
function constructGradientValue(literals: Array<string>, ...substitutions: Array<string>) {
  let template = ''
  for (let i = 0; i < literals.length; i += 1) {
    template += literals[i]
    // Adds leading coma if properties preceed color-stops
    if ((i === 3 && substitutions[i]) && (substitutions[0] || substitutions[1] || substitutions[2])) {
      template = template.slice(0, -1)
      template += `, ${substitutions[i]}`
    // No trailing space if color-stops is the only param provided
    } else if ((i === 3 && substitutions[i]) && (!substitutions[0] && !substitutions[1] && !substitutions[2])) {
      template += `${substitutions[i]}`
    // Only adds substitution if it is defined
    } else if (substitutions[i]) {
      template += `${substitutions[i]} `
    }
  }
  return template.trim()
}
 
/**
 * CSS for declaring a radial gradient, including a fallback background-color. The fallback is either the first color-stop or an explicitly passed fallback color.
 *
 * @example
 * // Styles as object usage
 * const styles = {
 *   ...radialGradient({
 *     colorStops: ['#00FFFF 0%', 'rgba(0, 0, 255, 0) 50%', '#0000FF 95%'],
 *     extent: 'farthest-corner at 45px 45px',
 *     position: 'center',
 *     shape: 'ellipse',
 *   })
 * }
 *
 * // styled-components usage
 * const div = styled.div`
 *   ${radialGradient({
 *     colorStops: ['#00FFFF 0%', 'rgba(0, 0, 255, 0) 50%', '#0000FF 95%'],
 *     extent: 'farthest-corner at 45px 45px',
 *     position: 'center',
 *     shape: 'ellipse',
 *   })}
 *`
 *
 * // CSS as JS Output
 *
 * div: {
 *   'background-color': '#00FFFF',
 *   'background-image': 'radial-gradient(center ellipse farthest-corner at 45px 45px, #00FFFF 0%, rgba(0, 0, 255, 0) 50%, #0000FF 95%)',
 * }
 */
 
function radialGradient({
  colorStops,
  extent,
  fallback,
  position,
  shape,
}: RadialGradientConfiguration) {
  if (!colorStops || colorStops.length < 2) throw new Error('radialGradient requries at least 2 color-stops to properly render.')
  return {
    'background-color': fallback || parseFallback(colorStops),
    'background-image': constructGradientValue`radial-gradient(${position}${shape}${extent}${colorStops.join(', ')})`,
  }
}
 
export default radialGradient