react-native-star-rating
Version:
A React Native component for generating and displaying interactive star ratings
191 lines (172 loc) • 4.57 kB
JavaScript
// React and react native imports
import React, { Component } from 'react';
import { View, ViewPropTypes, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import { View as AnimatableView } from 'react-native-animatable';
// Local file imports
import StarButton from './StarButton';
const ANIMATION_TYPES = [
'bounce',
'flash',
'jello',
'pulse',
'rotate',
'rubberBand',
'shake',
'swing',
'tada',
'wobble',
];
const propTypes = {
activeOpacity: PropTypes.number,
animation: PropTypes.oneOf(ANIMATION_TYPES),
buttonStyle: ViewPropTypes.style,
containerStyle: ViewPropTypes.style,
disabled: PropTypes.bool,
emptyStar: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
PropTypes.number,
]),
emptyStarColor: PropTypes.string,
fullStar: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
PropTypes.number,
]),
fullStarColor: PropTypes.string,
halfStar: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
PropTypes.number,
]),
halfStarColor: PropTypes.string,
halfStarEnabled: PropTypes.bool,
// eslint-disable-next-line react/forbid-prop-types
icoMoonJson: PropTypes.object,
iconSet: PropTypes.string,
maxStars: PropTypes.number,
rating: PropTypes.number,
reversed: PropTypes.bool,
starSize: PropTypes.number,
starStyle: ViewPropTypes.style,
selectedStar: PropTypes.func,
};
const defaultProps = {
activeOpacity: 0.2,
animation: undefined,
buttonStyle: {},
containerStyle: {},
disabled: false,
emptyStar: 'star-o',
emptyStarColor: 'gray',
fullStar: 'star',
fullStarColor: 'black',
halfStar: 'star-half-o',
halfStarColor: undefined,
halfStarEnabled: false,
icoMoonJson: undefined,
iconSet: 'FontAwesome',
maxStars: 5,
rating: 0,
reversed: false,
starSize: 40,
starStyle: {},
selectedStar: () => {},
};
class StarRating extends Component {
constructor(props) {
super(props);
this.starRef = [];
this.onStarButtonPress = this.onStarButtonPress.bind(this);
}
onStarButtonPress(rating) {
const { selectedStar } = this.props;
selectedStar(rating);
}
render() {
const {
activeOpacity,
animation,
buttonStyle,
containerStyle,
disabled,
emptyStar,
emptyStarColor,
fullStar,
fullStarColor,
halfStar,
halfStarColor,
halfStarEnabled,
icoMoonJson,
iconSet,
maxStars,
rating,
reversed,
starSize,
starStyle,
} = this.props;
const newContainerStyle = {
flexDirection: reversed ? 'row-reverse' : 'row',
justifyContent: 'space-between',
...StyleSheet.flatten(containerStyle),
};
// Round rating down to nearest .5 star
let starsLeft = Math.round(rating * 2) / 2;
const starButtons = [];
for (let i = 0; i < maxStars; i++) {
let starIconName = emptyStar;
let finalStarColor = emptyStarColor;
if (starsLeft >= 1) {
starIconName = fullStar;
finalStarColor = fullStarColor;
} else if (starsLeft === 0.5) {
starIconName = halfStar;
if (halfStarColor) {
finalStarColor = halfStarColor;
} else {
finalStarColor = fullStarColor;
}
}
const starButtonElement = (
<AnimatableView
key={i}
ref={(node) => { this.starRef.push(node); }}
>
<StarButton
activeOpacity={activeOpacity}
buttonStyle={buttonStyle}
disabled={disabled}
halfStarEnabled={halfStarEnabled}
icoMoonJson={icoMoonJson}
iconSet={iconSet}
onStarButtonPress={(event) => {
if (animation && ANIMATION_TYPES.includes(animation)) {
for (let s = 0; s <= i; s++) {
this.starRef[s][animation](1000 + (s * 200));
}
}
this.onStarButtonPress(event);
}}
rating={i + 1}
reversed={reversed}
starColor={finalStarColor}
starIconName={starIconName}
starSize={starSize}
starStyle={starStyle}
/>
</AnimatableView>
);
starButtons.push(starButtonElement);
starsLeft -= 1;
}
return (
<View style={newContainerStyle} pointerEvents={disabled ? 'none' : 'auto'}>
{starButtons}
</View>
);
}
}
StarRating.propTypes = propTypes;
StarRating.defaultProps = defaultProps;
export default StarRating;