1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| import { useState } from "react"; import PropTypes from "prop-types";
const containerStyle = { display: "flex", alignItems: "center", gap: "16px", };
const starContainerStyle = { display: "flex", };
StarRating.propTypes = { maxRating: PropTypes.number, defaultRating: PropTypes.number, color: PropTypes.string, size: PropTypes.number, message: PropTypes.array, className: PropTypes.string, onSetRating: PropTypes.func, };
export default function StarRating({ maxRating = 5, color = "#fcc419", size = 48, className = "", messages = [], defaultRating = 0, onSetRating, }) { const [rating, setRating] = useState(defaultRating); const [tempRating, setTempRating] = useState(0);
function handleRating(rating) { setRating(rating); onSetRating(rating); }
const textStyle = { lineHeight: "1", maigin: "0", color, fontSize: `${size / 1.5}px`, };
return ( <div style={containerStyle} className={className}> <div style={starContainerStyle}> {Array.from({ length: maxRating }, (_, i) => ( <Star key={i} full={tempRating ? tempRating >= i + 1 : rating >= i + 1} onRate={() => handleRating(i + 1)} onHoverIn={() => setTempRating(i + 1)} onHoverOut={() => setTempRating(0)} color={color} size={size} /> ))} </div> <p style={textStyle}> {messages.length === maxRating ? messages[tempRating ? tempRating - 1 : rating - 1] : tempRating || rating || ""} </p> </div> ); }
function Star({ onRate, full, onHoverIn, onHoverOut, color, size }) { const starStyle = { width: `${size}px`, height: `${size}px`, display: "block", cursor: "pointer", };
return ( <span role="button" style={starStyle} onClick={onRate} onMouseEnter={onHoverIn} onMouseLeave={onHoverOut} > {full ? ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill={color} stroke={color} > <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" /> </svg> ) : ( <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke={color} > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="{2}" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" /> </svg> )} </span> ); }
|