UNPKG

wix-style-react

Version:
155 lines 7.44 kB
import React from 'react'; import PropTypes from 'prop-types'; import { withFocusable } from '../common/Focusable'; import { st, classes } from './FacesRatingBar.st.css'; import { dataHooks, facesData } from './constants'; import Box from '../Box/Box'; import Tooltip from '../Tooltip/Tooltip'; import { FaceDisapointed, FaceFrowning, FaceNeutral, FaceSmiling, FaceGrining, } from './icons/FaceIcons'; const faceIconsMap = { 5: { 1: FaceDisapointed, 2: FaceFrowning, 3: FaceNeutral, 4: FaceSmiling, 5: FaceGrining, }, 4: { 1: FaceDisapointed, 2: FaceFrowning, 3: FaceSmiling, 4: FaceGrining, }, 3: { 1: FaceDisapointed, 2: FaceNeutral, 3: FaceSmiling, }, 2: { 1: FaceDisapointed, 2: FaceSmiling, }, }; /** A rating component that will enable the user to rate on a 1-5 scale. */ class FacesRatingBar extends React.PureComponent { constructor() { super(...arguments); this.state = { faceHoveredIndex: 0, }; this._onFaceClick = index => { this.props.onChange(index); }; this._onFaceMouseEnter = index => { this.setState({ faceHoveredIndex: index }); }; this._onFaceMouseLeave = () => { this.setState({ faceHoveredIndex: 0 }); }; this._onFaceFocus = (faceIndex, focusableProps) => { // We would like to change the faces color on focus / hover this.setState({ faceHoveredIndex: faceIndex }); focusableProps.focusableOnFocus(); }; this._onFaceBlur = focusableProps => { // We would like to change the faces color on focus / hover this.setState({ faceHoveredIndex: 0 }); focusableProps.focusableOnBlur(); }; this._shouldShowDescriptionValues = () => { const { readOnly, descriptionValues, maxValue } = this.props; let shouldShowDescriptionValues = false; // Adding description values is not available in read only mode and it must be an array of strings at size of at least 2. if (!readOnly && descriptionValues) { shouldShowDescriptionValues = Array.isArray(descriptionValues) && descriptionValues.length === maxValue; } return shouldShowDescriptionValues; }; } componentDidMount() { const { readOnly, value } = this.props; if (readOnly && value === 0) { throw new Error('In readOnly mode the value couldn’t be 0. Please enter a value between 1 to 5.'); } } render() { const { dataHook, readOnly, value, descriptionValues, maxValue } = this.props; const { faceHoveredIndex } = this.state; const showDescriptionValues = this._shouldShowDescriptionValues(); return (React.createElement(Box, { className: st(classes.root, {}, this.props), dataHook: dataHook }, React.createElement(Faces, { readOnly: readOnly, maxValue: maxValue, selectedIndex: value, hoveredIndex: faceHoveredIndex, showDescriptionValues: showDescriptionValues, descriptionValues: descriptionValues, onClick: this._onFaceClick, onMouseEnter: this._onFaceMouseEnter, onMouseLeave: this._onFaceMouseLeave, handleFocus: this._onFaceFocus, handleBlur: this._onFaceBlur }))); } } const Faces = ({ readOnly, selectedIndex, hoveredIndex, showDescriptionValues, descriptionValues, onClick, onMouseEnter, onMouseLeave, handleFocus, handleBlur, maxValue, }) => { const facesArr = []; for (let i = 1; i <= maxValue; i++) { const isSelected = selectedIndex === i; const isHovered = hoveredIndex === i; const iconType = facesData[i].name; const commonProps = { key: i, faceIndex: i, isSelected, iconType, maxValue, }; const face = readOnly ? (React.createElement(ReadOnlyModeFace, { ...commonProps })) : (React.createElement(FocusableInteractiveModeFace, { ...commonProps, isHovered: isHovered, showDescriptionValues: showDescriptionValues, descriptionValues: descriptionValues, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, handleFocus: handleFocus, handleBlur: handleBlur })); facesArr.push(face); } return facesArr; }; const InteractiveModeFace = ({ faceIndex, isSelected, iconType, isHovered, showDescriptionValues, descriptionValues, onClick, onMouseEnter, onMouseLeave, handleFocus, handleBlur, maxValue, ...focusableProps }) => { const IconTagName = faceIconsMap[maxValue][faceIndex]; const tooltipContent = showDescriptionValues ? descriptionValues[faceIndex - 1] : ''; return (React.createElement("button", { "data-hook": dataHooks.face, "data-index": faceIndex, "data-selected": isSelected, className: st(classes.buttonWrapper), onClick: () => onClick(faceIndex), onMouseEnter: () => onMouseEnter(faceIndex), onMouseLeave: onMouseLeave, onFocus: () => handleFocus(faceIndex, focusableProps), onBlur: () => handleBlur(focusableProps) }, React.createElement("div", { "data-hook": dataHooks.face, "data-selected": isSelected, className: st(classes.faceContainer, { type: 'interactive', hovered: isHovered, selected: isSelected, iconType, }) }, React.createElement(Tooltip, { dataHook: facesData[faceIndex].tooltipDataHook, content: tooltipContent, disabled: !showDescriptionValues }, React.createElement(IconTagName, { width: 22, height: 22 }))))); }; const FocusableInteractiveModeFace = withFocusable(InteractiveModeFace); const ReadOnlyModeFace = ({ faceIndex, isSelected, iconType, maxValue }) => { const IconTagName = faceIconsMap[maxValue][faceIndex]; return (React.createElement("div", { "data-hook": dataHooks.face, "data-selected": isSelected, className: st(classes.faceContainer, { type: 'readOnly', selected: isSelected, iconType, }) }, React.createElement(IconTagName, null))); }; FacesRatingBar.displayName = 'FacesRatingBar'; FacesRatingBar.propTypes = { /** Applies a data-hook HTML attribute that can be used in the tests */ dataHook: PropTypes.string, /** Allows you to apply a CSS class to the component’s root element */ className: PropTypes.string, /** Specifies whether the rating bar is in read only mode */ readOnly: PropTypes.bool, /** Specifies the rate value descriptions’ texts. The array length must match the maxValue prop number (5 by default). */ descriptionValues: PropTypes.arrayOf(PropTypes.string), /** Specifies the selected rate. `0` indicates undefined rating. `readOnly` mode value cannot be `0`. */ value: PropTypes.oneOf([0, 1, 2, 3, 4, 5]).isRequired, /** Specifies the maximum rate value. */ maxValue: PropTypes.oneOf([2, 3, 4, 5]), /** Defines a handler that is called whenever a rating changes. * ##### Signature: * function(rating: number) => void * * `rating`: 1 | 2 | 3 | 4 | 5 */ onChange: PropTypes.func, }; FacesRatingBar.defaultProps = { readOnly: false, onChange: () => { }, maxValue: 5, }; export default FacesRatingBar; //# sourceMappingURL=FacesRatingBar.js.map