react-native-ui-lib
Version:
<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a
279 lines (248 loc) • 6.53 kB
JavaScript
import _pt from "prop-types";
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import _ from 'lodash';
import * as Modifiers from "../../commons/modifiers";
import { Colors, Spacings, Typography } from "../../style";
import View from "../view";
import Text from "../text";
import TouchableOpacity from "../touchableOpacity";
import Image from "../image";
/**
* @description: A single grid view/list item component
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/GridViewScreen.tsx
*/
class GridListItem extends Component {
static propTypes = {
/**
* Custom GridListItem to be rendered in the GridView
*/
renderCustomItem: _pt.func,
/**
* The item size
*/
itemSize: _pt.oneOfType([_pt.number, _pt.shape({
width: _pt.number,
height: _pt.number
})]),
/**
* Title content text
*/
title: _pt.oneOfType([_pt.string, _pt.element]),
/**
* Title content typography
*/
titleTypography: _pt.string,
/**
* Title content color
*/
titleColor: _pt.string,
/**
* Title content number of lines
*/
titleLines: _pt.number,
/**
* Subtitle content text
*/
subtitle: _pt.oneOfType([_pt.string, _pt.element]),
/**
* Subtitle content typography
*/
subtitleTypography: _pt.string,
/**
* Subtitle content color
*/
subtitleColor: _pt.string,
/**
* Subtitle content number of lines
*/
subtitleLines: _pt.number,
/**
* Description content text
*/
description: _pt.oneOfType([_pt.string, _pt.element]),
/**
* Description content typography
*/
descriptionTypography: _pt.string,
/**
* Description content color
*/
descriptionColor: _pt.string,
/**
* Description content number of lines
*/
descriptionLines: _pt.number,
/**
* Renders the title, subtitle and description inside the item
*/
overlayText: _pt.bool,
/**
* Should content be align to start (default is center)
*/
alignToStart: _pt.bool,
/**
* Renders an overlay on top of the image
*/
renderOverlay: _pt.func,
/**
* Test ID for component
*/
testID: _pt.string
};
static displayName = 'GridListItem';
static defaultProps = {
itemSize: 48
};
state = {};
onItemPress = () => {
this.props.onPress?.(this.props);
};
getItemSizeObj() {
const {
itemSize
} = this.props;
if (_.isPlainObject(itemSize)) {
return itemSize;
}
return {
width: itemSize,
height: itemSize
};
}
renderContent({
text,
typography,
color,
numberOfLines = 1,
style,
testID
}) {
const {
alignToStart
} = this.props;
if (text) {
return <Text testID={testID} // @ts-ignore
style={[style, Typography[typography], color && {
color
}, alignToStart && styles.contentAlignedToStart]} numberOfLines={numberOfLines}>
{text}
</Text>;
}
}
render() {
const {
testID,
imageProps,
alignToStart,
containerStyle,
containerProps,
renderCustomItem,
children,
title,
titleTypography,
titleColor,
titleLines,
overlayText,
overlayTextContainerStyle,
subtitle,
subtitleTypography,
subtitleColor,
subtitleLines,
description,
descriptionTypography,
descriptionColor,
descriptionLines,
onPress,
renderOverlay
} = this.props;
const hasPress = _.isFunction(onPress);
const hasOverlay = _.isFunction(renderOverlay);
const Container = hasPress ? TouchableOpacity : View;
const imageStyle = { ...this.getItemSizeObj()
};
const width = _.get(imageStyle, 'width');
const TextContainer = overlayText ? View : React.Fragment;
const textContainerStyle = overlayText ? {
style: [styles.overlayText, overlayTextContainerStyle]
} : null;
const imageBorderRadius = imageProps?.borderRadius;
return <Container style={[styles.container, alignToStart && styles.containerAlignedToStart, {
width
}, containerStyle]} {...containerProps} onPress={hasPress ? this.onItemPress : undefined} accessible={renderCustomItem ? true : undefined} {...Modifiers.extractAccessibilityProps(this.props)}>
{imageProps && <View style={[{
borderRadius: imageBorderRadius
}, imageStyle]}>
<Image {...imageProps} style={[imageStyle, imageProps?.style]} />
{children}
</View>}
{!_.isNil(renderCustomItem) && <View style={{
width
}}>{renderCustomItem()}</View>}
{hasOverlay && <View style={[styles.overlay, this.getItemSizeObj()]}>{renderOverlay?.()}</View>}
<TextContainer {...textContainerStyle}>
{this.renderContent({
testID: `${testID}.title`,
text: title,
typography: titleTypography,
color: titleColor,
numberOfLines: titleLines,
style: styles.title
})}
{this.renderContent({
testID: `${testID}.subtitle`,
text: subtitle,
typography: subtitleTypography,
color: subtitleColor,
numberOfLines: subtitleLines,
style: styles.subtitle
})}
{this.renderContent({
testID: `${testID}.description`,
text: description,
typography: descriptionTypography,
color: descriptionColor,
numberOfLines: descriptionLines,
style: styles.description
})}
</TextContainer>
</Container>;
}
}
const styles = StyleSheet.create({
container: {
alignSelf: 'flex-start',
alignItems: 'center'
},
containerAlignedToStart: {
alignItems: 'flex-start'
},
title: {
marginTop: Spacings.s1,
textAlign: 'center',
...Typography.bodySmallBold
},
subtitle: {
textAlign: 'center',
...Typography.subtext
},
description: {
textAlign: 'center',
...Typography.subtext,
color: Colors.grey30
},
contentAlignedToStart: {
textAlign: 'left'
},
overlay: {
position: 'absolute',
left: 0,
top: 0
},
overlayText: {
position: 'absolute',
bottom: 10,
left: 10
}
});
export default GridListItem;