@deboxsoft/react-native-elements
Version:
React Native Elements & UI Toolkit
367 lines (348 loc) • 9.09 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import {
Platform,
StyleSheet,
Switch,
TouchableHighlight,
View,
} from 'react-native';
import { renderNode, nodeType } from '../helpers';
import { ViewPropTypes, TextPropTypes, withTheme } from '../config';
import Avatar from '../avatar/Avatar';
import Badge from '../badge/badge';
import CheckBox from '../checkbox/CheckBox';
import Icon from '../icons/Icon';
import Text from '../text/Text';
import ButtonGroup from '../buttons/ButtonGroup';
import Input from '../input/Input';
const ANDROID_SECONDARY = 'rgba(0, 0, 0, 0.54)';
const chevronDefaultProps = {
type: Platform.OS === 'ios' ? 'ionicon' : 'material',
color: '#D1D1D6',
name: Platform.OS === 'ios' ? 'ios-arrow-forward' : 'keyboard-arrow-right',
size: 16,
};
const checkmarkDefaultProps = theme => ({
name: 'check',
size: 20,
color: theme.colors.primary,
});
const renderText = (content, defaultProps, style) =>
renderNode(Text, content, {
...defaultProps,
style: StyleSheet.flatten([style, defaultProps && defaultProps.style]),
});
const renderAvatar = content =>
renderNode(Avatar, content, {
size: 40,
rounded: true,
});
const renderIcon = content =>
renderNode(Icon, content, {
color: Platform.OS === 'ios' ? null : ANDROID_SECONDARY,
size: 24,
});
const ListItem = props => {
const {
title,
titleStyle,
titleProps,
subtitle,
subtitleStyle,
subtitleProps,
containerStyle,
onPress,
onLongPress,
Component = onPress || onLongPress ? TouchableHighlight : View,
leftIcon,
leftAvatar,
leftElement,
rightIcon,
rightAvatar,
rightElement,
rightTitle,
rightTitleStyle,
rightTitleProps,
rightSubtitle,
rightSubtitleStyle,
rightSubtitleProps,
input,
buttonGroup,
switch: switchProps, // switch is a reserved keyword
checkBox,
badge,
chevron,
contentContainerStyle,
rightContentContainerStyle,
checkmark,
disabled,
disabledStyle,
bottomDivider,
topDivider,
pad,
linearGradientProps,
ViewComponent = linearGradientProps && global.Expo
? global.Expo.LinearGradient
: View,
theme,
...attributes
} = props;
return (
<Component
{...attributes}
onPress={onPress}
onLongPress={onLongPress}
disabled={disabled}
>
<PadView
Component={ViewComponent}
{...linearGradientProps}
style={StyleSheet.flatten([
styles.container(theme),
(buttonGroup || switchProps) && { paddingVertical: 8 },
topDivider && { borderTopWidth: StyleSheet.hairlineWidth },
bottomDivider && { borderBottomWidth: StyleSheet.hairlineWidth },
containerStyle,
disabled && disabledStyle,
])}
pad={pad}
>
{renderNode(Text, leftElement)}
{renderIcon(leftIcon)}
{renderAvatar(leftAvatar)}
{(title || subtitle) && (
<View
style={StyleSheet.flatten([
styles.contentContainer,
contentContainerStyle,
])}
>
{renderText(
title,
{ testID: 'listItemTitle', ...titleProps },
StyleSheet.flatten([styles.title, titleStyle])
)}
{renderText(
subtitle,
subtitleProps,
StyleSheet.flatten([styles.subtitle, subtitleStyle])
)}
</View>
)}
{(!!rightTitle || !!rightSubtitle) && (
<View
style={StyleSheet.flatten([
styles.rightContentContainer,
rightContentContainerStyle,
])}
>
{renderText(
rightTitle,
rightTitleProps,
StyleSheet.flatten([
styles.title,
styles.rightTitle,
rightTitleStyle,
])
)}
{renderText(
rightSubtitle,
rightSubtitleProps,
StyleSheet.flatten([
styles.subtitle,
styles.rightSubtitle,
rightSubtitleStyle,
])
)}
</View>
)}
{input && (
<Input
{...input}
inputStyle={StyleSheet.flatten([
styles.input,
input && input.inputStyle,
])}
inputContainerStyle={StyleSheet.flatten([
styles.inputContentContainer,
input && input.inputContainerStyle,
])}
containerStyle={StyleSheet.flatten([
styles.inputContainer,
input && input.containerStyle,
])}
/>
)}
{switchProps && <Switch {...switchProps} />}
{checkBox && (
<CheckBox
{...checkBox}
containerStyle={StyleSheet.flatten([
styles.checkboxContainer,
checkBox && checkBox.containerStyle,
])}
/>
)}
{badge && <Badge {...badge} />}
{buttonGroup && (
<ButtonGroup
{...buttonGroup}
containerStyle={StyleSheet.flatten([
styles.buttonGroupContainer,
buttonGroup && buttonGroup.containerStyle,
])}
/>
)}
{renderAvatar(rightAvatar)}
{renderIcon(rightIcon)}
{renderNode(Text, rightElement)}
{renderNode(Icon, checkmark, checkmarkDefaultProps(theme))}
{renderNode(Icon, chevron, chevronDefaultProps)}
</PadView>
</Component>
);
};
const styles = {
container: theme => ({
...Platform.select({
ios: {
padding: 14,
},
default: {
padding: 16,
},
}),
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'white',
borderColor: theme.colors.divider,
}),
title: {
backgroundColor: 'transparent',
...Platform.select({
ios: {
fontSize: 17,
},
default: {
fontSize: 16,
},
}),
},
subtitle: {
backgroundColor: 'transparent',
...Platform.select({
ios: {
fontSize: 15,
},
default: {
color: ANDROID_SECONDARY,
fontSize: 14,
},
}),
},
contentContainer: {
flex: 1,
justifyContent: 'center',
},
rightContentContainer: {
flex: 0.5,
justifyContent: 'center',
alignItems: 'flex-end',
},
inputContainer: {
flex: 1,
},
inputContentContainer: {
flex: 1,
borderBottomWidth: 0,
width: null,
height: null,
},
input: {
flex: 1,
textAlign: 'right',
width: null,
height: null,
marginLeft: 0,
},
checkboxContainer: {
margin: 0,
marginRight: 0,
marginLeft: 0,
padding: 0,
},
buttonGroupContainer: {
flex: 1,
marginLeft: 0,
marginRight: 0,
marginTop: 0,
marginBottom: 0,
},
rightTitle: {
color: ANDROID_SECONDARY,
},
rightSubtitle: {
color: ANDROID_SECONDARY,
},
};
ListItem.propTypes = {
containerStyle: ViewPropTypes.style,
contentContainerStyle: ViewPropTypes.style,
rightContentContainerStyle: ViewPropTypes.style,
Component: PropTypes.func,
onPress: PropTypes.func,
onLongPress: PropTypes.func,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
titleStyle: TextPropTypes.style,
titleProps: PropTypes.object,
subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
subtitleStyle: TextPropTypes.style,
subtitleProps: PropTypes.object,
leftIcon: nodeType,
leftAvatar: nodeType,
leftElement: nodeType,
rightIcon: nodeType,
rightAvatar: nodeType,
rightElement: nodeType,
rightTitle: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
rightTitleStyle: TextPropTypes.style,
rightTitleProps: PropTypes.object,
rightSubtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
rightSubtitleStyle: TextPropTypes.style,
rightSubtitleProps: PropTypes.object,
input: PropTypes.object,
buttonGroup: PropTypes.object,
switch: PropTypes.object,
checkBox: PropTypes.object,
badge: PropTypes.object,
chevron: nodeType,
checkmark: nodeType,
disabled: PropTypes.bool,
disabledStyle: ViewPropTypes.style,
topDivider: PropTypes.bool,
bottomDivider: PropTypes.bool,
pad: PropTypes.number,
linearGradientProps: PropTypes.object,
ViewComponent: PropTypes.func,
theme: PropTypes.object,
};
ListItem.defaultProps = {
pad: 16,
};
const PadView = ({ children, pad, Component, ...props }) => {
const childrens = React.Children.toArray(children);
const length = childrens.length;
const Container = Component || View;
return (
<Container {...props}>
{React.Children.map(
childrens,
(child, index) =>
child && [child, index !== length - 1 && <View width={pad} />]
)}
</Container>
);
};
export { ListItem };
export default withTheme(ListItem, 'ListItem');