UNPKG

ratti

Version:

React Star Rating - Zero dependency, a highly-configurable, accessible rating component for React applications with TypeScript support.

246 lines (245 loc) 7.55 kB
import { jsxs as rt, jsx as c } from "react/jsx-runtime"; import { forwardRef as at, useState as C, useRef as W, useId as st, useImperativeHandle as ct, useEffect as lt } from "react"; const it = "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z", q = ({ fillPercentage: r = 1, starId: w, fillColor: i, forcedColor: f, svgPathD: u = it, size: l }) => { const h = `star-clip-${w}`, d = r < 1 && !f, a = d ? `${Math.max(0, Math.min(100, r * 100))}%` : "100%", p = f || i || "currentColor", $ = l ? typeof l == "number" ? l : parseFloat(l) : 24; return /* @__PURE__ */ rt( "svg", { "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", width: $, height: $, viewBox: "0 0 24 24", fill: "none", stroke: f || "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "star-icon", style: { color: p }, children: [ d && /* @__PURE__ */ c("defs", { children: /* @__PURE__ */ c("clipPath", { id: h, children: /* @__PURE__ */ c("rect", { x: "0", y: "0", width: a, height: "100%" }) }) }), /* @__PURE__ */ c("path", { d: u }), /* @__PURE__ */ c("g", { clipPath: d ? `url(#${h})` : void 0, children: /* @__PURE__ */ c("path", { d: u, fill: p, stroke: "none" }) }) ] } ); }, ut = [ "#d32f2f", "#ed6c02", "#ff9800", "#4caf50", "#00a63d" ]; function R(r, w) { const i = 1 / w; return Math.round(r * i) / i; } function X(r, w, i, f) { if (!i || r <= 0) return; const u = f || ut, l = u.length; if (l === 0) return; const h = w / l, d = Math.min( Math.floor((r - 1e-3) / h), l - 1 ), a = Math.max(0, d); return u[a >= 0 ? a : 0]; } const vt = at( ({ maxRating: r = 5, defaultValue: w = 0, value: i, onChange: f, onHoverChange: u, onBlur: l, disabled: h = !1, readOnly: d = !1, precision: a = 1, activeColorsEnabled: p = !1, customActiveColors: $, variant: S = "default", svgPathD: T, className: J = "", size: y }, O) => { const V = i !== void 0, [Q, Y] = C(w), [_, v] = C(0), [b, k] = C( null ), [N, P] = C(!1), L = W(!1), e = !h && !d, Z = st(), B = W(null); ct(O, () => B.current); const m = V ? i : Q; lt(() => { const n = () => P(!0), t = () => P(!1); return e && (document.addEventListener("keydown", n), document.addEventListener("mousedown", t)), () => { document.removeEventListener("keydown", n), document.removeEventListener("mousedown", t); }; }, [e]); function A(n, t) { if (!e) return m; const { left: o, width: s } = n.currentTarget.getBoundingClientRect(), D = (n.clientX - o) / s, K = Math.ceil(D / a) * a, M = t + Math.min(K, 1); return Math.min(Math.max(M, 0), r); } function E(n) { V || Y(n), f?.(n); } function U(n, t) { if (!e) return; const o = R(A(n, t), a); o === m ? (v(0), k(0), E(0), L.current = !0) : (E(o), v(0), k(o), L.current = !1); } function j(n, t) { if (!e || L.current) return; const o = A(n, t); v(o), u?.(o); } function G(n, t) { if (!e || L.current) return; const o = A(n, t); v(o), u?.(o); } function z() { e && (v(0), u?.(0), L.current = !1); } function tt() { e && N && b === null && k(m); } function et(n) { e && (k(null), v(0), l?.(n)); } function nt(n) { if (!e) return; let t; const o = b ?? m; switch (n.key) { case "ArrowRight": case "ArrowUp": t = Math.min(r, o + a); break; case "ArrowLeft": case "ArrowDown": t = Math.max(0, o > 0 ? o - a : 0); break; case "Home": t = 0; break; case "End": t = r; break; case "Enter": case "Space": { n.preventDefault(); const s = R(o, a); s !== m && E(s), k(s), v(0); return; } default: return; } if (t !== void 0) { n.preventDefault(); const s = R(t, a); k(s), v(s); } } const F = _ > 0 ? _ : b !== null ? b : m, x = y ? typeof y == "number" ? `${y}px` : y : void 0; return /* @__PURE__ */ c( "div", { ref: B, className: `star-rating variant-${S} ${h ? "disabled" : ""} ${d ? "readonly" : ""} ${J}`, role: "slider", "aria-orientation": "horizontal", "aria-valuemin": 0, "aria-valuemax": r, "aria-valuenow": e ? m : void 0, "aria-valuetext": `${m.toFixed(a === 1 ? 0 : 1)} out of ${r} stars`, "aria-label": "StarRating", "aria-disabled": h, "aria-readonly": d, onMouseLeave: e ? z : void 0, onFocus: e ? tt : void 0, onBlur: e ? et : void 0, onKeyDown: e ? nt : void 0, tabIndex: e ? 0 : -1, style: { ...x ? { "--star-size": x } : {} }, children: [...Array(r)].map((n, t) => { const o = t + 1, s = `${Z}-${t}`, D = F >= o, K = F - t; let M = 0; D ? M = 1 : F > t && (M = R(K, a), M = Math.max(0, Math.min(1, M))); const H = `star-item ${b !== null && t === Math.max(0, Math.ceil(b) - 1) && N ? "keyboard-focused" : ""}`, ot = p ? X( F, r, p, $ ) : void 0; if (S === "circle" || S === "square") { const g = p ? X( F, r, p, $ ) : "var(--star-bg-selected)"; return /* @__PURE__ */ c( "div", { role: "presentation", className: `${H} star-background star-background--${S}`, style: { "--star-fill-percentage": M, "--star-active-bg-color": g }, onClick: e ? (I) => U(I, t) : void 0, onMouseEnter: e ? (I) => j(I, t) : void 0, onMouseMove: e ? (I) => G(I, t) : void 0, children: /* @__PURE__ */ c( q, { starId: s, size: y, fillPercentage: 1, forcedColor: "var(--star-icon-on-bg)", svgPathD: T } ) }, s ); } return /* @__PURE__ */ c( "div", { role: "presentation", className: `${H} star-button`, onClick: e ? (g) => U(g, t) : void 0, onMouseEnter: e ? (g) => j(g, t) : void 0, onMouseMove: e ? (g) => G(g, t) : void 0, children: /* @__PURE__ */ c( q, { fillPercentage: M, starId: s, size: y, fillColor: ot, svgPathD: T } ) }, s ); }) } ); } ); export { vt as RateStar };