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 |