From b51f76b463629982f2b5478239bb23c59692a25e Mon Sep 17 00:00:00 2001 From: Caleb Brown Date: Thu, 3 Aug 2017 17:04:04 -0500 Subject: [PATCH 1/8] Update the library. - Take advantage of `defaultProps` - Use props instead of state.config - Fix some validation issues with changing state on component mount - Don't use a cursor if when you cannot edit - Fix prop-types import --- src/react-stars.js | 289 ++++++++++++++++++++------------------------- 1 file changed, 131 insertions(+), 158 deletions(-) diff --git a/src/react-stars.js b/src/react-stars.js index 20d547b..45236b0 100644 --- a/src/react-stars.js +++ b/src/react-stars.js @@ -1,20 +1,19 @@ -import React, { Component, PropTypes } from 'react' +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; const parentStyles = { overflow: 'hidden', position: 'relative' -} +}; const defaultStyles = { position: 'relative', overflow: 'hidden', - cursor: 'pointer', - display: 'block', - float: 'left' -} + display: 'block', + float: 'left' +}; -const getHalfStarStyles = (color, uniqueness) => { - return ` +const getHalfStarStyles = (color, uniqueness) => ` .react-stars-${uniqueness}:before { position: absolute; overflow: hidden; @@ -24,222 +23,196 @@ const getHalfStarStyles = (color, uniqueness) => { width: 50%; content: attr(data-forhalf); color: ${color}; - }` -} + }`; -class ReactStars extends Component { - constructor(props) { +const isDecimal = value => value % 1 !== 0; - super(props) +const moreThanHalf = (event, size) => { + const { target } = event; + let mouseAt = event.clientX - target.getBoundingClientRect().left; + mouseAt = Math.round(Math.abs(mouseAt)); + return mouseAt > size / 2; +}; - // set defaults - - props = Object.assign({}, props) +class ReactStars extends Component { + static displayName = 'ReactStars'; + static defaultProps = { + char: '★', + className: '', + color1: 'gray', + color2: '#ffd700', + count: 5, + edit: true, + half: true, + size: 15, + value: 0, + onChange: () => {} + }; + static propTypes = { + char: PropTypes.string, + className: PropTypes.string, + color1: PropTypes.string, + color2: PropTypes.string, + count: PropTypes.number, + edit: PropTypes.bool, + half: PropTypes.bool, + onChange: PropTypes.func, + size: PropTypes.number, + value: PropTypes.number + }; - if(typeof props.edit === 'undefined') { - props.edit = true - } else { - props.edit = false - } + constructor(props) { + super(props); - if(typeof props.half === 'undefined') { - props.half = true - } else { - props.half = false - } + const { value, half } = this.props; this.state = { - uniqueness: (Math.random() + '').replace('.', ''), - value: props.value || 0, - stars: [], + uniqueness: (`${Math.random()}`).replace('.', ''), + value, + stars: this.getStars(value), halfStar: { - at: Math.floor(props.value), - hidden: props.half && props.value % 1 < 0.5 - } - } - - this.state.config = { - count: props.count || 5, - size: props.size || 15, - char: props.char || '★', - // default color of inactive star - color1: props.color1 || 'gray', - // color of an active star - color2: props.color2 || '#ffd700', - half: props.half, - edit: props.edit, - } - + at: Math.floor(value), + hidden: half && value % 1 < 0.5 + }, + }; } - componentDidMount() { + componentWillReceiveProps(nextProps) { + const { half } = this.props; this.setState({ - stars: this.getStars(this.state.value) - }) - } - - componentWillReceiveProps(props) { - this.setState({ - stars: this.getStars(props.value), - value: props.value, + stars: this.getStars(nextProps.value), + value: nextProps.value, halfStar: { - at: Math.floor(props.value), - hidden: this.state.config.half && props.value % 1 < 0.5 - } - }) - } - - isDecimal(value) { - return value % 1 !== 0 + at: Math.floor(nextProps.value), + hidden: half && nextProps.value % 1 < 0.5 + }, + }); } getRate() { - let stars - if(this.state.config.half) { - stars = Math.floor(this.state.value) - } else { - stars = Math.round(this.state.value) - } - return stars + const { value } = this.state; + return this.props.half ? Math.floor(value) : Math.round(value); } - getStars(activeCount) { - if(typeof activeCount === 'undefined') { - activeCount = this.getRate() - } - let stars = [] - for(let i = 0; i < this.state.config.count; i++) { + getStars(newCount) { + const { count } = this.props; + const activeCount = (typeof newCount === 'undefined') ? this.getRate() : newCount; + const stars = []; + for (let i = 0; i < count; i += 1) { stars.push({ active: i <= activeCount - 1 - }) + }); } - return stars + return stars; } - mouseOver(event) { - let { config, halfStar } = this.state - if(!config.edit) return; - let index = Number(event.target.getAttribute('data-index')) - if(config.half) { - const isAtHalf = this.moreThanHalf(event, config.size) - halfStar.hidden = isAtHalf - if(isAtHalf) index = index + 1 - halfStar.at = index + mouseOver = (event) => { + const { halfStar } = this.state; + const { half, size } = this.props; + let index = Number(event.target.getAttribute('data-index')); + if (half) { + const isAtHalf = moreThanHalf(event, size); + halfStar.hidden = isAtHalf; + if (isAtHalf) index += 1; + halfStar.at = index; } else { - index = index + 1 + index += 1; } this.setState({ stars: this.getStars(index) - }) - } - - moreThanHalf(event, size) { - let { target } = event - var mouseAt = event.clientX - target.getBoundingClientRect().left - mouseAt = Math.round(Math.abs(mouseAt)) - return mouseAt > size / 2 + }); } - mouseLeave() { - const { value, halfStar, config } = this.state - if(!config.edit) return - if(config.half) { - halfStar.hidden = !this.isDecimal(value) - halfStar.at = Math.floor(this.state.value) + mouseLeave = () => { + const { value, halfStar } = this.state; + const { half } = this.props; + if (half) { + halfStar.hidden = !isDecimal(value); + halfStar.at = Math.floor(this.state.value); } this.setState({ stars: this.getStars() - }) + }); } - clicked(event) { - const { config, halfStar } = this.state - if(!config.edit) return - let index = Number(event.target.getAttribute('data-index')) - let value - if(config.half) { - const isAtHalf = this.moreThanHalf(event, config.size) - halfStar.hidden = isAtHalf - if(isAtHalf) index = index + 1 - value = isAtHalf ? index : index + .5 - halfStar.at = index + clicked = (event) => { + const { halfStar } = this.state; + const { half, size } = this.props; + let index = Number(event.target.getAttribute('data-index')); + let value; + if (half) { + const isAtHalf = this.moreThanHalf(event, size); + halfStar.hidden = isAtHalf; + if (isAtHalf) index += 1; + value = isAtHalf ? index : index + 0.5; + halfStar.at = index; } else { - value = index = index + 1 + index += 1; + value = index; } this.setState({ - value: value, + value, stars: this.getStars(index) - }) - this.props.onChange(value) + }); + this.props.onChange(value); } renderHalfStarStyleElement() { - const { config, uniqueness } = this.state + const { uniqueness } = this.state; + const { color2 } = this.props; return ( - - ) +