דילוג לתוכן
uiify

Spinner

מחוון מונפש למצב טעינה.

דפדפנים
Chrome 123+Firefox 121+Safari 17.5+
שכבה
0
גודל חבילה דחוסה
459 B
מגבלת פריסה כפויה
0 ms
מגבלת Axe
0
תואם SSR
כן
חוזה מפורסם
סביבת בדיקות

מגרש ניסויים

Small
Medium
Large
import { Spinner } from "@gunkin/uiify";

export default function Example() {
  return <Spinner className="" label="Loading results" slotProps={{ label: { className: "" } }} />;
}
@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

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

@layer components {
  [data-uiify-spinner] {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--primary);
  }

  [data-uiify-spinner] > [data-part="label"] {
    color: var(--foreground);
  }

  [data-uiify-spinner]::before {
    flex: none;
    display: block;
    inline-size: 2rem;
    block-size: 2rem;
    content: "";
    border-radius: 50%;
    background: conic-gradient(
      from calc(-90deg + var(--uiify-spinner-tail)),
      currentcolor 0 var(--uiify-spinner-length),
      transparent 0
    );
    mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px));
    animation:
      uiify-spinner-rotate 2s linear infinite,
      uiify-spinner-orbit 1.5s ease-in-out infinite;
  }

  [data-uiify-spinner][data-value]::before {
    --uiify-spinner-tail: 0deg;
    --uiify-spinner-length: calc(attr(data-value type(<number>), 0) * 3.6deg);

    background: conic-gradient(
      from 0deg,
      currentcolor 0 var(--uiify-spinner-length),
      color-mix(in oklch, currentcolor 20%, transparent) 0
    );
    animation: none;
  }

  [data-uiify-spinner][data-size="sm"]::before {
    inline-size: 1.25rem;
    block-size: 1.25rem;
    mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 1px));
  }

  [data-uiify-spinner][data-size="lg"]::before {
    inline-size: 6.25rem;
    block-size: 6.25rem;
    mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px));
  }

  [data-uiify-spinner][data-align="center"] {
    margin-inline: auto;
  }

  [data-uiify-spinner][data-align="fixed"],
  [data-uiify-spinner][data-align="absolute"] {
    inset-block-start: 50%;
    inset-inline-start: 50%;
    translate: -50% -50%;
  }

  [data-uiify-spinner][data-align="fixed"] {
    position: fixed;
  }

  [data-uiify-spinner][data-align="absolute"] {
    position: absolute;
  }

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

  @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;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    [data-uiify-spinner]:not([data-value])::before {
      animation: uiify-spinner-orbit 2.5s ease-in-out infinite;
    }
  }
}
import { Spinner } from "@gunkin/uiify";

export default function Example() {
  return (
    <Spinner
      className={
        "relative inline-flex items-center [gap:0.5rem] text-primary before:flex-none before:block before:[inline-si" +
        "ze:2rem] before:[block-size:2rem] before:content-[''] before:rounded-[50%] before:[background:conic-gradien" +
        "t(_from_calc(-90deg_+_var(--uiify-spinner-tail)),_currentcolor_0_var(--uiify-spinner-length),_transparent_0" +
        "_)] before:[mask:radial-gradient(farthest-side,_transparent_calc(100%_-_4px),_#000_calc(100%_-_3px))] befor" +
        "e:[animation:uiify-spinner-rotate_2s_linear_infinite,_uiify-spinner-orbit_1.5s_ease-in-out_infinite] data-[" +
        "value]:before:[--uiify-spinner-tail:0deg] data-[value]:before:[--uiify-spinner-length:calc(attr(data-value_" +
        "type(<number>),_0)_*_3.6deg)] data-[value]:before:[background:conic-gradient(_from_0deg,_currentcolor_0_var" +
        "(--uiify-spinner-length),_color-mix(in_oklch,_currentcolor_20%,_transparent)_0_)] data-[value]:before:[anim" +
        "ation:none] data-[size=sm]:before:[inline-size:1.25rem] data-[size=sm]:before:[block-size:1.25rem] data-[si" +
        "ze=sm]:before:[mask:radial-gradient(farthest-side,_transparent_calc(100%_-_3px),_#000_calc(100%_-_1px))] da" +
        "ta-[size=lg]:before:[inline-size:6.25rem] data-[size=lg]:before:[block-size:6.25rem] data-[size=lg]:before:" +
        "[mask:radial-gradient(farthest-side,_transparent_calc(100%_-_4px),_#000_calc(100%_-_3px))] data-[align=cent" +
        "er]:[margin-inline:auto] data-[align=fixed]:[inset-block-start:50%] data-[align=fixed]:[inset-inline-start:" +
        "50%] data-[align=fixed]:[translate:-50%_-50%] data-[align=absolute]:[inset-block-start:50%] data-[align=abs" +
        "olute]:[inset-inline-start:50%] data-[align=absolute]:[translate:-50%_-50%] data-[align=fixed]:fixed data-[" +
        "align=absolute]:absolute motion-reduce:[&:not([data-value])::before]:[animation:uiify-spinner-orbit_2.5s_ea" +
        "se-in-out_infinite]"
      }
      label="Loading results"
      slotProps={{ label: { className: "text-foreground" } }}
    />
  );
}

API

Spinner

מאפייןטיפוסברירת מחדלתיאור
asElementType"div"משנה את תגית השורש המוצגת, למשל as="span".
classNamestring—שמות המחלקות מועברים לאלמנט השורש לצורך עיצוב בצד הלקוח.
align"center" | "fixed" | "absolute"—ממקם את מחוון הטעינה בזרימה הרגילה, בקיבוע לאזור התצוגה או במיקום מוחלט.
childrenReactNode—תוכן גלוי המוצג לצד השם הנגיש של אזור המצב.
valuenumber—אחוז קבוע בטווח 0–100. מחליף את ההנפשה בקשת סטטית ומשנה את התפקיד ל-progressbar.
delaynumber0מספר אלפיות השנייה להמתנה לפני הופעת מחוון הטעינה, המוחל ב-CSS ולכן אינו דורש JavaScript.
labelstring"Loading"שם נגיש המוכרז על ידי אזור המצב.
showLabelbooleanfalseמציג את התווית הגלויה כחלק [data-part="label"].
slotPropsSpinnerSlotProps—מאפיינים מובנים לתווית הגלויה שנוצרת.
size"small" | "default" | "large""default"שולט בקוטר מחוון הטעינה המבוסס על CSS בלבד.
renderReactElement | ((props, state) => ReactElement)—החלפת האלמנט המוצג תוך שימור ההתנהגות וקישורי הנגישות.

מקלדת

מקשפעולה

נגישות

משתמש באזור חי עם role="status" ועם aria-label. המחוון החזותי מבוסס על CSS בלבד ואינו מרנדר SVG.

נקודות חיבור לעיצוב

data-uiify-spinnerdata-statedata-delaydata-valuedata-sizedata-aligndata-part="label"--uiify-spinner-tail--uiify-spinner-length
דף זה תורגם אוטומטית וטרם נבדק.