UNPKG

wix-style-react

Version:
138 lines 6.87 kB
import React from 'react'; import PropTypes from 'prop-types'; import { st, classes } from './StarsRatingBar.st.css'; import { dataHooks, starIndexes, starRatingBarSizes, starRatingBarSizesInPx, } from './constants'; import Text from '../Text'; import InteractiveModeStar from './components/InteractiveModeStar'; import { StarFilled as StarFilledIcon } from '@wix/wix-ui-icons-common'; /** Star Rating Component */ class StarsRatingBar extends React.PureComponent { constructor(props) { super(props); this._getStarsRatingBarSize = () => { const { readOnly } = this.props; return readOnly ? this._getReadOnlyModeStarsSize() : this._getInteractiveModeStarsSize(); }; this._getReadOnlyModeStarsSize = () => { const { size } = this.props; return size ? size : starRatingBarSizes.medium; }; this._getInteractiveModeStarsSize = () => { // In interactive mode the size must be 'large' return starRatingBarSizes.large; }; this._onStarIconClick = ratingValue => { this.props.onChange(ratingValue); }; this._onMouseEnter = ratingValue => { this.setState({ hoveredStarIndex: ratingValue }); }; this._onMouseLeave = () => { this.setState({ hoveredStarIndex: 0 }); }; this._handleFocus = ratingValue => { // We would like to change the rate caption label when focus / hover this.setState({ hoveredStarIndex: ratingValue }); }; this._handleBlur = () => { // We would like to change the rate caption label when focus / hover this.setState({ hoveredStarIndex: 0 }); }; this._renderStars = () => { const { readOnly, value } = this.props; const { starsRatingBarSize, hoveredStarIndex } = this.state; return Object.values(starIndexes).map(ratingValue => { return readOnly ? (this._renderReadOnlyModeStar(ratingValue)) : (React.createElement(InteractiveModeStar, { className: "InteractiveModeStar", key: ratingValue, starsRatingBarSize: starsRatingBarSize, index: ratingValue, selectedStarIndex: value, hoveredStarIndex: hoveredStarIndex, onClick: this._onStarIconClick, onMouseEnter: this._onMouseEnter, onMouseLeave: this._onMouseLeave, handleFocus: this._handleFocus, handleBlur: this._handleBlur })); }); }; this._renderReadOnlyModeStar = ratingValue => { const { readOnly, value } = this.props; const { starsRatingBarSize } = this.state; const isFilledStar = ratingValue <= value; const dataHook = isFilledStar ? dataHooks.filledStar : dataHooks.emptyStar; return (React.createElement(StarFilledIcon, { key: ratingValue, "data-hook": dataHook, className: st(classes.star, { readOnly, filled: isFilledStar, empty: !isFilledStar, }), size: starRatingBarSizesInPx[starsRatingBarSize] })); }; this._shouldShowRateCaption = () => { const { readOnly, descriptionValues } = this.props; let shouldShowRateCaption = false; if (descriptionValues) { const isValidRateCaption = Array.isArray(descriptionValues) && descriptionValues.length === 5; if (readOnly) { // Adding description values is not available in read only mode shouldShowRateCaption = false; } else { // Description values must be an array of strings at size 5 shouldShowRateCaption = isValidRateCaption; } } return shouldShowRateCaption; }; this._renderRateCaption = () => { const { descriptionValues, value } = this.props; const { hoveredStarIndex } = this.state; const isStarsHovered = hoveredStarIndex !== 0; let rateCaptionCurrentLabel = ''; // If the user hovers on a star the label should be compatible to the value of the hovered star // otherwise the label should be compatible to the selected value. if (isStarsHovered) { rateCaptionCurrentLabel = descriptionValues[hoveredStarIndex - 1]; } else { rateCaptionCurrentLabel = value === 0 ? '' : descriptionValues[value - 1]; } return (React.createElement("div", { className: classes.rateCaption }, React.createElement(Text, { dataHook: dataHooks.ratingCaption, ellipsis: true, size: "small", weight: "normal", secondary: true }, rateCaptionCurrentLabel))); }; const starsRatingBarSize = this._getStarsRatingBarSize(); this.state = { starsRatingBarSize, hoveredStarIndex: 0, }; } componentDidUpdate(prevProps) { if (prevProps.size !== this.props.size) { const starsRatingBarSize = this._getStarsRatingBarSize(); this.setState({ starsRatingBarSize }); } } render() { const { dataHook, className } = this.props; return (React.createElement("div", { "data-hook": dataHook, className: st(classes.root, className) }, React.createElement("div", { role: "radiogroup", className: classes.starsContainer }, this._renderStars()), this._shouldShowRateCaption() ? this._renderRateCaption() : null)); } } StarsRatingBar.displayName = 'StarsRatingBar'; StarsRatingBar.propTypes = { /** Applies a data-hook HTML attribute that can be used in tests */ dataHook: PropTypes.string, /** Applies a CSS class to the component’s root element */ className: PropTypes.string, /** Controls the size of the star rating bar. Interactive mode must be `large`. The default value for the read only mode is `medium`. */ size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large']), /** Specifies whether the rating bar is in read-only mode. */ readOnly: PropTypes.bool, /** Specifies the rate value labels. Array must contain all 5 strings to display the rating labels. */ descriptionValues: PropTypes.arrayOf(PropTypes.string), /** Specifies the selected rate. 0 indicates an undefined rating. */ value: PropTypes.oneOf([0, 1, 2, 3, 4, 5]).isRequired, /** Defines a handler that is called whenever rating changes. * ##### Signature: * function(rating: number) => void * * `rating`: 1 | 2 | 3 | 4 | 5 */ onChange: PropTypes.func, }; StarsRatingBar.defaultProps = { readOnly: false, onChange: () => { }, }; export default StarsRatingBar; //# sourceMappingURL=StarsRatingBar.js.map