Created
April 27, 2017 14:55
-
-
Save alien3d/1d3100ca43e643a8e8ab83a636415370 to your computer and use it in GitHub Desktop.
react native element list item
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {PropTypes, Component} from 'react'; | |
import { | |
ScrollView, | |
View, | |
StyleSheet, | |
TouchableHighlight, | |
Image, | |
Platform, | |
Switch, | |
TextInput, | |
DatePickerAndroid, | |
DatePickerIOS, | |
TimePickerAndroid, | |
TouchableWithoutFeedback, | |
TouchableOpacity | |
} from 'react-native'; | |
import Badge from '../badge/badge'; | |
import Icon from '../icons/Icon'; | |
import Text from '../text/Text'; | |
import colors from '../config/colors'; | |
import fonts from '../config/fonts'; | |
import normalize from '../helpers/normalizeText'; | |
import Moment from 'moment'; | |
let styles; | |
const FORMATS = { | |
'date': 'YYYY-MM-DD', | |
'datetime': 'YYYY-MM-DD HH:mm', | |
'time': 'HH:mm' | |
}; | |
class ListItem extends Component { | |
constructor(props) { | |
super(props); | |
var date = new Date(); | |
this.state = { | |
currentDate: date, | |
currentDateTime: date.getFullYear() + (date.getMonth() + 1) + date.getDay() + " " + date.getHours + ":" + date.getMinutes(), | |
currentTime: this._formatTime(date.getHours(), + date.getMinutes()), | |
currentHour: date.getHours(), | |
currentMinute: date.getMinutes(), | |
is24Hour: false | |
} | |
} | |
showPickerAndroid = async(options) => { | |
try { | |
var newState = {}; | |
const {action, year, month, day} = await DatePickerAndroid.open(options); | |
if (action === DatePickerAndroid.dismissedAction) { | |
newState['currentText'] = 'dismissed'; | |
} else { | |
var date = new Date(year, month, day); | |
newState['currentText'] = date.toLocaleDateString(); | |
newState['currentDate'] = date; | |
this | |
.props | |
.textInputDateOnChange(date); | |
} | |
this.setState(newState); | |
} catch ({code, message}) { | |
console.warn(`Error `, message); | |
} | |
}; | |
showTimePickerAndroid = async(options) => { | |
console.log(options) | |
try { | |
const {action, minute, hour} = await TimePickerAndroid.open(options); | |
var newState = {}; | |
if (action === TimePickerAndroid.timeSetAction) { | |
newState['currentTime'] = this._formatTime(hour, minute); | |
newState['currentHour'] = hour; | |
newState['currentMinute'] = minute; | |
this | |
.props | |
.textInputTimeOnChange(this._formatTime(hour, minute)); | |
} else if (action === TimePickerAndroid.dismissedAction) { | |
newState['currentText'] = 'dismissed'; | |
} | |
this.setState(newState); | |
} catch ({code, message}) { | |
console.warn(`Error `, message); | |
} | |
}; | |
_formatTime(hour, minute) { | |
return hour + ':' + (minute < 10 | |
? '0' + minute | |
: minute); | |
} | |
/** | |
* Format Date. Either using default or pre-defined | |
* @param {object} date | |
* @param {type} dateType | |
* @param {object} format | |
* @returns {string} date | |
*/ | |
_formatDate(date, type, format) { | |
dateParse = null; | |
// if js can do like this.. could be shorter FORMATS.{type} ? | |
var dateParse = null; | |
// use pre defined format | |
if (typeof format !== 'object') { | |
switch (type) { | |
case "date": | |
dateParse = Moment(date, FORMATS.date).format(FORMATS.date); | |
break; | |
case "datetime": | |
dateParse = Moment(date, FORMATS.datetime).format(FORMATS.datetime); | |
break; | |
case "time": | |
dateParse = Moment(date, FORMATS.time).format(FORMATS.time); | |
break; | |
case "hour": | |
if (date.length == 1) { | |
dateParse = "0".date; | |
} else { | |
dataParse = date; | |
} | |
break; | |
case "minute": | |
if (date.length == 1) { | |
dateParse = "0".date; | |
} else { | |
dataParse = date; | |
} | |
break; | |
default: | |
dateParse = "1.4 : unknown custom date"; | |
} | |
} else { | |
switch (type) { | |
case "date": | |
dateParse = Moment(date, format.date); | |
break; | |
case "datetime": | |
dateParse = Moment(date, format.datetime); | |
break; | |
case "time": | |
dateParse = Moment(date, format.time); | |
break; | |
case "hour": | |
if (date.length == 1) { | |
dateParse = "0".date; | |
} else { | |
dataParse = date; | |
} | |
break; | |
case "minute": | |
if (date.length == 1) { | |
dateParse = "0".date; | |
} else { | |
dataParse = date; | |
} | |
break; | |
default: | |
dateParse = "2.4 unknown custom date"; | |
} | |
} | |
return dateParse; | |
} | |
/** | |
* TextInput Focus | |
* @returns {void} | |
*/ | |
focus() { | |
const ref = this.props.textInputRef; | |
this | |
.refs[ref] | |
.focus(); | |
} | |
/** | |
* TextInput Blur | |
* @returns {void} | |
*/ | |
blur() { | |
const ref = this.props.textInputRef; | |
this | |
.refs[ref] | |
.blur(); | |
} | |
/** | |
* Switch Value | |
* @param {bool} value | |
*/ | |
_onSwitchChange(value) { | |
this | |
.props | |
.switchOnChange(value); | |
} | |
render() { | |
const { | |
onPress, | |
title, | |
leftIcon, | |
rightIcon, | |
leftIconContainerStyle, | |
avatarStyle, | |
underlayColor, | |
subtitle, | |
subtitleStyle, | |
containerStyle, | |
wrapperStyle, | |
titleStyle, | |
titleContainerStyle, | |
hideChevron, | |
chevronColor, | |
chevronOnPress, | |
roundAvatar, | |
component, | |
fontFamily, | |
rightTitle, | |
rightTitleContainerStyle, | |
rightTitleStyle, | |
subtitleContainerStyle, | |
badge, | |
badgeContainerStyle, | |
badgeTextStyle, | |
label, | |
onLongPress, | |
switchButton, | |
onSwitch, | |
switchDisabled, | |
switchOnTintColor, | |
switchThumbTintColor, | |
switchTintColor, | |
switched, | |
textInput, | |
textInputRef, | |
textInputSecureTextEntry, | |
textInputAutoCapitalize, | |
textInputAutoCorrect, | |
textInputFocus, | |
textInputAutoFocus, | |
textInputEditable, | |
textInputKeyboardType, | |
textInputMaxLength, | |
textInputMultiline, | |
textInputOnChangeText, | |
textInputOnFocus, | |
textInputOnBlur, | |
textInputOnSubmitEditing, | |
textInputSelectTextOnFocus, | |
textInputReturnKeyType, | |
textInputValue, | |
textInputStyle, | |
textInputContainerStyle, | |
textInputPlaceHolder, | |
textInputHour, | |
textInputHourFormat, | |
textInputMinute, | |
textInputMinuteFormat, | |
textInputTime, | |
textInputTimeFormat, | |
textInputTimeIs24Hour, | |
textInputDate, | |
textInputDateFormat, | |
textInputDateMode, | |
textInputDateMinDate, | |
textInputDateMaxDate, | |
textInputDateTime, | |
textInputDateTimeFormat, | |
...attributes | |
} = this.props; | |
let {avatar} = this.props; | |
if (typeof avatar === 'string') { | |
avatar = { | |
uri: avatar | |
} | |
} | |
if (typeof textInputDate === "string") { | |
// just double recheck from props.. | |
if (textInputDate.length > 0) { | |
// check valid date and is format | |
if (Moment(textInputDate, textInputDateFormat, true).isValid()) { | |
this.setState({currentDate: textInputDate}); | |
} else { | |
console.log("Date give is not in right format. Date : " + textInputDate + " Format " + textInputDateFormat); | |
} | |
} | |
} | |
if (typeof textInputDateTime === "string") { | |
// just double recheck from props.. | |
if (textInputDateTime.length > 0) { | |
// check valid date and is format | |
if (Moment(textInputDateTime, textInputDateTimeFormat, true).isValid()) { | |
this.setState({currentDateTime: textInputDateTime}); | |
} else { | |
console.log("Date give is not in right format. Date : " + textInputDateTime + " Format " + textInputDateTimeFormat); | |
} | |
} | |
} | |
if (typeof textInputHour === "string") { | |
if (textInputHour.length > 0) { | |
if (Moment(textInputHour, textInputHourFormat, true).isValid()) { | |
this.setState({currentHour: textInputHour}); | |
} | |
} | |
} | |
// unknown yet output should be | |
if (typeof textInputMinute === "string") { | |
if (textInputMinute.length > 0) { | |
if (Moment(textInputHour, textInputTimeFormat, true).isValid()) { | |
this.setState({currentMinute: textInputMinute}); | |
} | |
} | |
} | |
if (typeof textInputTimeIs24Hour === "string") { | |
// just double recheck from props.. | |
if (textInputTimeIs24Hour.length > 0) { | |
if (textInputTimeIs24Hour == "true" || textInputTimeIs24Hour == "false" || textInputTimeIs24Hour == true || textInputTimeIs24Hour == false) { | |
this.setState({is24Hour: textInputTimeIs24Hour}); | |
} | |
} | |
} | |
return ( | |
<TouchableHighlight | |
onLongPress={onLongPress} | |
onPress={onPress} | |
underlayColor={underlayColor} | |
style={[ | |
styles.container, containerStyle && containerStyle | |
]} | |
{...attributes}> | |
<View | |
style={[ | |
styles.wrapper, wrapperStyle && wrapperStyle | |
]}> | |
{leftIcon && leftIcon.name && ( | |
<View | |
style={[ | |
styles.iconStyle, leftIconContainerStyle && leftIconContainerStyle | |
]}><Icon | |
type={leftIcon.type} | |
iconStyle={[ | |
styles.icon, leftIcon.style && leftIcon.style | |
]} | |
name={leftIcon.name} | |
color={leftIcon.color || colors.grey4} | |
size={leftIcon.size || 24}/> | |
</View> | |
) | |
} | |
{avatar && (<Image | |
style={[ | |
styles.avatar, roundAvatar && { | |
borderRadius: 17 | |
}, | |
avatarStyle && avatarStyle | |
]} | |
source={avatar}/>) | |
} | |
<View style={styles.titleSubtitleContainer}> | |
<View style={titleContainerStyle}> | |
{(title && (typeof title === 'string' || typeof title === 'number')) | |
? ( | |
<Text | |
style={[ | |
styles.title, !leftIcon && { | |
marginLeft: 10 | |
}, | |
titleStyle && titleStyle, | |
fontFamily && { | |
fontFamily | |
} | |
]}>{title}</Text> | |
) | |
: ( | |
<View> | |
{title} | |
</View> | |
)} | |
</View> | |
<View style={subtitleContainerStyle}> | |
{(subtitle && (typeof subtitle === 'string' || typeof subtitle === 'number')) | |
? ( | |
<Text | |
style={[ | |
styles.subtitle, !leftIcon && { | |
marginLeft: 10 | |
}, | |
subtitleStyle && subtitleStyle, | |
fontFamily && { | |
fontFamily | |
} | |
]}>{subtitle}</Text> | |
) | |
: ( | |
<View> | |
{subtitle} | |
</View> | |
)} | |
</View> | |
</View> | |
{rightTitle && (rightTitle !== '') && !textInput && ( | |
<View style={[styles.rightTitleContainer, rightTitleContainerStyle]}> | |
<Text style={[styles.rightTitleStyle, rightTitleStyle]}>{rightTitle}</Text> | |
</View> | |
) | |
} | |
{textInput && ( | |
<View style={textInputContainerStyle}> | |
<TextInput | |
ref={textInputRef} | |
secureTextEntry={textInputSecureTextEntry} | |
underlineColorAndroid='transparent' | |
style={textInputStyle} | |
defaultValue={rightTitle} | |
value={textInputValue} | |
autoCapitalize={textInputAutoCapitalize} | |
autoCorrect={textInputAutoCorrect} | |
autoFocus={textInputAutoFocus} | |
focus={textInputFocus} | |
editable={textInputEditable} | |
keyboardType={textInputKeyboardType} | |
maxLength={textInputMaxLength} | |
multiline={textInputMultiline} | |
onChangeText={textInputOnChangeText} | |
onFocus={textInputOnFocus} | |
onBlur={textInputOnBlur} | |
onSubmitEditing={textInputOnSubmitEditing} | |
selectTextOnFocus={textInputSelectTextOnFocus} | |
returnKeyType={textInputReturnKeyType} | |
placeholder={textInputPlaceHolder}/> | |
</View> | |
) | |
} | |
{Platform.OS === 'android' && textInputDate && ( | |
<View style={textInputContainerStyle}> | |
<TouchableWithoutFeedback | |
onPress={this | |
.showPickerAndroid | |
.bind(this, { | |
date: this.state.currentDate, | |
mode: textInputDateMode, | |
minDate: textInputDateMinDate, | |
maxDate: textInputDateMaxDate | |
})}> | |
<View style={styles.datePickerStyle}> | |
<Text>{this._formatDate(this.state.currentDate, "date", textInputDateFormat)}</Text> | |
</View> | |
</TouchableWithoutFeedback> | |
</View> | |
) | |
} | |
{Platform.OS === 'android' && textInputDateTime && ( | |
<View style={textInputContainerStyle}> | |
<Text>Sorry not supported yet by react native | |
</Text> | |
</View> | |
) | |
} | |
{Platform.OS === 'android' && textInputTime && ( | |
<View style={textInputContainerStyle}> | |
<TouchableWithoutFeedback | |
onPress={this | |
.showTimePickerAndroid | |
.bind(this, { | |
hour: this.state.currentHour, | |
minute: this.state.currentMinute, | |
is24Hour: this.state.is24Hour | |
})}> | |
<View style={styles.datePickerStyle}> | |
<Text>{this.state.currentTime}</Text> | |
</View> | |
</TouchableWithoutFeedback> | |
</View> | |
) | |
} | |
{Platform.OS === 'ios' && TextInputDate( | |
<View> | |
<Text>Wait on going | |
</Text> | |
</View> | |
) | |
} | |
{Platform.OS === 'ios' && TextInputDateTime( | |
<View> | |
<Text>Wait on going | |
</Text> | |
</View> | |
) | |
} | |
{Platform.OS === 'ios' && TextInputTime( | |
<View> | |
<Text>Wait on going | |
</Text> | |
</View> | |
) | |
} | |
{!hideChevron && ( | |
<View style={styles.chevronContainer} onPress={chevronOnPress}> | |
<Icon | |
type={rightIcon.type} | |
iconStyle={rightIcon.style} | |
size={28} | |
name={rightIcon.name || 'chevron-right'} | |
color={rightIcon.color || chevronColor}/> | |
</View> | |
) | |
} | |
{switchButton && hideChevron && ( | |
<View style={styles.switchContainer}> | |
<Switch | |
onValueChange={this | |
._onSwitchChange | |
.bind(this)} | |
style={{ | |
marginBottom: 10 | |
}} | |
disabled={switchDisabled} | |
onTintColor={switchOnTintColor} | |
thumbTintColor={switchThumbTintColor} | |
tintColor={switchTintColor} | |
value={switched}/> | |
</View> | |
) | |
} | |
{badge && !rightTitle && (<Badge badge={badge}/>) | |
} | |
{label && label | |
} | |
</View> | |
</TouchableHighlight> | |
) | |
} | |
}; | |
ListItem.defaultProps = { | |
underlayColor: 'white', | |
chevronColor: colors.grey4, | |
rightIcon: { | |
name: 'chevron-right' | |
}, | |
hideChevron: false, | |
roundAvatar: false, | |
textInputEditable: true | |
} | |
ListItem.propTypes = { | |
title: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]), | |
avatar: PropTypes.object, | |
icon: PropTypes.any, | |
onPress: PropTypes.func, | |
rightIcon: PropTypes.object, | |
underlayColor: PropTypes.string, | |
subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]), | |
subtitleStyle: PropTypes.any, | |
containerStyle: PropTypes.any, | |
wrapperStyle: PropTypes.any, | |
titleStyle: PropTypes.any, | |
titleContainerStyle: PropTypes.any, | |
hideChevron: PropTypes.bool, | |
chevronColor: PropTypes.string, | |
roundAvatar: PropTypes.bool, | |
badge: PropTypes.any, | |
switchButton: PropTypes.bool, | |
onSwitch: PropTypes.func, | |
switchDisabled: PropTypes.bool, | |
switchOnTintColor: PropTypes.string, | |
switchThumbTintColor: PropTypes.string, | |
switchTintColor: PropTypes.string, | |
switched: PropTypes.bool, | |
textInput: PropTypes.bool, | |
textInputAutoCapitalize: PropTypes.bool, | |
textInputAutoCorrect: PropTypes.bool, | |
textInputAutoFocus: PropTypes.bool, | |
textInputEditable: PropTypes.bool, | |
textInputKeyboardType: PropTypes.oneOf([ | |
'default', | |
'email-address', | |
'numeric', | |
'phone-pad', | |
'ascii-capable', | |
'numbers-and-punctuation', | |
'url', | |
'number-pad', | |
'name-phone-pad', | |
'decimal-pad', | |
'twitter', | |
'web-search' | |
]), | |
textInputMaxLength: PropTypes.number, | |
textInputMultiline: PropTypes.bool, | |
textInputOnChangeText: PropTypes.func, | |
textInputOnFocus: PropTypes.func, | |
textInputOnBlur: PropTypes.func, | |
textInputSelectTextOnFocus: PropTypes.bool, | |
textInputReturnKeyType: PropTypes.string, | |
textInputValue: PropTypes.string, | |
textInputStyle: PropTypes.any, | |
textInputContainerStyle: PropTypes.any, | |
textInputDate: PropTypes.any, | |
textInputDateMinDate: PropTypes.any, | |
textInputDateMaxDate: PropTypes.any, | |
textInputDateTime: PropTypes.any, | |
textInputTime: PropTypes.any, | |
textInputHour: PropTypes.number, | |
textInputMinute: PropTypes.number, | |
textInputHourFormat: PropTypes.string, | |
textInputMinuteFormat: PropTypes.string, | |
textInputTimeIs24Hour: PropTypes.bool, | |
textInputDateOnChange: PropTypes.func, | |
textInputDateMode: PropTypes.oneOf(['default', 'calendar', 'spinner', 'default']), | |
textInputDateIosMode: PropTypes.oneOf(['date', 'time', 'datetime']), | |
switchOnChange: PropTypes.func, | |
chevronOnPress: PropTypes.func | |
}; | |
styles = StyleSheet.create({ | |
avatar: { | |
width: 34, | |
height: 34 | |
}, | |
container: { | |
paddingTop: 10, | |
paddingRight: 10, | |
paddingBottom: 10, | |
borderBottomColor: '#ededed', | |
borderBottomWidth: 1, | |
backgroundColor: 'transparent' | |
}, | |
wrapper: { | |
flexDirection: 'row', | |
marginLeft: 10 | |
}, | |
iconStyle: { | |
flex: 0.15, | |
justifyContent: 'center', | |
alignItems: 'center' | |
}, | |
icon: { | |
marginRight: 8 | |
}, | |
title: { | |
fontSize: normalize(14), | |
color: colors.grey1 | |
}, | |
subtitle: { | |
color: colors.grey3, | |
fontSize: normalize(12), | |
marginTop: 1, | |
...Platform.select({ | |
ios: { | |
fontWeight: '600' | |
}, | |
android: { | |
...fonts.android.bold | |
} | |
}) | |
}, | |
titleSubtitleContainer: { | |
justifyContent: 'center', | |
flex: 1 | |
}, | |
chevronContainer: { | |
flex: 0.3, | |
alignItems: 'flex-end', | |
justifyContent: 'center' | |
}, | |
switchContainer: { | |
flex: 0.15, | |
alignItems: 'flex-end', | |
justifyContent: 'center', | |
marginRight: 5 | |
}, | |
rightTitleContainer: { | |
flex: 1, | |
alignItems: 'flex-end', | |
justifyContent: 'center' | |
}, | |
rightTitleStyle: { | |
marginRight: 5, | |
color: colors.grey4 | |
}, | |
datePickerStyle: { | |
alignItems: 'flex-start', | |
flex: 1 | |
} | |
}); | |
export default ListItem; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment