التقييم
نجوم القراءة فقط هي HTML من الخادم ولا تشحن أي سكربت. وحده التقييم القابل للتعديل يترطّب، كمجموعة أزرار راديو أصلية.
split - الحجم لم يُقَس بعد
التقييم
split - الحجم لم يُقَس بعدنجوم القراءة فقط هي HTML من الخادم ولا تشحن أي سكربت. وحده التقييم القابل للتعديل يترطّب، كمجموعة أزرار راديو أصلية.
جرّبه
value
max
size
readOnly
defaultValue
disabled
الشيفرة
rating.tsx
import { Rating } from 'topclassui/rating'
import type { RatingDesignProps } from 'topclassui/rating'
/** The site's Try it stage: each schema prop arrives from a control, and an absent one keeps its default. */
export default function Demo(props: RatingDesignProps = {}) {
const { readOnly, defaultValue, disabled, ...shown } = props
if (readOnly === false) {
return <Rating defaultValue={defaultValue ?? 3} disabled={disabled} {...shown} readOnly={false} aria-label="Rate this course" />
}
return <Rating value={3.5} {...shown} />
}
value وحده يعرض النجوم على الخادم؛ ووحده readOnly={false} يشحن نصف العميل.
كل الحالات، بدون تمرير الفأرة
6 حالاتأو استورده من الحزمة
topclassui/rating
import { Rating } from 'topclassui/rating'ثبّت مرة واحدة:npm i topclassui@beta zod
أمثلة
- القراءة فقط هي الافتراضية:
valueمحصور بين 0 وmaxويُرسم إلى أقرب نصف نجمة. readOnly={false}يعرض أزرار راديو أصلية، زر لكل نجمة، مسمّاة من «نجمة واحدة» إلى «5 نجوم».- مع
nameتُرسل الخطوة المحددة، من 1 إلىmax، قبل تشغيل أي سكربت. وإعادة ضبط النموذج تعيد الخطوة التي أرسلها الخادم وتستدعيonValueChange. valueمعonValueChangeيحتاجان ملفًا فيه 'use client': صفحة الخادم لا تستطيع تمرير دالة. أماdefaultValueفيعمل من صفحة الخادم.maxمن 1 إلى 10، والافتراضي 5. عشر نجوم بحجمxlعرضها 436px، فيلتف الصف على الهاتف بدل أن تتمرر الصفحة.
read-only
128 reviews
read-only.tsx
import { Rating } from 'topclassui/rating'
/** Stars that only show a value: server HTML, no script. 3.5 draws half a star, and 3.7 rounds to it. */
export default function Demo() {
return (
<div className="flex flex-col items-start gap-3">
<Rating value={0} />
<Rating value={3} />
<Rating value={5} />
<Rating value={3.5} />
<p className="flex flex-wrap items-center gap-2">
<Rating value={3.7} />
<span className="text-sm text-muted">128 reviews</span>
</p>
</div>
)
}
editable
Rate this course
editable.tsx
import { Rating } from 'topclassui/rating'
/** readOnly={false}: a radio group of five, the only part that hydrates. The arrows move and
* select, and the pointer fills up to the star it is on. A server page can render it as it is. */
export default function Demo() {
return (
<div className="flex flex-col items-start gap-2">
<h2 id="rating-editable-title" className="text-sm font-medium">Rate this course</h2>
<Rating readOnly={false} defaultValue={3} aria-labelledby="rating-editable-title" />
</div>
)
}
in-form
in-form.tsx
import { Button } from 'topclassui/button'
import { Rating } from 'topclassui/rating'
/** Each radio submits its step under name, so the form works before any script runs. Reset puts
* the stars back where the server drew them. */
export default function Demo() {
return (
<form className="flex flex-col items-start gap-3">
<h2 id="rating-form-title" className="text-sm font-medium">How was your stay?</h2>
<Rating readOnly={false} name="stay" defaultValue={4} aria-labelledby="rating-form-title" />
<div className="flex flex-wrap gap-2">
<Button type="submit">Send</Button>
<Button type="reset" variant="outline">Reset</Button>
</div>
</form>
)
}
controlled
Chosen: 2 of 5
controlled.tsx
'use client'
import { useState } from 'react'
import { Button } from 'topclassui/button'
import { RatingInput } from 'topclassui/rating'
/** RatingInput takes onValueChange, so a client file renders it: a Server Component page cannot pass a function. */
export default function Demo() {
const [value, setValue] = useState(2)
return (
<div className="flex flex-col items-start gap-3">
<RatingInput value={value} onValueChange={setValue} aria-label="Delivery" />
<p className="text-sm" data-chosen={value}>Chosen: {value} of 5</p>
<Button variant="outline" onClick={() => { setValue(0) }}>Clear</Button>
</div>
)
}
disabled
disabled.tsx
import { Rating } from 'topclassui/rating'
/** Every radio is disabled: no key, no click, no hover fill, and nothing is submitted. */
export default function Demo() {
return <Rating readOnly={false} disabled defaultValue={2} aria-label="Locked rating" />
}
sizes
sizes.tsx
import { Rating } from 'topclassui/rating'
const SIZES = ['xs', 'sm', 'md', 'lg', 'xl'] as const
/** The star follows the icon scale, 16 to 40 px. custom draws it at 1em, so the text size sets it.
* An editing step never drops under 24 px, even at xs. */
export default function Demo() {
return (
<div className="flex flex-col items-start gap-3">
{SIZES.map((size) => <Rating key={size} size={size} value={3.5} />)}
<Rating size="custom" value={2} className="text-3xl" />
<Rating readOnly={false} size="xs" defaultValue={2} aria-label="Extra small" />
<Rating readOnly={false} size="custom" defaultValue={2} aria-label="Your own size" className="text-3xl" />
</div>
)
}
max-ten
max-ten.tsx
import { Rating } from 'topclassui/rating'
/** Ten stars at xl, the widest a rating gets: 436 px, so on a phone the row wraps rather than
* scrolling the page. */
export default function Demo() {
return (
<div className="flex flex-col items-start gap-4">
<Rating max={10} size="xl" value={7.5} />
<Rating readOnly={false} max={10} size="xl" defaultValue={8} aria-label="Out of ten" />
</div>
)
}
بالعربية، من اليمين إلى اليسار
قيّم هذه الدورة
rtl.tsx
import { getLabels } from 'topclassui/labels/get-labels'
import { TopClassProvider } from 'topclassui/provider'
import { Rating } from 'topclassui/rating'
const arabic = getLabels('ar')
/** Arabic, inside TopClassProvider as the root layout would mount it. The first star is at the
* right, and half a star fills its right half. */
export default function Demo() {
return (
<TopClassProvider direction="rtl" locale="ar">
<div dir="rtl" lang="ar" className="flex flex-col items-start gap-3">
<Rating value={3.5} {...arabic} />
<h2 id="rating-rtl-title" className="text-sm font-medium">قيّم هذه الدورة</h2>
<Rating readOnly={false} defaultValue={2} aria-labelledby="rating-rtl-title" {...arabic} />
</div>
</TopClassProvider>
)
}
الخصائص
لوحة المفاتيح وإمكانية الوصول
- في وضع القراءة فقط هو صورة واحدة مسمّاة «4.5 من 5»؛ مرّر
aria-labelلتقول أكثر، مثل «4.3 من 128 مراجعة». - في وضع التعديل تحتاج المجموعة إلى
aria-labelأوaria-labelledby. ولا تقل مساحة ضغط النجمة عن 24px، و44px تحت مؤشر لمس. - النجمة الممتلئة بلون warning-on-soft، بتباين 3:1 أو أكثر على كل سطح؛ وفي وضع الألوان القسرية تبقى الممتلئة مصمتة والفارغة محدّدة الإطار.
من اليمين إلى اليسار
النجمة الأولى على اليمين، ونصف النجمة يملأ نصفها الأيمن. مرّر labels وlocale العربيين لأسماء عربية.
الخادم والمتصفح
يُعرض على الخادم، والجزء التفاعلي مكوّن متصفح لا يُرسل إلا عند استخدامه.
الملفات: index.tsx, client.tsx.
على الشارة: split - الحجم لم يُقَس بعد.