UNPKG

react-native-ui-lib

Version:

[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct.svg)](https://stand-with-ukraine.pp.ua)

151 lines (135 loc) 3.75 kB
import _ from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; import {StyleSheet, Animated} from 'react-native'; import {ViewPropTypes} from 'deprecated-react-native-prop-types'; import {Colors} from '../../style'; import {BaseComponent} from '../../commons'; import View from '../../components/view'; // TODO: add finisher animation (check icon animation or something) /** * @description: Scanner component for progress indication * @extends: Animated.View * @gif: https://media.giphy.com/media/l49JVcxoclUXbryiA/giphy.gif * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/CardScannerScreen.js */ export default class AnimatedScanner extends BaseComponent { static displayName = 'AnimatedScanner'; static propTypes = { /** * animated value between 0 and 100 */ // progress: PropTypes.object, progress: PropTypes.number, /** * Duration of current break (can be change between breaks) */ duration: PropTypes.number, /** * scanner opacity */ opacity: PropTypes.number, /** * scanner background color */ backgroundColor: PropTypes.string, /** * breakpoint callback - ({progress, isDone}) => {} */ onBreakpoint: PropTypes.func, /** * should hide the scanner line */ hideScannerLine: PropTypes.bool, /** * the container style */ containerStyle: ViewPropTypes.style, /** * Used as a testing identifier */ testID: PropTypes.string }; static defaultProps = { progress: 0, duration: 1000 }; constructor(props) { super(props); this.state = { animatedProgress: new Animated.Value(0), isDone: false }; } componentDidMount() { const {progress, duration} = this.props; if (progress > 0) { this.animate(progress, duration); } } generateStyles() { this.styles = createStyles(this.props); } componentDidUpdate(prevProps) { const {progress, duration} = this.props; if (prevProps.progress !== progress) { this.animate(progress, duration); } } componentWillUnmount() { this.state.animatedProgress.stopAnimation(); } animate(toValue, duration) { const {animatedProgress} = this.state; Animated.timing(animatedProgress, { toValue, duration, useNativeDriver: false }).start(({finished}) => { if (finished) { const isDone = toValue >= 100; this.setState({isDone}); _.invoke(this.props, 'onBreakpoint', {progress: toValue, isDone}); } }); } render() { const {opacity, backgroundColor, hideScannerLine, style, containerStyle, testID} = this.props; const {isDone, animatedProgress} = this.state; return ( <View style={[{...StyleSheet.absoluteFillObject}, containerStyle]}> <Animated.View style={[ this.styles.container, style, opacity && {opacity}, backgroundColor && {backgroundColor}, { left: animatedProgress.interpolate({ inputRange: [0, 100], outputRange: ['0%', '100%'] }) } ]} testID={testID} > {isDone && !hideScannerLine && <View style={this.styles.scanner}/>} </Animated.View> </View> ); } } function createStyles() { return StyleSheet.create({ container: { ...StyleSheet.absoluteFillObject, backgroundColor: Colors.white, opacity: 0.9 }, scanner: { ...StyleSheet.absoluteFillObject, borderWidth: StyleSheet.hairlineWidth, borderColor: Colors.grey50 } }); }