import color from 'color'; import * as React from 'react'; import { StyleProp, StyleSheet, TextStyle, View, ViewStyle, } from 'react-native'; import TouchableRipple from '../TouchableRipple/TouchableRipple'; import Text from '../Typography/Text'; import { withTheme } from '../../core/theming'; import type { $RemoveChildren, EllipsizeProp } from '../../types'; type Title = | React.ReactNode | ((props: { selectable: boolean; ellipsizeMode: EllipsizeProp | undefined; color: string; fontSize: number; }) => React.ReactNode); type Description = | React.ReactNode | ((props: { selectable: boolean; ellipsizeMode: EllipsizeProp | undefined; color: string; fontSize: number; }) => React.ReactNode); type Props = $RemoveChildren & { /** * Title text for the list item. */ title: Title; /** * Description text for the list item or callback which returns a React element to display the description. */ description?: Description; /** * Callback which returns a React element to display on the left side. */ left?: (props: { color: string; style: { marginLeft: number; marginRight: number; marginVertical?: number; }; }) => React.ReactNode; /** * Callback which returns a React element to display on the right side. */ right?: (props: { color: string; style?: { marginRight: number; marginVertical?: number; }; }) => React.ReactNode; /** * Function to execute on press. */ onPress?: () => void; /** * @optional */ theme: ReactNativePaper.Theme; /** * Style that is passed to the wrapping TouchableRipple element. */ style?: StyleProp; /** * Style that is passed to Title element. */ titleStyle?: StyleProp; /** * Style that is passed to Description element. */ descriptionStyle?: StyleProp; /** * Truncate Title text such that the total number of lines does not * exceed this number. */ titleNumberOfLines?: number; /** * Truncate Description text such that the total number of lines does not * exceed this number. */ descriptionNumberOfLines?: number; /** * Ellipsize Mode for the Title. One of `'head'`, `'middle'`, `'tail'`, `'clip'`. * * See [`ellipsizeMode`](https://reactnative.dev/docs/text#ellipsizemode) */ titleEllipsizeMode?: EllipsizeProp; /** * Ellipsize Mode for the Description. One of `'head'`, `'middle'`, `'tail'`, `'clip'`. * * See [`ellipsizeMode`](https://reactnative.dev/docs/text#ellipsizemode) */ descriptionEllipsizeMode?: EllipsizeProp; }; /** * A component to show tiles inside a List. * *
* * * *
* * ## Usage * ```js * import * as React from 'react'; * import { List } from 'react-native-paper'; * * const MyComponent = () => ( * } * /> * ); * * export default MyComponent; * ``` * * @extends TouchableRipple props https://callstack.github.io/react-native-paper/touchable-ripple.html */ const ListItem = ({ left, right, title, description, onPress, theme, style, titleStyle, titleNumberOfLines = 1, descriptionNumberOfLines = 2, titleEllipsizeMode, descriptionEllipsizeMode, descriptionStyle, ...rest }: Props) => { const renderDescription = ( descriptionColor: string, description?: Description | null ) => { return typeof description === 'function' ? ( description({ selectable: false, ellipsizeMode: descriptionEllipsizeMode, color: descriptionColor, fontSize: styles.description.fontSize, }) ) : ( {description} ); }; const renderTitle = () => { const titleColor = color(theme.colors.text).alpha(0.87).rgb().string(); return typeof title === 'function' ? ( title({ selectable: false, ellipsizeMode: titleEllipsizeMode, color: titleColor, fontSize: styles.title.fontSize, }) ) : ( {title} ); }; const descriptionColor = color(theme.colors.text).alpha(0.54).rgb().string(); return ( {left ? left({ color: descriptionColor, style: description ? styles.iconMarginLeft : { ...styles.iconMarginLeft, ...styles.marginVerticalNone, }, }) : null} {renderTitle()} {description ? renderDescription(descriptionColor, description) : null} {right ? right({ color: descriptionColor, style: description ? styles.iconMarginRight : { ...styles.iconMarginRight, ...styles.marginVerticalNone, }, }) : null} ); }; ListItem.displayName = 'List.Item'; const styles = StyleSheet.create({ container: { padding: 8, }, row: { flexDirection: 'row', }, title: { fontSize: 16, }, description: { fontSize: 14, }, marginVerticalNone: { marginVertical: 0 }, iconMarginLeft: { marginLeft: 0, marginRight: 16 }, iconMarginRight: { marginRight: 0 }, item: { marginVertical: 6, paddingLeft: 8, }, content: { flex: 1, justifyContent: 'center', }, }); export default withTheme(ListItem);