דילוג לתוכן
uiify

Color picker

שדה צבע המבוסס על בורר הצבע המובנה.

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

מגרש ניסויים

Color Picker

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

export default function Example() {
  return (
    <ColorPicker
      className=""
      defaultValue="#2563eb"
      id="color-picker"
      label="Brand color"
      name="brand-color"
      slotProps={{
        field: { className: "" },
        label: { className: "" },
        surface: { className: "" },
        control: { className: "" },
        input: { className: "" },
      }}
    />
  );
}
/* Text fields — Input and Textarea share the same surface. Invalid state keys
   off the [data-invalid] attribute the components emit. Textarea autosize uses
   the native field-sizing (Chrome 123+) when the component sets data-autosize. */

@layer components {
  :where([data-uiify-input], [data-uiify-textarea]) {
    display: block;
    inline-size: 100%;
    max-inline-size: 24rem;
    padding-block: var(--space-sm);
    padding-inline: var(--space-md);
    border: var(--border-width) solid var(--input);
    border-radius: var(--radius-md);
    background-color: var(--card);
    color: var(--foreground);
    font-size: var(--uiify-control-text);
    line-height: var(--leading-normal);
    transition: var(--transition-colors);
  }

  :where([data-uiify-input], [data-uiify-textarea])::placeholder {
    color: var(--muted-foreground);
  }

  :where([data-uiify-input], [data-uiify-textarea]):focus-visible {
    border-color: var(--primary);
  }

  :where([data-uiify-input], [data-uiify-textarea]):disabled,
  :where([data-uiify-input], [data-uiify-textarea])[data-disabled] {
    opacity: 0.5;
    cursor: not-allowed;
  }

  :where([data-uiify-input], [data-uiify-textarea])[data-invalid],
  :where([data-uiify-input], [data-uiify-textarea]):user-invalid {
    border-color: var(--destructive);
  }

  :where([data-uiify-input], [data-uiify-textarea])[data-invalid]:focus-visible {
    outline-color: var(--destructive);
  }

  /* Input is a pill sized like Button: --control-md tall and base text. Textarea keeps its own
     rounded rectangle. */
  [data-uiify-input] {
    box-sizing: border-box;
    block-size: var(--uiify-control-size, var(--control-md));
    padding-block: 0;
    padding-inline: var(--space-lg);
    border-radius: var(--radius-full);
    font-size: var(--uiify-control-font, var(--text-base));
  }

  [data-uiify-textarea] {
    min-block-size: 4lh;
    resize: block;
  }

  [data-uiify-textarea][data-autosize] {
    field-sizing: content;
    resize: none;
  }

  [data-uiify-field] {
    display: grid;
    gap: var(--space-sm);
    inline-size: 100%;
    max-inline-size: 24rem;
  }

  [data-uiify-field] [data-part="label"] {
    color: var(--foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    line-height: var(--leading-normal);
  }

  [data-uiify-field] [data-part="label"][data-required]::after {
    content: " *";
    color: var(--destructive);
  }

  [data-uiify-field] [data-part="description"] {
    margin: 0;
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
  }

  [data-uiify-field] [data-part="error"] {
    margin: 0;
    color: var(--destructive);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
  }

  /* Shared presence fade when an error message is mounted. */
  @media (prefers-reduced-motion: no-preference) {
    [data-uiify-field] [data-part="error"] {
      transition: opacity var(--duration-fast) var(--ease-out);
    }

    @starting-style {
      [data-uiify-field] [data-part="error"] {
        opacity: 0;
      }
    }
  }
}

/* Field supplies the label and read-only text input; color input overlays it. */

@layer components {
  [data-uiify-color-picker] [data-part="surface"] {
    position: relative;
    inline-size: 100%;
    max-inline-size: 24rem;
  }

  [data-uiify-color-picker] [data-part="control"] {
    padding-inline-end: calc(var(--space-md) + 2rem);
  }

  [data-uiify-color-picker] [data-part="surface"]::before,
  [data-uiify-color-picker] [data-part="surface"]::after {
    position: absolute;
    inset-block: 0;
    inset-inline-end: 11px;
    inline-size: 24px;
    block-size: 24px;
    margin-block: auto;
    border-radius: var(--radius-lg);
    content: "";
    z-index: 1;
    pointer-events: none;
  }

  [data-uiify-color-picker] [data-part="surface"]::before {
    background: conic-gradient(
        var(--muted) 25%,
        transparent 0 50%,
        var(--muted) 0 75%,
        transparent 0
      )
      0 0 / 17px 10px repeat;
  }

  [data-uiify-color-picker] [data-part="surface"]::after {
    background: linear-gradient(var(--uiify-color-picker-value), var(--uiify-color-picker-value));
  }

  [data-uiify-color-picker] [data-part="native-input"] {
    position: absolute;
    inset-block: 0;
    inset-inline: 0;
    inline-size: 100%;
    block-size: 100%;
    margin: 0;
    opacity: 0;
    z-index: 2;
    cursor: pointer;
  }

  [data-uiify-color-picker]
    [data-part="surface"]:has([data-part="native-input"]:focus-visible)
    [data-part="control"] {
    border-color: var(--primary);
    box-shadow: 0 0 0 var(--ring-width) color-mix(in oklch, var(--ring) 20%, transparent);
  }

  [data-uiify-color-picker]
    [data-part="surface"]:has([data-part="native-input"][aria-invalid="true"]:focus-visible)
    [data-part="control"] {
    box-shadow: 0 0 0 var(--ring-width) color-mix(in oklch, var(--destructive) 20%, transparent);
  }

  [data-uiify-color-picker]
    [data-part="surface"]:has([data-part="native-input"]:disabled)
    [data-part="control"] {
    cursor: not-allowed;
  }

  [data-uiify-color-picker] [data-part="native-input"]:disabled {
    cursor: not-allowed;
  }

  [data-uiify-color-picker] [data-part="label"][data-disabled] {
    color: var(--muted-foreground);
    cursor: not-allowed;
  }
}
import { ColorPicker } from "@gunkin/uiify";

export default function Example() {
  return (
    <ColorPicker
      className="grid gap-sm w-full max-w-96"
      defaultValue="#2563eb"
      id="color-picker"
      label="Brand color"
      name="brand-color"
      slotProps={{
        field: { className: "grid gap-sm w-full max-w-96" },
        label: {
          className:
            "text-sm font-medium [line-height:var(--leading-normal)] text-foreground " +
            "data-[disabled]:text-muted-foreground data-[disabled]:cursor-not-allowed",
        },
        surface: {
          className:
            "group/color-picker relative w-full [max-inline-size:24rem] before:absolute " +
            "before:[inset-block:0] before:[inset-inline-end:11px] before:size-6 " +
            "before:my-auto before:rounded-lg before:content-[''] before:z-[1] " +
            "before:pointer-events-none " +
            "before:[background:conic-gradient(var(--muted)_25%,transparent_0_50%,var(--muted)_0_75%,transparent_0)_0_0/17px_10px_repeat] " +
            "after:absolute after:[inset-block:0] after:[inset-inline-end:11px] after:size-6 " +
            "after:my-auto after:rounded-lg after:content-[''] after:z-[1] " +
            "after:pointer-events-none " +
            "after:[background:linear-gradient(var(--uiify-color-picker-value),var(--uiify-color-picker-value))]",
        },
        control: {
          className:
            "block w-full py-sm px-md pe-[calc(var(--space-md)_+_2rem)] " +
            "border-[length:var(--border-width)] border-solid border-input rounded-md bg-card " +
            "text-foreground [font-size:var(--uiify-control-text)] " +
            "[line-height:var(--leading-normal)] " +
            "group-has-[[data-part=native-input]:focus-visible]/color-picker:border-primary " +
            "group-has-[[data-part=native-input]:focus-visible]/color-picker:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_20%,_transparent)] " +
            "group-has-[[data-part=native-input]:disabled]/color-picker:cursor-not-allowed",
        },
        input: {
          className:
            "absolute inset-0 w-full h-full m-0 opacity-0 z-[2] cursor-pointer " + "disabled:cursor-not-allowed",
        },
      }}
    />
  );
}

API

ColorPicker

מאפייןטיפוסברירת מחדלתיאור
label*string—תווית גלויה לקלט הצבע המובנה.
valuestring—מחרוזת צבע CSS נוכחית; הופכת את הבורר למבוקר.
defaultValuestring—מחרוזת צבע CSS התחלתית לשימוש לא מבוקר, כגון "#2563eb".
onValueChange(value: string) => void—נקראת עם הצבע הנבחר כשהבורר המובנה משתנה.
onChangeChangeEventHandler<HTMLInputElement>—אירוע השינוי המובנה של קלט הצבע; יש לקרוא את הצבע מתוך currentTarget.value.
slotPropsColorPickerSlotProps—מאפיינים לשדה, לתווית, למשטח דוגמית הצבע, לפקד הערך ולקלט הבורר המובנה שנוצרים.
alphabooleanfalseמעביר את רמז השקיפות המובנה alpha. תמיכת הדפדפנים וממשק הבורר משתנים.
colorSpace"limited-srgb" | "display-p3""limited-srgb"בוחר את רמז מרחב הצבע המובנה המועבר לקלט.
renderReactElement | ((props, state) => ReactElement)—החלפת האלמנט המוצג תוך שימור ההתנהגות וקישורי הנגישות.

מקלדת

מקשפעולה
Tabמיקוד שדה הצבע
Enter / Spaceפתיחת הבורר המובנה

נגישות

אלמנט <input type="color"> מובנה ושקוף מונח מעל משטח הערך של Field. זהו פקד הטופס היחיד, הוא נשאר ניתן להפעלה במקלדת, מקבל תווית מ-Field.Label ופותח את בורר המערכת; onChange עדיין מקבל את האירוע המובנה. לפני הידרציה הבורר פועל, אך הערך המוצג נשאר ערך השרת. הרמזים Alpha ו-display-p3 תלויים בתמיכת הדפדפן.

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

data-uiify-color-pickerdata-uiify-fielddata-uiify-inputdata-disableddata-partdata-value--uiify-color-picker-value
דף זה תורגם אוטומטית וטרם נבדק.