import React from 'react' ; import { Image , ImageURISource , StyleProp , Text , TextInput , TextStyle , TouchableOpacity , View , ViewStyle } from 'react-native' ; import { style as S } from '../styles/Stepper' ; const icons = { increase : require ( '../../assets/images/increaseImage.png' ) , decrease : require ( '../../assets/images/decreaseImage.png' ) } ; const nonNumericRegex = /\D/g ; export interface SerializableStatelessStepperProps { format ? : 'horizontalCenter' | 'horizontalLeft' | 'vertical' ; stepperStyle ? : ViewStyle ; count : number ; countUpperLimit ? : number ; counterStyle ? : TextStyle ; editable ? : boolean ; prefix ? : string ; } export interface StatelessStepperProps extends Omit < SerializableStatelessStepperProps , 'stepperStyle' | 'counterStyle' > { onChange ? : ( count : number ) => void ; stepperStyle ? : StyleProp < ViewStyle > ; counterStyle ? : StyleProp < TextStyle > ; renderText ? : ( text : string , style : StyleProp < TextStyle > , value : number ) => React . ReactNode ; onDecreaseButtonPress : ( count : number ) => void ; decreaseButtonImage ? : ImageURISource ; renderDecreaseButton ? : ( count : number , handlePress : ( ) => void ) => React . ReactNode ; onIncreaseButtonPress : ( count : number ) => void ; increaseButtonImage ? : ImageURISource ; renderIncreaseButton ? : ( count : number , handlePress : ( ) => void ) => React . ReactNode ; } const defaultProps = { increaseButtonImage : icons . increase , decreaseButtonImage : icons . decrease } ; export const StatelessStepper = ( props = defaultProps ) : JSX . Element => { const kButtonTouchabilityOpacity = 0.5 ; const handleDecreasePress = ( ) => { const oldCount = props . count ; const newCount = oldCount && oldCount - 1 ; if ( props . onDecreaseButtonPress && newCount ) { props . onDecreaseButtonPress ( newCount ) ; } if ( props . onChange && newCount ) { props . onChange ( newCount ) ; } } ; const handleIncreasePress = ( ) => { const newCount = props . count && props . count + 1 ; if ( props . onIncreaseButtonPress && newCount ) { props . onIncreaseButtonPress ( newCount ) ; } if ( props . onChange && newCount ) { props . onChange ( newCount ) ; } } ; const renderDecreaseButton = ( style = { } ) => { const { decreaseButtonImage = icons . decrease , renderDecreaseButton , count } = props ; if ( renderDecreaseButton && count ) { return renderDecreaseButton ( count , handleDecreasePress ) ; } return ( < TouchableOpacity accessibilityLabel = 'Decrease' activeOpacity = { kButtonTouchabilityOpacity } disabled = { props . count && props . count <= 0 || true } onPress = { handleDecreasePress } > < Image resizeMode = 'contain' source = { decreaseButtonImage } style = { [ S . buttonImage , style ] } / > < /TouchableOpacity>); } ; const renderIncreaseButton = ( style = { } ) => { const { countUpperLimit , increaseButtonImage = icons . increase , renderIncreaseButton } = props ; if ( renderIncreaseButton && props . count ) { return renderIncreaseButton ( props . count , handleIncreasePress ) ; } return ( < TouchableOpacity accessibilityLabel = 'Increase' activeOpacity = { kButtonTouchabilityOpacity } disabled = { ! countUpperLimit || props . count && props . count >= countUpperLimit || true } onPress = { handleIncreasePress } > < Image resizeMode = 'contain' source = { increaseButtonImage } style = { [ S . buttonImage , style ] } / > < /TouchableOpacity>); } ; const onTextChange = ( text ) => { text = text . replace ( nonNumericRegex , '' ) ; let value = parseInt ( text , 10 ) ; if ( ! isNaN ( value ) ) { if ( props . countUpperLimit && value > props . countUpperLimit ) { value = props . countUpperLimit ; } if ( props . onChange ) { props . onChange ( value ) ; } } } ; const renderText = ( counterStyle , counterText ) => { if ( props . renderText && props . count ) { return props . renderText ( counterText , counterStyle , props . count ) ; } if ( props . editable ) { return ( < TextInput keyboardType = { 'phone-pad' } onChangeText = { onTextChange } style = { counterStyle } value = { counterText } / > ) ; } return ( < Text style = { counterStyle } > { counterText } < /Text>); } ; const renderHorizontalCenter = ( counterText , counterStyle , stepperStyle ) => { return ( < View style = { stepperStyle ? stepperStyle : S . stepperHorizontalContainer } > { renderDecreaseButton ( ) } { renderText ( counterStyle ? counterStyle : S . counterHorizontalCenter , counterText ) } { renderIncreaseButton ( ) } < /View>); } ; const renderHorizontalLeft = ( counterText , counterStyle , stepperStyle ) => { return ( < View style = { stepperStyle ? stepperStyle : S . stepperHorizontalContainer } > { renderText ( counterStyle ? counterStyle : S . counterHorizontalLeft , counterText ) } { renderDecreaseButton ( ) } { renderIncreaseButton ( S . buttonIncreaseHorizontalLeft ) } < /View>); } ; const renderVertical = ( counterText , counterStyle , stepperStyle ) => { return ( < View style = { stepperStyle ? stepperStyle : S . stepperVerticalContainer } > { renderIncreaseButton ( ) } { renderText ( counterStyle ? counterStyle : S . counterVertical , counterText ) } { renderDecreaseButton ( ) } < /View>); } ; const { counterStyle , format , prefix , stepperStyle } = props ; const { count } = props ; const counterText = prefix ? `${ prefix } ${ count }` : `${ count }` ; switch ( format ) { case 'horizontalCenter' : return renderHorizontalCenter ( counterText , counterStyle , stepperStyle ) ; case 'horizontalLeft' : return renderHorizontalLeft ( counterText , counterStyle , stepperStyle ) ; case 'vertical' : return renderVertical ( counterText , counterStyle , stepperStyle ) ; default : return renderHorizontalCenter ( counterText , counterStyle , stepperStyle ) ; } } ;