import React from 'react'; import { StyleSheet, View } from 'react-native'; type Props = { colors: number[]; locations?: number[] | null; startPoint?: Point | null; endPoint?: Point | null; onLayout?: Function; } & React.ComponentProps; type State = { width?: number; height?: number; }; type Point = [number, number]; export default class NativeLinearGradient extends React.PureComponent { state = { width: undefined, height: undefined, }; onLayout = event => { this.setState({ width: event.nativeEvent.layout.width, height: event.nativeEvent.layout.height, }); if (this.props.onLayout) { this.props.onLayout(event); } }; getAngle(): string { const startPoint = this.props.startPoint ? this.props.startPoint : [0.5, 0.0]; const endPoint = this.props.endPoint ? this.props.endPoint : [0.5, 1.0]; const { width = 0, height = 0 } = this.state; let angle = 0; const gradientWidth = height * (endPoint[0] - startPoint[0]); const gradientHeight = width * (endPoint[1] - startPoint[1]); angle = Math.atan2(gradientHeight, gradientWidth) + Math.PI / 2; return `${angle}rad`; } getColors(): string { const { colors } = this.props; return colors .map((color, index) => { const colorStr = `${color.toString(16)}`; const hex = `#${colorStr.substring(2, colorStr.length)}`; const location = this.props.locations && this.props.locations[index]; if (location) { return `${hex} ${location * 100}%`; } return hex; }) .join(','); } getBackgroundImage(): string | null { if (this.state.width && this.state.height) { return `linear-gradient(${this.getAngle()},${this.getColors()})`; } else { return 'transparent'; } } render() { const { colors, locations, startPoint, endPoint, onLayout, style, ...props } = this.props; let compiledStyle = StyleSheet.flatten(style) || {}; const flatStyle = { ...compiledStyle, // @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'. backgroundImage: this.getBackgroundImage(), }; // TODO: Bacon: In the future we could consider adding `backgroundRepeat: "no-repeat"`. For more browser support. return ; } }