ستاره‌های امتیازPeek Rating

ردیفِ ستاره‌ای که ستاره‌ی زیرِ نشانگر بالا می‌آد و بزرگ می‌شه و حبابی برچسبِ همون پله رو نشون می‌ده؛ کلیک ثبت می‌کنه و کلیکِ دوباره پاک.

محمدجواد

ساخته شده توسط محمدجواد

سازنده فارسی‌فای، بچه دولوپر

وابستگی‌ها

بدون وابستگی

نوع تعامل

نشانگر رو روی ردیف ببر تا ستاره‌ی زیرش بالا بیاد و حباب برچسبِ اون پله رو نشون بده. با فشردن و کشیدنِ افقی مقدار پیش‌نمایش می‌گیره و موقعِ رهاکردن همون دمی ثبت می‌شه؛ روی لمس، کشیدنِ عمودی صفحه رو اسکرول می‌کنه و انتخاب فقط با فشارِ افقی رخ می‌ده. با کلیکِ دوباره روی ستاره‌ی فعلی مقدار صفر می‌شه. کلیدهای جهت، Home/End، Space/Enter و Backspace/Delete هم کار می‌کنن.

پراپ‌ها

گزینه‌هایی که می‌تونی به کامپوننت بدی؛ ستاره‌دارها اجباری‌اند.

value
number

حالتِ controlled؛ اگه بدی مالکیتِ مقدار با توئه.

defaultValue
numberپیش‌فرض: 0

مقدارِ اولیه توی حالتِ uncontrolled.

onChange
(value: number) => void

با هر ثبت صدا زده می‌شه؛ صفر یعنی پاک‌شده.

onPreview
(value: number | null) => void

با هر جابه‌جاییِ نشانگر پله‌ی زیرِ اون رو می‌ده؛ خروج `null`.

count
numberپیش‌فرض: 5

شمارِ ستاره‌ها.

shape
"star" | "heart" | "bolt"پیش‌فرض: "star"star · heart · bolt

گلیفِ آماده.

نصب

۱. این آدرس رو یک‌بار توی components.json بذار تا shadcn مخزن فارسی‌فای رو بشناسه.

components.jsonjson
{
  "registries": {
    "@farsify": "https://farsify.ir/r/{name}.json"
  }
}

۲. بعد با دستورِ زیر کامپوننت رو نصب کن.

npx shadcn@latest add @farsify/peek-rating

پیش‌نیاز: Tailwind CSS v4 و صفحهٔ راست‌به‌چپ dir="rtl".

نمونه

peek-rating.tsxtsx
"use client";

import { useState } from "react";
import { PeekRating } from "@/components/farsify/peek-rating";

const LABELS = ["ضعیف", "نسبتاً خوب", "خوب", "خیلی خوب", "عالی"];

export function ProductScore() {
  const [score, setScore] = useState(0);

  return (
    <div className="flex flex-col items-center gap-3">
      <PeekRating
        value={score}
        onChange={setScore}
        labels={LABELS}
        size={36}
      />
      {/* برچسبِ کنارِ فرم از onPreview می‌آید و با خروجِ نشانگر
          به مقدارِ ثبت‌شده برمی‌گردد */}
      <span className="text-sm">{LABELS[score - 1] ?? "امتیازی نداده‌اید"}</span>
    </div>
  );
}

// بدون کنترل — مقدارِ اولیه‌ی ۳ از ۵
<PeekRating defaultValue={3} labels={LABELS} />

// فقط نمایش: ستاره‌ها دکمه نیستند و ریشه نقشِ img می‌گیرد
<PeekRating value={4} readOnly ariaLabel="امتیازِ این محصول" />

// قلبِ صورتی، ده پله، بدونِ حبابِ راهنما
<PeekRating
  shape="heart"
  count={10}
  activeColor="#e5484d"
  showTip={false}
  lift={9}
  magnify={1.25}
/>

نکته‌ها

  • برای فرمِ امتیازدهی، `onChange` رو به state وصل کن و `defaultValue` بده؛ برای نمایشِ امتیازِ ثبت‌شده فقط `readOnly` با `value` بذار — توی اون حالت ستاره‌ها دکمه نیستن و ریشه یه تصویرِ قابلِ خواندن می‌شه («۳ از ۵»).
  • `onPreview` برای چیزیه که صفحه‌خوان یا برچسبِ کنارِ فرم لازم داره؛ با خروجِ نشانگر `null` می‌گیره، پس می‌تونی متنِ کمکی رو همون لحظه به مقدارِ ثبت‌شده برگردونی.
  • برچسب‌ها **فارسی** بده و تعدادشون رو دستِ‌کم برابرِ `count` بگیر: متنِ حباب از `labels` می‌آد و نامِ دسترس‌پذیرِ هر ستاره «۲ از ۵، نسبتاً خوب» می‌شه. اگه ندی، فقط رقمِ فارسیِ پله نشون داده می‌شه.
  • این پورت راست‌به‌چپ نمی‌شه چون لازم نیست: خودِ مرجع آینه‌سازی رو توی JS انجام می‌ده (هم اندیسِ ستاره و هم جای حباب)، پس توی فارسی ستاره‌ی اول از سمتِ راست شروع می‌شه و همه‌چیز سرِ جاشه.
  • گلیف‌ها درون‌خطی‌ان و از `@hugeicons/core-free-icons` کپی شدن تا وابستگیِ UI بیرونی اضافه نشه؛ `fill="currentColor"` دارن، پس گلیف توپُر می‌آد و رنگ رو از `activeColor`/`idleColor` می‌گیره.
  • با `prefers-reduced-motion` برخاستن و بزرگ‌نمایی کامل حذف می‌شن ولی رنگِ پیش‌نمایش سرِ جاش می‌مونه — بازخورد از دست نمی‌ره، فقط حرکتش کم می‌شه.

مجوز

کد بعد از نصب مالِ خودته؛ هر تغییری خواستی بده و توی پروژه‌ی خودت نگهش دار. برای پروژه‌های شخصی و تجاری آزاده، حتی اگه کدت بسته باشه. فقط اسم و لینک فارسی‌فای رو یه جا توی پروژه نگه دار.