UNPKG

@wix/design-system

Version:

@wix/design-system

62 lines 3.73 kB
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