UNPKG

react-native-wallet-cards

Version:
145 lines (131 loc) 5.05 kB
import React, { Component } from 'react'; import * as Animatable from 'react-native-animatable'; import { ScrollView, SafeAreaView, TouchableWithoutFeedback, Platform, View } from 'react-native'; import PropTypes from 'prop-types'; import StylesComponent from './style'; export default class CardsWallet extends Component { static propTypes = { data: PropTypes.array.isRequired, cardHeight: PropTypes.number, cardBgColor: PropTypes.string, cardBorderRadius: PropTypes.number, cardShadowColor: PropTypes.string, showCardShadow: PropTypes.bool, cardSeparation: PropTypes.number, cardEasing: PropTypes.string, easingTime: PropTypes.number, autoClose: PropTypes.bool, cardOpenOffset: PropTypes.number, }; static defaultProps = { data: [], cardHeight: 170, cardBgColor: 'white', cardBorderRadius: 10, cardShadowColor: '#000', showCardShadow: true, cardSeparation: 50, cardEasing: 'ease-in-out', easingTime: 300, autoClose: false, cardOpenOffset: 20, }; state = { totalHeight: 0 }; constructor(props) { super(props); this.setProps(); this.cards = this.renderCards(); this.selectedIdx = null; } shouldComponentUpdate(nextProps) { if (nextProps.data === this.props.data) return false; this.setProps(); this.cards = this.renderCards(); return true; } setProps() { // Get styles this.styles = StylesComponent.getSheet(this.props); // Set defaults this.cardSeparation = -this.props.cardHeight + this.props.cardSeparation; this.state.totalHeight = (this.props.data.length * this.props.cardSeparation) + this.props.cardHeight; this.cardsRef = []; this.isCardDisplay = []; // Warnings if (this.props.data.length === 0) { console.warn('prop data has 0 elements and must be an array of components'); } } renderCards() { return this.props.data.map((item, index) => <Animatable.View ref={(ref) => { this.cardsRef[index] = ref; this.isCardDisplay[index] = false; }} key={index} style={[ this.styles.card, this.props.showCardShadow && this.styles.cardShadow, { zIndex: index, top: index * this.cardSeparation, marginBottom: 0 } ]}> <View style={[this.styles.cardContent, Platform.OS === 'android' && this.styles.cardAndroid]}> <TouchableWithoutFeedback onPress={() => this.animateCard(index)}> {item} </TouchableWithoutFeedback> </View> </Animatable.View> ); } animateCard(index) { if (this.props.autoClose && this.selectedIdx !== null && this.selectedIdx !== index && this.isCardDisplay[this.selectedIdx]) { this.animateCard(this.selectedIdx); } this.selectedIdx = index; let marginBottomStart = 0; let marginBottomEnd = this.props.cardHeight - (this.props.cardSeparation - this.props.cardOpenOffset); if (index === this.props.data.length - 1) { marginBottomStart = 0; marginBottomEnd = 0; } else if (this.isCardDisplay[index]) { marginBottomStart = marginBottomEnd; marginBottomEnd = 0; } this.isCardDisplay[index] = !this.isCardDisplay[index]; let totalActive = 1; let totalInactive = 0; if (this.isCardDisplay.length !== (index + 1)) { for (let index in this.isCardDisplay) { totalActive+= this.isCardDisplay[index] ? 1 : 0; totalInactive+= !this.isCardDisplay[index] ? 1 : 0; } const newTotalHeight = totalActive * this.props.cardHeight + (this.props.cardSeparation * totalInactive); this.setState({ totalHeight: newTotalHeight }); } this.cardsRef[index].transition( { marginBottom: marginBottomStart }, { marginBottom: marginBottomEnd }, this.props.easingTime, this.props.cardEasing ); this.forceUpdate(); } render() { return ( <SafeAreaView style={this.styles.safeArea}> <ScrollView style={this.styles.scrollView} showsVerticalScrollIndicator={false} contentContainerStyle={[this.styles.container, { height: this.state.totalHeight }]}> <View style={this.styles.scrollContainer}> { this.cards } </View> </ScrollView> </SafeAreaView> ); } }