react-rating-stars-component
Advanced tools
Comparing version 1.0.3 to 1.1.0
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -11,7 +11,7 @@ Object.defineProperty(exports, "__esModule", { | ||
var _react = require('react'); | ||
var _react = require("react"); | ||
var _react2 = _interopRequireDefault(_react); | ||
var _propTypes = require('prop-types'); | ||
var _propTypes = require("prop-types"); | ||
@@ -29,19 +29,19 @@ var _propTypes2 = _interopRequireDefault(_propTypes); | ||
var parentStyles = { | ||
overflow: 'hidden', | ||
position: 'relative' | ||
overflow: "hidden", | ||
position: "relative" | ||
}; | ||
var defaultStyles = { | ||
position: 'relative', | ||
overflow: 'hidden', | ||
cursor: 'pointer', | ||
display: 'block', | ||
float: 'left' | ||
position: "relative", | ||
overflow: "hidden", | ||
cursor: "pointer", | ||
display: "block", | ||
float: "left" | ||
}; | ||
var getHalfStarStyles = function getHalfStarStyles(color, uniqueness) { | ||
return '\n .react-stars-' + uniqueness + ':before {\n position: absolute;\n overflow: hidden;\n display: block;\n z-index: 1;\n top: 0; left: 0;\n width: 50%;\n content: attr(data-forhalf);\n color: ' + color + ';\n }'; | ||
return "\n .react-stars-" + uniqueness + ":before {\n position: absolute;\n overflow: hidden;\n display: block;\n z-index: 1;\n top: 0; left: 0;\n width: 50%;\n content: attr(data-forhalf);\n color: " + color + ";\n }"; | ||
}; | ||
var getHalfStarStyleForIcons = function getHalfStarStyleForIcons(color) { | ||
return '\n span.react-stars-half > * {\n color: ' + color + ';\n }'; | ||
return "\n span.react-stars-half > * {\n color: " + color + ";\n }"; | ||
}; | ||
@@ -62,3 +62,3 @@ | ||
_this.state = { | ||
uniqueness: (Math.random() + '').replace('.', ''), | ||
uniqueness: (Math.random() + "").replace(".", ""), | ||
value: props.value || 0, | ||
@@ -85,5 +85,5 @@ stars: [], | ||
halfIcon: props.halfIcon, | ||
filledIcon: props.filledIcon | ||
filledIcon: props.filledIcon, | ||
a11y: props.a11y | ||
}; | ||
return _this; | ||
@@ -93,3 +93,3 @@ } | ||
_createClass(ReactStars, [{ | ||
key: 'componentDidMount', | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
@@ -101,3 +101,3 @@ this.setState({ | ||
}, { | ||
key: 'componentWillReceiveProps', | ||
key: "componentWillReceiveProps", | ||
value: function componentWillReceiveProps(props) { | ||
@@ -123,3 +123,3 @@ this.setState({ | ||
}, { | ||
key: 'isDecimal', | ||
key: "isDecimal", | ||
value: function isDecimal(value) { | ||
@@ -129,3 +129,3 @@ return value % 1 !== 0; | ||
}, { | ||
key: 'getRate', | ||
key: "getRate", | ||
value: function getRate() { | ||
@@ -141,5 +141,5 @@ var stars = void 0; | ||
}, { | ||
key: 'getStars', | ||
key: "getStars", | ||
value: function getStars(activeCount) { | ||
if (typeof activeCount === 'undefined') { | ||
if (typeof activeCount === "undefined") { | ||
activeCount = this.getRate(); | ||
@@ -156,3 +156,3 @@ } | ||
}, { | ||
key: 'mouseOver', | ||
key: "mouseOver", | ||
value: function mouseOver(event) { | ||
@@ -164,3 +164,3 @@ var _state = this.state, | ||
if (!config.edit) return; | ||
var index = Number(event.currentTarget.getAttribute('data-index')); | ||
var index = Number(event.currentTarget.getAttribute("data-index")); | ||
if (config.half) { | ||
@@ -179,3 +179,3 @@ var isAtHalf = this.moreThanHalf(event, config.size); | ||
}, { | ||
key: 'moreThanHalf', | ||
key: "moreThanHalf", | ||
value: function moreThanHalf(event, size) { | ||
@@ -189,3 +189,3 @@ var target = event.target; | ||
}, { | ||
key: 'mouseLeave', | ||
key: "mouseLeave", | ||
value: function mouseLeave() { | ||
@@ -207,3 +207,3 @@ var _state2 = this.state, | ||
}, { | ||
key: 'clicked', | ||
key: "clicked", | ||
value: function clicked(event) { | ||
@@ -215,3 +215,3 @@ var _state3 = this.state, | ||
if (!config.edit) return; | ||
var index = Number(event.currentTarget.getAttribute('data-index')); | ||
var index = Number(event.currentTarget.getAttribute("data-index")); | ||
var value = void 0; | ||
@@ -222,3 +222,3 @@ if (config.half) { | ||
if (isAtHalf) index = index + 1; | ||
value = isAtHalf ? index : index + .5; | ||
value = isAtHalf ? index : index + 0.5; | ||
halfStar.at = index; | ||
@@ -235,3 +235,3 @@ } else { | ||
}, { | ||
key: 'renderHalfStarStyleElement', | ||
key: "renderHalfStarStyleElement", | ||
value: function renderHalfStarStyleElement() { | ||
@@ -243,17 +243,59 @@ var _state4 = this.state, | ||
return _react2.default.createElement('style', { dangerouslySetInnerHTML: { | ||
return _react2.default.createElement("style", { | ||
dangerouslySetInnerHTML: { | ||
__html: isUsingIcons ? getHalfStarStyleForIcons(config.color2) : getHalfStarStyles(config.color2, uniqueness) | ||
} }); | ||
} | ||
}); | ||
} | ||
}, { | ||
key: 'renderStars', | ||
value: function renderStars() { | ||
key: "handleKeyDown", | ||
value: function handleKeyDown(event) { | ||
var _this2 = this; | ||
var key = event.key; | ||
var _state5 = this.state, | ||
halfStar = _state5.halfStar, | ||
stars = _state5.stars, | ||
uniqueness = _state5.uniqueness, | ||
config = _state5.config, | ||
isUsingIcons = _state5.isUsingIcons; | ||
value = _state5.value, | ||
config = _state5.config; | ||
var keyNumber = Number(key); // e.g. "1" => 1, "ArrowUp" => NaN | ||
if (keyNumber) { | ||
// number | ||
if (Number.isInteger(keyNumber) && keyNumber > 0 && keyNumber <= config.count) { | ||
value = keyNumber; | ||
} | ||
} else { | ||
// string | ||
if ((key === "ArrowUp" || key === "ArrowRight") && value < config.count) { | ||
event.preventDefault(); | ||
value += config.half ? 0.5 : 1; | ||
} else if ((key === "ArrowDown" || key === "ArrowLeft") && value > 0.5) { | ||
event.preventDefault(); | ||
value -= config.half ? 0.5 : 1; | ||
} | ||
} | ||
this.setState(function (prevState) { | ||
return { | ||
value: value, | ||
stars: _this2.getStars(value), | ||
halfStar: config.half ? { | ||
hidden: Number.isInteger(value), | ||
at: Math.floor(value) | ||
} : prevState.halfStar | ||
}; | ||
}); | ||
this.props.onChange(value); | ||
} | ||
}, { | ||
key: "renderStars", | ||
value: function renderStars() { | ||
var _this3 = this; | ||
var _state6 = this.state, | ||
halfStar = _state6.halfStar, | ||
stars = _state6.stars, | ||
uniqueness = _state6.uniqueness, | ||
config = _state6.config, | ||
isUsingIcons = _state6.isUsingIcons; | ||
var color1 = config.color1, | ||
@@ -270,6 +312,6 @@ color2 = config.color2, | ||
return stars.map(function (star, i) { | ||
var starClass = ''; | ||
var starClass = ""; | ||
var isHalf = false; | ||
if (half && !halfStar.hidden && halfStar.at === i) { | ||
if (!isUsingIcons) starClass = 'react-stars-' + uniqueness;else starClass = 'react-stars-half'; | ||
if (!isUsingIcons) starClass = "react-stars-" + uniqueness;else starClass = "react-stars-half"; | ||
isHalf = true; | ||
@@ -279,7 +321,7 @@ } | ||
color: star.active ? color2 : color1, | ||
cursor: edit ? 'pointer' : 'default', | ||
fontSize: size + 'px' | ||
cursor: edit ? "pointer" : "default", | ||
fontSize: size + "px" | ||
}); | ||
return _react2.default.createElement( | ||
'span', | ||
"span", | ||
{ | ||
@@ -289,8 +331,9 @@ className: starClass, | ||
key: i, | ||
'data-index': i, | ||
'data-forhalf': filledIcon ? i : char, | ||
onMouseOver: _this2.mouseOver.bind(_this2), | ||
onMouseMove: _this2.mouseOver.bind(_this2), | ||
onMouseLeave: _this2.mouseLeave.bind(_this2), | ||
onClick: _this2.clicked.bind(_this2) }, | ||
"data-index": i, | ||
"data-forhalf": filledIcon ? i : char, | ||
onMouseOver: _this3.mouseOver.bind(_this3), | ||
onMouseMove: _this3.mouseOver.bind(_this3), | ||
onMouseLeave: _this3.mouseLeave.bind(_this3), | ||
onClick: _this3.clicked.bind(_this3) | ||
}, | ||
!isUsingIcons && char, | ||
@@ -302,12 +345,30 @@ isUsingIcons && (star.active && filledIcon || !star.active && isHalf && halfIcon || !star.active && !isHalf && emptyIcon) | ||
}, { | ||
key: 'render', | ||
key: "render", | ||
value: function render() { | ||
var className = this.props.className; | ||
var _state7 = this.state, | ||
config = _state7.config, | ||
value = _state7.value; | ||
return _react2.default.createElement( | ||
'div', | ||
{ className: className, style: parentStyles }, | ||
this.state.config.half ? this.renderHalfStarStyleElement() : '', | ||
this.renderStars() | ||
"div", | ||
{ style: { display: "flex" } }, | ||
_react2.default.createElement( | ||
"div", | ||
{ | ||
tabIndex: config.a11y && config.edit ? 0 : null, | ||
"aria-label": "add rating by typing an integer from 0 to 5 or pressing arrow keys", | ||
onKeyDown: config.a11y && config.edit ? this.handleKeyDown.bind(this) : null, | ||
className: className, | ||
style: parentStyles | ||
}, | ||
config.half ? this.renderHalfStarStyleElement() : "", | ||
this.renderStars(), | ||
_react2.default.createElement( | ||
"p", | ||
{ style: { position: "absolute", left: "-200rem" }, role: "status" }, | ||
value | ||
) | ||
) | ||
); | ||
@@ -332,3 +393,4 @@ } | ||
halfIcon: _propTypes2.default.element, | ||
filledIcon: _propTypes2.default.element | ||
filledIcon: _propTypes2.default.element, | ||
a11y: _propTypes2.default.bool | ||
}; | ||
@@ -341,6 +403,7 @@ | ||
count: 5, | ||
char: '★', | ||
char: "★", | ||
size: 15, | ||
color1: 'gray', | ||
color2: '#ffd700', | ||
color1: "gray", | ||
color2: "#ffd700", | ||
a11y: true, | ||
@@ -347,0 +410,0 @@ onChange: function onChange() {} |
{ | ||
"name": "react-rating-stars-component", | ||
"version": "1.0.3", | ||
"version": "1.1.0", | ||
"description": "Simple star rating component for your React projects.", | ||
@@ -5,0 +5,0 @@ "main": "dist/react-stars.js", |
109
README.md
# react-rating-stars-component :star: | ||
### Forked from `react-stars`: https://github.com/n49/react-stars | ||
@@ -6,6 +7,4 @@ | ||
![react-stars](http://i.imgur.com/VDbzbqF.gif) | ||
## DEMO: https://codesandbox.io/s/oo1y2y1o59 | ||
@@ -16,2 +15,3 @@ | ||
###### Install react-stars package with NPM: | ||
`npm install react-rating-stars-component --save` | ||
@@ -22,17 +22,19 @@ | ||
```javascript | ||
import ReactStars from 'react-rating-stars-component' | ||
import React from 'react' | ||
import { render } from 'react-dom' | ||
import ReactStars from "react-rating-stars-component"; | ||
import React from "react"; | ||
import { render } from "react-dom"; | ||
const ratingChanged = (newRating) => { | ||
console.log(newRating) | ||
} | ||
console.log(newRating); | ||
}; | ||
render(<ReactStars | ||
count={5} | ||
onChange={ratingChanged} | ||
size={24} | ||
color2={'#ffd700'} />, | ||
render( | ||
<ReactStars | ||
count={5} | ||
onChange={ratingChanged} | ||
size={24} | ||
color2={"#ffd700"} | ||
/>, | ||
document.getElementById('where-to-render') | ||
document.getElementById("where-to-render") | ||
); | ||
@@ -42,30 +44,32 @@ ``` | ||
Or use other elements as icons: | ||
> We do not support CSS for other third party libraries like fontawesome in this case. So you must import it by urself. | ||
![react-stars-fa](https://i.imgur.com/ko9NNRH.gif) | ||
```javascript | ||
import ReactStars from 'react-rating-stars-component' | ||
import React from 'react' | ||
import { render } from 'react-dom' | ||
import ReactStars from "react-rating-stars-component"; | ||
import React from "react"; | ||
import { render } from "react-dom"; | ||
const ratingChanged = (newRating) => { | ||
console.log(newRating) | ||
} | ||
console.log(newRating); | ||
}; | ||
render(<ReactStars | ||
count={5} | ||
onChange={ratingChanged} | ||
size={24} | ||
half={true} | ||
emptyIcon={<i className='far fa-star'></i>} | ||
halfIcon={<i className='fa fa-star-half-alt'></i>} | ||
fullIcon={<i className='fa fa-star'></i>} | ||
color2={'#ffd700'} />, | ||
render( | ||
<ReactStars | ||
count={5} | ||
onChange={ratingChanged} | ||
size={24} | ||
half={true} | ||
emptyIcon={<i className="far fa-star"></i>} | ||
halfIcon={<i className="fa fa-star-half-alt"></i>} | ||
fullIcon={<i className="fa fa-star"></i>} | ||
color2={"#ffd700"} | ||
/>, | ||
document.getElementById('where-to-render') | ||
document.getElementById("where-to-render") | ||
); | ||
``` | ||
### API | ||
@@ -75,20 +79,23 @@ | ||
| Property | Description | Default value | type | | ||
| -------- | ----------- | ------------- | ---- | | ||
| `className` | Name of parent class | `null` | string | | ||
| `count` | How many total stars you want | 5 | number | | ||
| `value` | Set rating value | 0 | number | | ||
| `char` | Which character you want to use as a star | ★ | string | | ||
| `color1` | Color of inactive star (this supports any CSS valid value) | `gray` | string | | ||
| `color2` | Color of selected or active star | `#ffd700` | string | | ||
| `size` | Size of stars (in px) | `15px` | string | | ||
| `edit` | Should you be able to select rating or just see rating (for reusability) | `true` | boolean | | ||
| `half` | Should component use half stars, if not the decimal part will be dropped otherwise normal algebra rools will apply to round to half stars | `true` | boolean| | ||
|`emptyIcon`| Use your own elements as empty icons | `null` | element | | ||
|`halfIcon`| Use your own elements as half filled icons | `null` | element | | ||
|`filledIcon`| Use your own elements as filled icons | `null` | element | | ||
| `onChange(new_rating)` | Will be invoked any time the rating is changed | `null` | function | | ||
| Property | Description | Default value | type | | ||
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -------- | | ||
| `className` | Name of parent class | `null` | string | | ||
| `count` | How many total stars you want | 5 | number | | ||
| `value` | Set rating value | 0 | number | | ||
| `char` | Which character you want to use as a star | ★ | string | | ||
| `color1` | Color of inactive star (this supports any CSS valid value) | `gray` | string | | ||
| `color2` | Color of selected or active star | `#ffd700` | string | | ||
| `size` | Size of stars (in px) | `15px` | string | | ||
| `edit` | Should you be able to select rating or just see rating (for reusability) | `true` | boolean | | ||
| `half` | Should component use half stars, if not the decimal part will be dropped otherwise normal algebra rools will apply to round to half stars | `true` | boolean | | ||
| `emptyIcon` | Use your own elements as empty icons | `null` | element | | ||
| `halfIcon` | Use your own elements as half filled icons | `null` | element | | ||
| `filledIcon` | Use your own elements as filled icons | `null` | element | | ||
| `a11y` | Should component be accessible and controlled via keyboard (arrow keys and numbers) | `true` | boolean | | ||
| `onChange(new_rating)` | Will be invoked any time the rating is changed | `null` | function | | ||
### Help improve the component | ||
###### Build on your machine: | ||
```bash | ||
@@ -102,11 +109,17 @@ # Clone the repo | ||
``` | ||
Build the component: | ||
```bash | ||
npm build | ||
``` | ||
Run the examples (dev): | ||
```bash | ||
npm run dev-example | ||
``` | ||
Build the examples (production): | ||
```bash | ||
@@ -124,4 +137,4 @@ npm run build-example | ||
* Make better docs | ||
* Better state management | ||
* Write tests | ||
- Make better docs | ||
- Better state management | ||
- Write tests |
@@ -1,16 +0,16 @@ | ||
import React, { Component } from 'react' | ||
import PropTypes from 'prop-types' | ||
import React, { Component } from "react"; | ||
import PropTypes from "prop-types"; | ||
const parentStyles = { | ||
overflow: 'hidden', | ||
position: 'relative' | ||
} | ||
overflow: "hidden", | ||
position: "relative", | ||
}; | ||
const defaultStyles = { | ||
position: 'relative', | ||
overflow: 'hidden', | ||
cursor: 'pointer', | ||
display: 'block', | ||
float: 'left' | ||
} | ||
position: "relative", | ||
overflow: "hidden", | ||
cursor: "pointer", | ||
display: "block", | ||
float: "left", | ||
}; | ||
@@ -28,4 +28,4 @@ const getHalfStarStyles = (color, uniqueness) => { | ||
color: ${color}; | ||
}` | ||
} | ||
}`; | ||
}; | ||
const getHalfStarStyleForIcons = (color) => { | ||
@@ -35,17 +35,15 @@ return ` | ||
color: ${color}; | ||
}` | ||
} | ||
}`; | ||
}; | ||
class ReactStars extends Component { | ||
constructor(props) { | ||
super(props); | ||
super(props) | ||
// set defaults | ||
props = Object.assign({}, props) | ||
props = Object.assign({}, props); | ||
this.state = { | ||
uniqueness: (Math.random() + '').replace('.', ''), | ||
uniqueness: (Math.random() + "").replace(".", ""), | ||
value: props.value || 0, | ||
@@ -55,6 +53,10 @@ stars: [], | ||
at: Math.floor(props.value), | ||
hidden: props.half && props.value % 1 < 0.5 | ||
hidden: props.half && props.value % 1 < 0.5, | ||
}, | ||
isUsingIcons: ((!props.half && props.emptyIcon && props.filledIcon) || (props.half && props.emptyIcon && props.halfIcon && props.filledIcon)) ? true : false | ||
} | ||
isUsingIcons: | ||
(!props.half && props.emptyIcon && props.filledIcon) || | ||
(props.half && props.emptyIcon && props.halfIcon && props.filledIcon) | ||
? true | ||
: false, | ||
}; | ||
@@ -73,5 +75,5 @@ this.state.config = { | ||
halfIcon: props.halfIcon, | ||
filledIcon: props.filledIcon | ||
} | ||
filledIcon: props.filledIcon, | ||
a11y: props.a11y, | ||
}; | ||
} | ||
@@ -81,4 +83,4 @@ | ||
this.setState({ | ||
stars: this.getStars(this.state.value) | ||
}) | ||
stars: this.getStars(this.state.value), | ||
}); | ||
} | ||
@@ -92,3 +94,3 @@ | ||
at: Math.floor(props.value), | ||
hidden: this.state.config.half && props.value % 1 < 0.5 | ||
hidden: this.state.config.half && props.value % 1 < 0.5, | ||
}, | ||
@@ -102,105 +104,157 @@ config: Object.assign({}, this.state.config, { | ||
half: props.half, | ||
edit: props.edit | ||
}) | ||
}) | ||
edit: props.edit, | ||
}), | ||
}); | ||
} | ||
isDecimal(value) { | ||
return value % 1 !== 0 | ||
return value % 1 !== 0; | ||
} | ||
getRate() { | ||
let stars | ||
let stars; | ||
if (this.state.config.half) { | ||
stars = Math.floor(this.state.value) | ||
stars = Math.floor(this.state.value); | ||
} else { | ||
stars = Math.round(this.state.value) | ||
stars = Math.round(this.state.value); | ||
} | ||
return stars | ||
return stars; | ||
} | ||
getStars(activeCount) { | ||
if (typeof activeCount === 'undefined') { | ||
activeCount = this.getRate() | ||
if (typeof activeCount === "undefined") { | ||
activeCount = this.getRate(); | ||
} | ||
let stars = [] | ||
let stars = []; | ||
for (let i = 0; i < this.state.config.count; i++) { | ||
stars.push({ | ||
active: i <= activeCount - 1 | ||
}) | ||
active: i <= activeCount - 1, | ||
}); | ||
} | ||
return stars | ||
return stars; | ||
} | ||
mouseOver(event) { | ||
let { config, halfStar } = this.state | ||
let { config, halfStar } = this.state; | ||
if (!config.edit) return; | ||
let index = Number(event.currentTarget.getAttribute('data-index')) | ||
let index = Number(event.currentTarget.getAttribute("data-index")); | ||
if (config.half) { | ||
const isAtHalf = this.moreThanHalf(event, config.size) | ||
halfStar.hidden = isAtHalf | ||
if (isAtHalf) index = index + 1 | ||
halfStar.at = index | ||
const isAtHalf = this.moreThanHalf(event, config.size); | ||
halfStar.hidden = isAtHalf; | ||
if (isAtHalf) index = index + 1; | ||
halfStar.at = index; | ||
} else { | ||
index = index + 1 | ||
index = index + 1; | ||
} | ||
this.setState({ | ||
stars: this.getStars(index) | ||
}) | ||
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 | ||
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 | ||
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) | ||
halfStar.hidden = !this.isDecimal(value); | ||
halfStar.at = Math.floor(this.state.value); | ||
} | ||
this.setState({ | ||
stars: this.getStars() | ||
}) | ||
stars: this.getStars(), | ||
}); | ||
} | ||
clicked(event) { | ||
const { config, halfStar } = this.state | ||
if (!config.edit) return | ||
let index = Number(event.currentTarget.getAttribute('data-index')) | ||
let value | ||
const { config, halfStar } = this.state; | ||
if (!config.edit) return; | ||
let index = Number(event.currentTarget.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 | ||
const isAtHalf = this.moreThanHalf(event, config.size); | ||
halfStar.hidden = isAtHalf; | ||
if (isAtHalf) index = index + 1; | ||
value = isAtHalf ? index : index + 0.5; | ||
halfStar.at = index; | ||
} else { | ||
value = index = index + 1 | ||
value = index = index + 1; | ||
} | ||
this.setState({ | ||
value: value, | ||
stars: this.getStars(index) | ||
}) | ||
this.props.onChange(value) | ||
stars: this.getStars(index), | ||
}); | ||
this.props.onChange(value); | ||
} | ||
renderHalfStarStyleElement() { | ||
const { config, uniqueness, isUsingIcons } = this.state | ||
const { config, uniqueness, isUsingIcons } = this.state; | ||
return ( | ||
<style dangerouslySetInnerHTML={{ | ||
__html: isUsingIcons ? getHalfStarStyleForIcons(config.color2) : getHalfStarStyles(config.color2, uniqueness) | ||
}}></style> | ||
) | ||
<style | ||
dangerouslySetInnerHTML={{ | ||
__html: isUsingIcons | ||
? getHalfStarStyleForIcons(config.color2) | ||
: getHalfStarStyles(config.color2, uniqueness), | ||
}} | ||
></style> | ||
); | ||
} | ||
handleKeyDown(event) { | ||
const { key } = event; | ||
let { value, config } = this.state; | ||
const keyNumber = Number(key); // e.g. "1" => 1, "ArrowUp" => NaN | ||
if (keyNumber) { | ||
// number | ||
if ( | ||
Number.isInteger(keyNumber) && | ||
keyNumber > 0 && | ||
keyNumber <= config.count | ||
) { | ||
value = keyNumber; | ||
} | ||
} else { | ||
// string | ||
if ((key === "ArrowUp" || key === "ArrowRight") && value < config.count) { | ||
event.preventDefault(); | ||
value += config.half ? 0.5 : 1; | ||
} else if ((key === "ArrowDown" || key === "ArrowLeft") && value > 0.5) { | ||
event.preventDefault(); | ||
value -= config.half ? 0.5 : 1; | ||
} | ||
} | ||
this.setState((prevState) => ({ | ||
value, | ||
stars: this.getStars(value), | ||
halfStar: config.half | ||
? { | ||
hidden: Number.isInteger(value), | ||
at: Math.floor(value), | ||
} | ||
: prevState.halfStar, | ||
})); | ||
this.props.onChange(value); | ||
} | ||
renderStars() { | ||
const { halfStar, stars, uniqueness, config, isUsingIcons } = this.state | ||
const { color1, color2, size, char, half, edit, halfIcon, emptyIcon, filledIcon } = config | ||
const { halfStar, stars, uniqueness, config, isUsingIcons } = this.state; | ||
const { | ||
color1, | ||
color2, | ||
size, | ||
char, | ||
half, | ||
edit, | ||
halfIcon, | ||
emptyIcon, | ||
filledIcon, | ||
} = config; | ||
return stars.map((star, i) => { | ||
let starClass = '' | ||
let starClass = ""; | ||
let isHalf = false; | ||
@@ -214,5 +268,5 @@ if (half && !halfStar.hidden && halfStar.at === i) { | ||
color: star.active ? color2 : color1, | ||
cursor: edit ? 'pointer' : 'default', | ||
fontSize: `${size}px` | ||
}) | ||
cursor: edit ? "pointer" : "default", | ||
fontSize: `${size}px`, | ||
}); | ||
return ( | ||
@@ -228,29 +282,39 @@ <span | ||
onMouseLeave={this.mouseLeave.bind(this)} | ||
onClick={this.clicked.bind(this)}> | ||
onClick={this.clicked.bind(this)} | ||
> | ||
{!isUsingIcons && char} | ||
{ | ||
isUsingIcons && ( | ||
(star.active && filledIcon) || (!star.active && isHalf && halfIcon) || (!star.active && !isHalf && emptyIcon) | ||
) | ||
} | ||
{isUsingIcons && | ||
((star.active && filledIcon) || | ||
(!star.active && isHalf && halfIcon) || | ||
(!star.active && !isHalf && emptyIcon))} | ||
</span> | ||
) | ||
}) | ||
); | ||
}); | ||
} | ||
render() { | ||
const { className } = this.props; | ||
const { | ||
className | ||
} = this.props | ||
const { config, value } = this.state; | ||
return ( | ||
<div className={className} style={parentStyles}> | ||
{this.state.config.half ? | ||
this.renderHalfStarStyleElement() : ''} | ||
{this.renderStars()} | ||
<div style={{ display: "flex" }}> | ||
<div | ||
tabIndex={config.a11y && config.edit ? 0 : null} | ||
aria-label="add rating by typing an integer from 0 to 5 or pressing arrow keys" | ||
onKeyDown={ | ||
config.a11y && config.edit ? this.handleKeyDown.bind(this) : null | ||
} | ||
className={className} | ||
style={parentStyles} | ||
> | ||
{config.half ? this.renderHalfStarStyleElement() : ""} | ||
{this.renderStars()} | ||
<p style={{ position: "absolute", left: "-200rem" }} role="status"> | ||
{value} | ||
</p> | ||
</div> | ||
</div> | ||
) | ||
); | ||
} | ||
} | ||
@@ -270,4 +334,5 @@ | ||
halfIcon: PropTypes.element, | ||
filledIcon: PropTypes.element | ||
} | ||
filledIcon: PropTypes.element, | ||
a11y: PropTypes.bool, | ||
}; | ||
@@ -279,10 +344,11 @@ ReactStars.defaultProps = { | ||
count: 5, | ||
char: '★', | ||
char: "★", | ||
size: 15, | ||
color1: 'gray', | ||
color2: '#ffd700', | ||
color1: "gray", | ||
color2: "#ffd700", | ||
a11y: true, | ||
onChange: () => { } | ||
onChange: () => {}, | ||
}; | ||
export default ReactStars | ||
export default ReactStars; |
Sorry, the diff of this file is too big to display
228878
1900
134