Color picker
שדה צבע המבוסס על בורר הצבע המובנה.
- דפדפנים
- Chrome 123+Firefox 121+Safari 17.5+
- שכבה
- 1
- גודל חבילה דחוסה
- 1.65 kB
- מגבלת פריסה כפויה
- 0 ms
- מגבלת Axe
- 0
- תואם SSR
- כן
- חוזה מפורסם
- סביבת בדיקות
מגרש ניסויים
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 | — | תווית גלויה לקלט הצבע המובנה. |
value | string | — | מחרוזת צבע CSS נוכחית; הופכת את הבורר למבוקר. |
defaultValue | string | — | מחרוזת צבע CSS התחלתית לשימוש לא מבוקר, כגון "#2563eb". |
onValueChange | (value: string) => void | — | נקראת עם הצבע הנבחר כשהבורר המובנה משתנה. |
onChange | ChangeEventHandler<HTMLInputElement> | — | אירוע השינוי המובנה של קלט הצבע; יש לקרוא את הצבע מתוך currentTarget.value. |
slotProps | ColorPickerSlotProps | — | מאפיינים לשדה, לתווית, למשטח דוגמית הצבע, לפקד הערך ולקלט הבורר המובנה שנוצרים. |
alpha | boolean | false | מעביר את רמז השקיפות המובנה alpha. תמיכת הדפדפנים וממשק הבורר משתנים. |
colorSpace | "limited-srgb" | "display-p3" | "limited-srgb" | בוחר את רמז מרחב הצבע המובנה המועבר לקלט. |
render | ReactElement | ((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