انتقل إلى المحتوى
uiify

Rating

مدخل لاختيار تقييم من صف نجوم.

المتصفحات
Chrome 123+Firefox 121+Safari 17.5+
الفئة
0
الحجم المضغوط
1.22 kB
ميزانية التخطيط القسري
0 ms
ميزانية axe
0
متوافق مع SSR
نعم
مبني على
elements/choice
العقد المنشور
بيئة الاختبار

المختبر

Rating

افتراضي

import { Rating } from "@gunkin/uiify";

export default function Example() {
  return <Rating className="" defaultValue={3} id="movie-rating" />;
}
/* Rating — a native radio group of stars. Inputs are visually hidden;
   flex-direction: row-reverse restores left-to-right visual order over
   reversed DOM order. Each input+label pair sits in its own [data-part="item"]
   wrapper (ChoiceGroup's shape), so `~` alone can't reach across pairs —
   `:has()` promotes a checked/hovered item onto its later (= more-preferred,
   thanks to row-reverse) sibling wrappers. This keeps the uncontrolled rating functional without
   JavaScript. */

@layer components {
  [data-uiify-rating] {
    display: inline-flex;
    flex-direction: row-reverse;
    gap: var(--space-xs);
  }

  [data-uiify-rating] > [data-part="item"] > input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  [data-uiify-rating] > [data-part="item"] > label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--input);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: var(--transition-colors);
  }

  [data-uiify-rating] > [data-part="item"]:has(> input:checked) > label,
  [data-uiify-rating] > [data-part="item"]:has(> input:checked) ~ [data-part="item"] > label {
    color: var(--primary);
  }

  [data-uiify-rating]:not([data-disabled], [data-readonly])
    > [data-part="item"]:has(> label:hover)
    > label,
  [data-uiify-rating]:not([data-disabled], [data-readonly])
    > [data-part="item"]:has(> label:hover)
    ~ [data-part="item"]
    > label {
    color: var(--primary);
  }

  [data-uiify-rating] > [data-part="item"] > input:focus-visible ~ label {
    outline: none;
    box-shadow: 0 0 0 var(--ring-width) color-mix(in oklch, var(--ring) 16%, transparent);
    border-radius: var(--radius-xs);
    corner-shape: squircle;
  }

  [data-uiify-rating][data-readonly] > [data-part="item"] > label {
    cursor: default;
  }

  [data-uiify-rating][data-disabled] > [data-part="item"] > label {
    cursor: default;
    opacity: 0.5;
  }
}
import { Rating } from "@gunkin/uiify";

export default function Example() {
  return (
    <Rating
      className={
        "inline-flex [flex-direction:row-reverse] gap-xs [&>[data-part=item]>input]:absolute [&>[data-part=item]>inp" +
        "ut]:[inline-size:1px] [&>[data-part=item]>input]:[block-size:1px] [&>[data-part=item]>input]:[margin:-1px] " +
        "[&>[data-part=item]>input]:overflow-hidden [&>[data-part=item]>input]:[clip-path:inset(50%)] [&>[data-part=" +
        "item]>input]:whitespace-nowrap [&>[data-part=item]>label]:inline-flex [&>[data-part=item]>label]:items-cent" +
        "er [&>[data-part=item]>label]:justify-center [&>[data-part=item]>label]:text-input [&>[data-part=item]>labe" +
        "l]:[font-size:1.5rem] [&>[data-part=item]>label]:leading-none [&>[data-part=item]>label]:cursor-pointer [&>" +
        "[data-part=item]>label]:[transition:var(--transition-colors)] [&>[data-part=item]:has(>input:checked)>label" +
        "]:text-primary [&>[data-part=item]:has(>input:checked)~[data-part=item]>label]:text-primary [&:not([data-di" +
        "sabled],[data-readonly])>[data-part=item]:has(>label:hover)>label]:text-primary [&:not([data-disabled],[dat" +
        "a-readonly])>[data-part=item]:has(>label:hover)~[data-part=item]>label]:text-primary [&>[data-part=item]>in" +
        "put:focus-visible~label]:[outline:none] [&>[data-part=item]>input:focus-visible~label]:[box-shadow:0_0_0_va" +
        "r(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&>[data-part=item]>input:focus-visible~" +
        "label]:rounded-xs [&>[data-part=item]>input:focus-visible~label]:[corner-shape:squircle] [&[data-readonly]>" +
        "[data-part=item]>label]:cursor-default [&[data-disabled]>[data-part=item]>label]:cursor-default [&[data-dis" +
        "abled]>[data-part=item]>label]:opacity-50"
      }
      defaultValue={3}
      id="movie-rating"
    />
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('inline-flex [flex-direction:row-reverse] gap-xs [&>[data-part=item]>input]:absolute [&>[data-part=item]>input]:[inline-size:1px] [&>[data-part=item]>input]:[block-size:1px] [&>[data-part=item]>input]:[margin:-1px] [&>[data-part=item]>input]:overflow-hidden [&>[data-part=item]>input]:[clip-path:inset(50%)] [&>[data-part=item]>input]:whitespace-nowrap [&>[data-part=item]>label]:inline-flex [&>[data-part=item]>label]:items-center [&>[data-part=item]>label]:justify-center [&>[data-part=item]>label]:text-input [&>[data-part=item]>label]:[font-size:1.5rem] [&>[data-part=item]>label]:leading-none [&>[data-part=item]>label]:cursor-pointer [&>[data-part=item]>label]:[transition:var(--transition-colors)] [&>[data-part=item]:has(>input:checked)>label]:text-primary [&>[data-part=item]:has(>input:checked)~[data-part=item]>label]:text-primary [&:not([data-disabled],[data-readonly])>[data-part=item]:has(>label:hover)>label]:text-primary [&:not([data-disabled],[data-readonly])>[data-part=item]:has(>label:hover)~[data-part=item]>label]:text-primary [&>[data-part=item]>input:focus-visible~label]:[outline:none] [&>[data-part=item]>input:focus-visible~label]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&>[data-part=item]>input:focus-visible~label]:rounded-xs [&>[data-part=item]>input:focus-visible~label]:[corner-shape:squircle] [&[data-readonly]>[data-part=item]>label]:cursor-default [&[data-disabled]>[data-part=item]>label]:cursor-default [&[data-disabled]>[data-part=item]>label]:opacity-50');

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

API

Rating

الخاصيةالنوعافتراضيالوصف
id*string—بادئة المعرّف للمجموعة ولكل مدخل radio مولّد.
defaultValuenumber0التقييم المحدّد عند أول عرض؛ يعتمد التحديد ومعاينة التحويم على أزرار radio أصلية مع CSS، لذا يعملان دون JavaScript.
maxnumber5عدد عناصر التقييم المعروضة.
readOnlybooleanfalseيعرض التقييم دون السماح للمستخدم بتغييره.
disabledbooleanfalseيعطّل كل مدخل radio في التقييم.
classNamestring—الفئة المطبّقة على عنصر التقييم.
aria-labelstring—اسم مجموعة التقييم للتقنيات المساعدة.

لوحة المفاتيح

المفتاحالإجراء
Tabنقل التركيز إلى عنصر التحكم أو منه
Enter / Spaceالتفعيل عند التركيز (لعناصر التحكم الشبيهة بالأزرار)

إمكانية الوصول

يستخدم HTML الدلالي متى أمكن. افحص بنية HTML المعروضة في المختبر؛ لا تُضاف ARIA إلا حين لا تكفي العناصر الأصلية.

نقاط التنسيق

data-disabled