UNPKG

react-rating-stars-component

Version:

Simple star rating component for your React projects.

315 lines (255 loc) 10.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _useConfig3 = require('./hooks/useConfig'); var _useConfig4 = _interopRequireDefault(_useConfig3); var _star = require('./star'); var _star2 = _interopRequireDefault(_star); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var parentStyles = { overflow: "hidden", position: "relative" }; 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 }'; } function getHalfStarStyleForIcons(color) { return '\n span.react-stars-half > * {\n color: ' + color + ';\n }'; }; function ReactStars(props) { var _useState = (0, _react.useState)(''), _useState2 = _slicedToArray(_useState, 2), uniqueness = _useState2[0], setUniqueness = _useState2[1]; var _useState3 = (0, _react.useState)(0), _useState4 = _slicedToArray(_useState3, 2), currentValue = _useState4[0], setCurrentValue = _useState4[1]; var _useState5 = (0, _react.useState)([]), _useState6 = _slicedToArray(_useState5, 2), stars = _useState6[0], setStars = _useState6[1]; var _useState7 = (0, _react.useState)(false), _useState8 = _slicedToArray(_useState7, 2), isUsingIcons = _useState8[0], setIsUsingIcons = _useState8[1]; var _useConfig = (0, _useConfig4.default)(props), _useConfig2 = _slicedToArray(_useConfig, 2), config = _useConfig2[0], setConfig = _useConfig2[1]; var _useState9 = (0, _react.useState)(0), _useState10 = _slicedToArray(_useState9, 2), halfStarAt = _useState10[0], setHalfStarAt = _useState10[1]; var _useState11 = (0, _react.useState)(false), _useState12 = _slicedToArray(_useState11, 2), halfStarHidden = _useState12[0], setHalfStarHidden = _useState12[1]; var _useState13 = (0, _react.useState)(''), _useState14 = _slicedToArray(_useState13, 2), classNames = _useState14[0], setClassNames = _useState14[1]; function iconsUsed(config) { return !config.isHalf && config.emptyIcon && config.filledIcon || config.isHalf && config.emptyIcon && config.halfIcon && config.filledIcon; } function createUniqueness() { setUniqueness((Math.random() + "").replace(".", "")); } (0, _react.useEffect)(function () { addClassNames(); validateInitialValue(props.value, props.count); setStars(getStars(props.value)); setConfig(props); createUniqueness(); setIsUsingIcons(iconsUsed(props)); setHalfStarAt(Math.floor(props.value)); setHalfStarHidden(props.isHalf && props.value % 1 < 0.5); }, []); function validateInitialValue(value, count) { if (value < 0 || value > count) { setCurrentValue(0); } else { setCurrentValue(value); } } function addClassNames() { var reactStarsClass = 'react-stars'; setClassNames(props.classNames + (' ' + reactStarsClass)); } function isDecimal(value) { return value % 1 === 0; } function getRate() { return config.isHalf ? Math.floor(currentValue) : Math.round(currentValue); } function getStars(activeCount) { if (typeof activeCount === 'undefined') { activeCount = getRate(); } var stars = []; for (var i = 0; i < config.count; i++) { stars.push({ active: i <= activeCount - 1 }); } return stars; } function mouseOver(event) { if (!config.edit) return; var index = Number(event.currentTarget.getAttribute('data-index')); if (config.isHalf) { var isAtHalf = moreThanHalf(event); setHalfStarHidden(isAtHalf); if (isAtHalf) index += 1; setHalfStarAt(index); } else { index += 1; } updateStars(index); } function updateStars(index) { var currentActive = stars.filter(function (x) { return x.active; }); if (index !== currentActive.length) { setStars(getStars(index)); } } function moreThanHalf(event) { var target = event.target; var boundingClientRect = target.getBoundingClientRect(); var mouseAt = event.clientX - boundingClientRect.left; mouseAt = Math.round(Math.abs(mouseAt)); return mouseAt > boundingClientRect.width / 2; } function mouseLeave() { if (!config.edit) return; updateHalfStarValues(currentValue); setStars(getStars()); } function updateHalfStarValues(value) { if (config.isHalf) { setHalfStarHidden(isDecimal(value)); setHalfStarAt(Math.floor(value)); } } function onClick(event) { if (!config.edit) return; var index = Number(event.currentTarget.getAttribute('data-index')); var value = void 0; if (config.isHalf) { var isAtHalf = moreThanHalf(event); setHalfStarHidden(isAtHalf); if (isAtHalf) index += 1; value = isAtHalf ? index : index + 0.5; setHalfStarAt(index); } else { value = index = index + 1; } currentValueUpdated(value); } function renderHalfStarStyleElement() { return _react2.default.createElement('style', { dangerouslySetInnerHTML: { __html: isUsingIcons ? getHalfStarStyleForIcons(config.activeColor) : getHalfStarStyles(config.activeColor, uniqueness) } }); } function currentValueUpdated(value) { if (value !== currentValue) { setStars(getStars(value)); setCurrentValue(value); props.onChange(value); } } function handleKeyDown(event) { if (!config.a11y && !config.edit) return; var key = event.key; var value = currentValue; var keyNumber = Number(key); // e.g. "1" => 1, "ArrowUp" => NaN if (keyNumber) { if (Number.isInteger(keyNumber) && keyNumber > 0 && keyNumber <= config.count) { value = keyNumber; } } else { if ((key === "ArrowUp" || key === "ArrowRight") && value < config.count) { event.preventDefault(); value += config.isHalf ? 0.5 : 1; } else if ((key === "ArrowDown" || key === "ArrowLeft") && value > 0.5) { event.preventDefault(); value -= config.isHalf ? 0.5 : 1; } } updateHalfStarValues(value); currentValueUpdated(value); } function renderStars() { return stars.map(function (star, i) { return _react2.default.createElement(_star2.default, { key: i, index: i, active: star.active, config: config, onMouseOver: mouseOver, onMouseLeave: mouseLeave, onClick: onClick, halfStarHidden: halfStarHidden, halfStarAt: halfStarAt, isUsingIcons: isUsingIcons, uniqueness: uniqueness }); }); } return _react2.default.createElement( 'div', { className: 'react-stars-wrapper-' + uniqueness, 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: handleKeyDown, className: classNames, style: parentStyles }, config.isHalf && renderHalfStarStyleElement(), renderStars(), _react2.default.createElement( 'p', { style: { position: 'absolute', left: '-200rem' }, role: 'status' }, currentValue ) ) ); } ReactStars.propTypes = { classNames: _propTypes2.default.string, edit: _propTypes2.default.bool, half: _propTypes2.default.bool, value: _propTypes2.default.number, count: _propTypes2.default.number, char: _propTypes2.default.string, size: _propTypes2.default.number, color: _propTypes2.default.string, activeColor: _propTypes2.default.string, emptyIcon: _propTypes2.default.element, halfIcon: _propTypes2.default.element, filledIcon: _propTypes2.default.element, a11y: _propTypes2.default.bool }; ReactStars.defaultProps = { edit: true, half: false, value: 0, count: 5, char: '★', size: 15, color: 'gray', activeColor: '#ffd700', a11y: true, onChange: function onChange() {} }; exports.default = ReactStars;