@wix/design-system
Version:
@wix/design-system
62 lines • 3.73 kB
JavaScript
import React, { useState, forwardRef } from 'react';
import { st, classes } from './StarsRatingBar.st.css.js';
import { dataHooks, starValues } from '../constants';
import Text from '../../Text';
import { Star, StarFilled } from '@wix/wix-ui-icons-common';
import { useUniqueId } from '../../providers/useCollapse/utils';
import semanticClassNames from '../StarsRatingBar.semanticClassNames';
import { getRatingLabel, getStarSizePx } from '../utils/common';
import { classes as commonClasses } from '../../common/styles/visuallyHidden.st.css.js';
import { withFocusable } from '../../common/Focusable';
const renderCaption = ({ descriptionValues }, value) => {
if (!Array.isArray(descriptionValues) ||
descriptionValues.length !== 5 ||
!value) {
return null;
}
return (React.createElement("div", { className: classes.rateCaption },
React.createElement(Text, { dataHook: dataHooks.ratingCaption, "aria-hidden": true, ellipsis: true, size: "small", weight: "normal", secondary: true }, descriptionValues[value - 1])));
};
const InteractiveStarsRatingBar = forwardRef((props, ref) => {
const { dataHook, className, value, onChange, focusableOnFocus, focusableOnBlur, } = props;
const name = useUniqueId(props.name);
const [hoveredValue, setHoveredValue] = useState(null);
const visualValue = hoveredValue ?? value ?? 0;
const valueToPassReference = value > 0 ? value : 1; // if value is 0, we pass the reference to the first star
const sizePx = getStarSizePx(props);
const handleChange = (event) => {
onChange?.(parseInt(event.currentTarget.value));
};
const createPointerEventHandler = (value) => (event) => {
if (event.pointerType === 'touch') {
// Ignoring the touch hover, because it is sticky and results in bad UX.
return;
}
switch (event.type) {
case 'pointerenter':
setHoveredValue(value);
break;
case 'pointerleave':
case 'pointercancel':
setHoveredValue(null);
break;
default:
break;
}
};
return (React.createElement("div", { "data-hook": dataHook, className: st(classes.root, className) },
React.createElement("div", { role: "radiogroup", className: classes.starsContainer }, starValues.map(starValue => {
const filled = visualValue >= starValue;
const checked = value === starValue;
const Icon = filled ? StarFilled : Star;
const handlePointerEvent = createPointerEventHandler(starValue);
return (React.createElement("label", { key: starValue, "data-hook": filled ? dataHooks.filledStar : dataHooks.emptyStar, "data-index": starValue, className: st(classes.starContainer, semanticClassNames.buttonInteractive), onPointerEnter: handlePointerEvent, onPointerLeave: handlePointerEvent, onPointerCancel: handlePointerEvent },
React.createElement("input", { type: "radio", name: name, value: starValue, checked: checked, "aria-label": getRatingLabel(props, starValue), className: commonClasses.visuallyHidden, onChange: handleChange, ref: valueToPassReference === starValue ? ref : undefined, onFocus: focusableOnFocus, onBlur: focusableOnBlur }),
React.createElement(Icon, { "aria-hidden": true, className: st(classes.star, { filled }, filled
? semanticClassNames.filledIcon
: semanticClassNames.emptyIcon), size: sizePx })));
})),
renderCaption(props, visualValue)));
});
export default withFocusable(InteractiveStarsRatingBar);
//# sourceMappingURL=InteractiveStarsRatingBar.js.map