UNPKG

react-awesome-stars

Version:

A flexible and customizable star rating component for React applications

96 lines (85 loc) 6.96 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var jsxRuntime = require('react/jsx-runtime'); var react = require('react'); function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z = "/* Root container */\n.star-rating-root {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n/* Stars container */\n.star-rating-stars {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n/* Individual star */\n.star-rating-star {\n position: relative;\n display: inline-block;\n cursor: pointer;\n transition: transform 0.15s;\n vertical-align: middle;\n}\n\n.star-rating-star-hovered {\n transform: scale(1.1);\n z-index: 1;\n}\n\n.star-rating-star-disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Half star hit areas */\n.star-rating-half {\n position: absolute;\n top: 0;\n width: 50%;\n height: 100%;\n z-index: 2;\n cursor: pointer;\n}\n.star-rating-half.left {\n left: 0;\n}\n.star-rating-half.right {\n right: 0;\n}\n\n/* SVGs */\n.star-rating-svg {\n display: block;\n pointer-events: none;\n}\n.star-rating-empty {\n position: absolute;\n top: 0;\n left: 0;\n}\n.star-rating-filled {\n position: relative;\n z-index: 1;\n}\n\n/* Filled star overlay */\n.star-rating-fill {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n overflow: hidden;\n pointer-events: none;\n z-index: 2;\n}\n\n/* Value display */\n.star-rating-value {\n margin-left: 8px;\n color: #555;\n font-size: 0.95em;\n font-weight: 500;\n user-select: none;\n}\n\n/* Accessibility: focus ring */\n.star-rating-star:focus {\n outline: 2px solid #fbbf24;\n outline-offset: 2px;\n}\n"; styleInject(css_248z); const StarRating = ({ rating = 0, maxRating = 5, interactive = true, onRatingChange, size = "md", fillColor = "#fbbf24", emptyColor = "#d1d5db", hoverColor = "#f59e0b", allowHalf = false, showRating = false, className = "", showTooltip = false, tooltipLabels = ["Poor", "Fair", "Good", "Great", "Excellent"], animationDuration = 150, disabled = false, }) => { const [hoverRating, setHoverRating] = react.useState(null); const [hoveredStar, setHoveredStar] = react.useState(null); const starSize = react.useMemo(() => { if (typeof size === "number") return size; const sizes = { xs: 16, sm: 20, md: 24, lg: 32, xl: 40 }; return sizes[size]; }, [size]); const handleMouseEnter = react.useCallback((starIndex, isHalf = false) => { if (!interactive || disabled) return; const newRating = isHalf ? starIndex - 0.5 : starIndex; setHoverRating(newRating); setHoveredStar(starIndex); }, [interactive, disabled]); const handleMouseLeave = react.useCallback(() => { if (!interactive || disabled) return; setHoverRating(null); setHoveredStar(null); }, [interactive, disabled]); const handleClick = react.useCallback((starIndex, isHalf = false) => { if (!interactive || disabled) return; const newRating = isHalf ? starIndex - 0.5 : starIndex; onRatingChange === null || onRatingChange === void 0 ? void 0 : onRatingChange(newRating); }, [interactive, disabled, onRatingChange]); const currentRating = hoverRating !== null ? hoverRating : rating; const renderStar = (starIndex) => { const isHovered = hoveredStar === starIndex; const fillPercentage = Math.min(Math.max(currentRating - (starIndex - 1), 0), 1); const starColor = isHovered ? hoverColor : fillPercentage > 0 ? fillColor : emptyColor; return (jsxRuntime.jsxs("div", { className: `star-rating-star${disabled ? " star-rating-star-disabled" : ""}${isHovered ? " star-rating-star-hovered" : ""}`, style: { width: starSize, height: starSize, transition: `transform ${animationDuration}ms`, }, onMouseEnter: () => handleMouseEnter(starIndex), onMouseLeave: handleMouseLeave, onClick: () => handleClick(starIndex), title: showTooltip ? tooltipLabels[starIndex - 1] : undefined, tabIndex: interactive && !disabled ? 0 : -1, role: interactive ? "button" : undefined, "aria-label": showTooltip ? tooltipLabels[starIndex - 1] : `Rate ${starIndex}`, children: [allowHalf && interactive && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "star-rating-half left", onMouseEnter: () => handleMouseEnter(starIndex, true), onClick: (e) => { e.stopPropagation(); handleClick(starIndex, true); } }), jsxRuntime.jsx("div", { className: "star-rating-half right", onMouseEnter: () => handleMouseEnter(starIndex, false), onClick: (e) => { e.stopPropagation(); handleClick(starIndex, false); } })] })), jsxRuntime.jsx("svg", { width: starSize, height: starSize, viewBox: "0 0 24 24", fill: emptyColor, className: "star-rating-svg star-rating-empty", children: jsxRuntime.jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }), jsxRuntime.jsx("div", { className: "star-rating-fill", style: { width: `${fillPercentage * 100}%`, transition: `width ${animationDuration}ms ease`, }, children: jsxRuntime.jsx("svg", { width: starSize, height: starSize, viewBox: "0 0 24 24", fill: starColor, className: "star-rating-svg star-rating-filled", children: jsxRuntime.jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }) })] }, starIndex)); }; return (jsxRuntime.jsxs("div", { className: `star-rating-root${className ? ` ${className}` : ""}`, children: [jsxRuntime.jsx("div", { className: "star-rating-stars", children: Array.from({ length: maxRating }, (_, i) => renderStar(i + 1)) }), showRating && (jsxRuntime.jsxs("span", { className: "star-rating-value", style: { fontSize: Math.max(starSize * 0.5, 12) }, children: [currentRating.toFixed(allowHalf ? 1 : 0), " / ", maxRating] }))] })); }; exports.StarRating = StarRating; exports.default = StarRating; //# sourceMappingURL=index.js.map