1 звезда на GitHub = 1 новый компонент.

Поставить звезду
E-commerceecommerceshopratingstarsreviews

Product Rating

Рейтинг звёздами только для чтения с дробной заливкой, значением и числом отзывов и единой доступной подписью.

Живое превью

Использование

Скопируйте и вставьте этот код в ваш React-компонент:

tsx
import { ProductRating } from 'react-component-kit-ui/ecommerce';

<ProductRating value={4.6} count={128} size="md" />

Ручная установка

Если вы не используете пакет npm, создайте файл и вставьте следующий код: src/components/ProductRating.tsx + ProductRating.css:

ProductRating.tsx
'use client';

import type { CSSProperties } from 'react';
import './ProductRating.css';

/** class:list → className */
function cx(...args: unknown[]): string {
  const out: string[] = [];
  const walk = (v: unknown) => {
    if (!v) return;
    if (typeof v === 'string' || typeof v === 'number') out.push(String(v));
    else if (Array.isArray(v)) v.forEach(walk);
    else if (typeof v === 'object') for (const [k, on] of Object.entries(v as Record<string, unknown>)) if (on) out.push(k);
  };
  args.forEach(walk);
  return out.join(' ');
}

/** "a: b; --c: d" → style object */
function st(css: string | undefined): CSSProperties {
  const o: Record<string, string> = {};
  for (const decl of String(css ?? '').split(';')) {
    const i = decl.indexOf(':');
    if (i < 0) continue;
    const k = decl.slice(0, i).trim();
    if (k) o[k.startsWith('--') ? k : k.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = decl.slice(i + 1).trim();
  }
  return o as CSSProperties;
}

/**
 * ProductRating — Read-only star rating with value and review count.
 *
 * @param {number} value - Average rating, 0–5. Default 4.6.
 * @param {number} count - Number of reviews (optional).
 * @param {string} size - Visual size (sm|md|lg). Default 'sm'.
 * @param {boolean} showValue - Print the numeric value. Default true.
 * @param {string} label - Accessible label template; `{value}` and `{count}` are replaced.
 * @param {string} className - Extra class.
 *
 * Accessibility: exposed as one `role="img"` with a full text label; stars are decorative.
 */
export interface ProductRatingProps {
  value?: number;
  count?: number;
  size?: 'sm' | 'md' | 'lg';
  showValue?: boolean;
  label?: string;
  className?: string;
}

export function ProductRating({
  value = 4.6,
  count,
  size = 'sm',
  showValue = true,
  label = 'Rated {value} out of 5{count}',
  className = '',
}: ProductRatingProps) {
  const clamped = Math.max(0, Math.min(5, value));
  const pct = `${(clamped / 5) * 100}%`;
  const aria = label
    .replace('{value}', clamped.toFixed(1))
    .replace('{count}', count !== undefined ? `, ${count} reviews` : '');
  const stars = '★★★★★';
  return (
    <>
      <span className={cx(['p-rating', `p-rating--${size}`, className])} role="img" aria-label={aria} data-rk-0ac791="">
        <span className="p-rating__stars" aria-hidden="true" style={st(`--p-rating-fill: ${pct}`)} data-rk-0ac791="">
          <span className="p-rating__base" data-rk-0ac791="">{stars}</span>
          <span className="p-rating__fill" data-rk-0ac791="">{stars}</span>
        </span>
        {showValue && <span className="p-rating__value" aria-hidden="true" data-rk-0ac791="">{clamped.toFixed(1)}</span>}
        {count !== undefined && <span className="p-rating__count" aria-hidden="true" data-rk-0ac791="">({count})</span>}
      </span>
    </>
  );
}

export default ProductRating;
ProductRating.css
/* ProductRating — ported from astro-component-kit (ecommerce/ProductRating.astro) */

.p-rating:where([data-rk-0ac791]) {
  --p-rating-star: var(--c-primary-light, #d4a017);
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  font-size: 0.8rem;
  line-height: 1;
  color: var(--c-text-2, #a3a3a3);
}
.p-rating--md:where([data-rk-0ac791]) { font-size: 0.95rem; }
.p-rating--lg:where([data-rk-0ac791]) { font-size: 1.15rem; }

.p-rating__stars:where([data-rk-0ac791]) {
  position: relative;
  display: inline-block;
  letter-spacing: 0.08em;
}
.p-rating__base:where([data-rk-0ac791]) { color: rgb(var(--ink-rgb, 255 255 255) / 0.14); }
.p-rating__fill:where([data-rk-0ac791]) {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--p-rating-fill);
  overflow: hidden;
  white-space: nowrap;
  color: var(--p-rating-star);
}
.p-rating__value:where([data-rk-0ac791]) { font-weight: 700; color: var(--c-text-1, #fff); }
.p-rating__count:where([data-rk-0ac791]) { color: var(--c-text-3, #737373); }

Краткая информация

Категория
E-commerce
Имя файла
ProductRating.tsx
Зависимости
Нет — чистый React + CSS
Теги
ecommerceshopratingstarsreviews