1import React from 'react'; 2import { StyleSheet, View } from 'react-native'; 3 4type Props = { 5 colors: number[]; 6 locations?: number[] | null; 7 startPoint?: Point | null; 8 endPoint?: Point | null; 9 onLayout?: Function; 10} & React.ComponentProps<typeof View>; 11 12type State = { 13 width?: number; 14 height?: number; 15}; 16 17type Point = [number, number]; 18 19export default class NativeLinearGradient extends React.PureComponent<Props, State> { 20 state = { 21 width: undefined, 22 height: undefined, 23 }; 24 25 onLayout = event => { 26 this.setState({ 27 width: event.nativeEvent.layout.width, 28 height: event.nativeEvent.layout.height, 29 }); 30 if (this.props.onLayout) { 31 this.props.onLayout(event); 32 } 33 }; 34 35 getAngle(): string { 36 const startPoint = this.props.startPoint ? this.props.startPoint : [0.5, 0.0]; 37 const endPoint = this.props.endPoint ? this.props.endPoint : [0.5, 1.0]; 38 const { width = 0, height = 0 } = this.state; 39 let angle = 0; 40 41 const gradientWidth = height * (endPoint[0] - startPoint[0]); 42 const gradientHeight = width * (endPoint[1] - startPoint[1]); 43 angle = Math.atan2(gradientHeight, gradientWidth) + Math.PI / 2; 44 45 return `${angle}rad`; 46 } 47 48 getColors(): string { 49 const { colors } = this.props; 50 return colors 51 .map((color, index) => { 52 const colorStr = `${color.toString(16)}`; 53 const hex = `#${colorStr.substring(2, colorStr.length)}`; 54 55 const location = this.props.locations && this.props.locations[index]; 56 if (location) { 57 return `${hex} ${location * 100}%`; 58 } 59 return hex; 60 }) 61 .join(','); 62 } 63 64 getBackgroundImage(): string | null { 65 if (this.state.width && this.state.height) { 66 return `linear-gradient(${this.getAngle()},${this.getColors()})`; 67 } else { 68 return 'transparent'; 69 } 70 } 71 72 render() { 73 const { colors, locations, startPoint, endPoint, onLayout, style, ...props } = this.props; 74 let compiledStyle = StyleSheet.flatten(style) || {}; 75 76 const flatStyle = { 77 ...compiledStyle, 78 // @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'. 79 backgroundImage: this.getBackgroundImage(), 80 }; 81 // TODO: Bacon: In the future we could consider adding `backgroundRepeat: "no-repeat"`. For more browser support. 82 return <View style={flatStyle} onLayout={this.onLayout} {...props} />; 83 } 84} 85