Color picker
مدخل لون مبني على منتقي الألوان الأصلي.
- المتصفحات
- Chrome 123+, Firefox 121+, Safari 17.5+
- الفئة
- 1
- الحجم المضغوط
- 1.21 kB
- ميزانية التخطيط القسري
- 0 ms
- ميزانية axe
- 0
- متوافق مع SSR
- نعم
- العقد المنشور
- بيئة الاختبار
المختبر
Color Picker
- 1
- 2
- 3
- 4
- 5
import { ColorPicker } from "@gunkin/uiify";
export default function Example() {
return <ColorPicker className="" defaultValue="#2563eb" id="color-picker" label="Brand color" name="brand-color" />;
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
/* 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);
corner-shape: squircle;
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);
}
[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);
corner-shape: squircle;
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) 16%, 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;
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
import { ColorPicker } from "@gunkin/uiify";
export default function Example() {
return (
<ColorPicker
className={
"grid gap-sm w-full max-w-96 [&>[data-part=label]]:text-sm [&>[data-part=label]]:font-medium [&>[data-part=l" +
"abel]]:[line-height:var(--leading-normal)] [&>[data-part=label]]:text-foreground [&_[data-part=control]]:bl" +
"ock [&_[data-part=control]]:w-full [&_[data-part=control]]:py-sm [&_[data-part=control]]:px-md [&_[data-par" +
"t=control]]:border-[length:var(--border-width)] [&_[data-part=control]]:border-solid [&_[data-part=control]" +
"]:border-input [&_[data-part=control]]:rounded-md [&_[data-part=control]]:[corner-shape:squircle] [&_[data-" +
"part=control]]:bg-card [&_[data-part=control]]:text-foreground [&_[data-part=control]]:[font-size:var(--uii" +
"fy-control-text)] [&_[data-part=control]]:[line-height:var(--leading-normal)] [&_[data-part=surface]]:relat" +
"ive [&_[data-part=surface]]:w-full [&_[data-part=surface]]:[max-inline-size:24rem] [&_[data-part=control]]:" +
"pe-[calc(var(--space-md)_+_2rem)] [&_[data-part=surface]::before]:absolute [&_[data-part=surface]::before]:" +
"[inset-block:0] [&_[data-part=surface]::before]:[inset-inline-end:11px] [&_[data-part=surface]::before]:siz" +
"e-6 [&_[data-part=surface]::before]:my-auto [&_[data-part=surface]::before]:rounded-lg [&_[data-part=surfac" +
"e]::before]:[corner-shape:squircle] [&_[data-part=surface]::before]:content-[''] [&_[data-part=surface]::be" +
"fore]:z-[1] [&_[data-part=surface]::before]:pointer-events-none [&_[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-part=surface]::after]:absolute [&_[data-part=surface]::after]:[inset-block:0] [&_[data-part=surfac" +
"e]::after]:[inset-inline-end:11px] [&_[data-part=surface]::after]:size-6 [&_[data-part=surface]::after]:my-" +
"auto [&_[data-part=surface]::after]:rounded-lg [&_[data-part=surface]::after]:[corner-shape:squircle] [&_[d" +
"ata-part=surface]::after]:content-[''] [&_[data-part=surface]::after]:z-[1] [&_[data-part=surface]::after]:" +
"pointer-events-none [&_[data-part=surface]::after]:[background:linear-gradient(var(--uiify-color-picker-val" +
"ue),var(--uiify-color-picker-value))] [&_[data-part=native-input]]:absolute [&_[data-part=native-input]]:in" +
"set-0 [&_[data-part=native-input]]:w-full [&_[data-part=native-input]]:h-full [&_[data-part=native-input]]:" +
"m-0 [&_[data-part=native-input]]:opacity-0 [&_[data-part=native-input]]:z-[2] [&_[data-part=native-input]]:" +
"cursor-pointer [&_[data-part=surface]:has([data-part=native-input]:focus-visible)_[data-part=control]]:bord" +
"er-primary [&_[data-part=surface]:has([data-part=native-input]:focus-visible)_[data-part=control]]:[box-sha" +
"dow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&_[data-part=surface]:has([" +
"data-part=native-input]:disabled)_[data-part=control]]:cursor-not-allowed [&_[data-part=native-input]:disab" +
"led]:cursor-not-allowed [&_[data-part=label][data-disabled]]:text-muted-foreground [&_[data-part=label][dat" +
"a-disabled]]:cursor-not-allowed"
}
defaultValue="#2563eb"
id="color-picker"
label="Brand color"
name="brand-color"
/>
);
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
/* 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('grid gap-sm w-full max-w-96 [&>[data-part=label]]:text-sm [&>[data-part=label]]:font-medium [&>[data-part=label]]:[line-height:var(--leading-normal)] [&>[data-part=label]]:text-foreground [&_[data-part=control]]:block [&_[data-part=control]]:w-full [&_[data-part=control]]:py-sm [&_[data-part=control]]:px-md [&_[data-part=control]]:border-[length:var(--border-width)] [&_[data-part=control]]:border-solid [&_[data-part=control]]:border-input [&_[data-part=control]]:rounded-md [&_[data-part=control]]:[corner-shape:squircle] [&_[data-part=control]]:bg-card [&_[data-part=control]]:text-foreground [&_[data-part=control]]:[font-size:var(--uiify-control-text)] [&_[data-part=control]]:[line-height:var(--leading-normal)] [&_[data-part=surface]]:relative [&_[data-part=surface]]:w-full [&_[data-part=surface]]:[max-inline-size:24rem] [&_[data-part=control]]:pe-[calc(var(--space-md)_+_2rem)] [&_[data-part=surface]::before]:absolute [&_[data-part=surface]::before]:[inset-block:0] [&_[data-part=surface]::before]:[inset-inline-end:11px] [&_[data-part=surface]::before]:size-6 [&_[data-part=surface]::before]:my-auto [&_[data-part=surface]::before]:rounded-lg [&_[data-part=surface]::before]:[corner-shape:squircle] [&_[data-part=surface]::before]:z-[1] [&_[data-part=surface]::before]:pointer-events-none [&_[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-part=surface]::after]:absolute [&_[data-part=surface]::after]:[inset-block:0] [&_[data-part=surface]::after]:[inset-inline-end:11px] [&_[data-part=surface]::after]:size-6 [&_[data-part=surface]::after]:my-auto [&_[data-part=surface]::after]:rounded-lg [&_[data-part=surface]::after]:[corner-shape:squircle] [&_[data-part=surface]::after]:z-[1] [&_[data-part=surface]::after]:pointer-events-none [&_[data-part=surface]::after]:[background:linear-gradient(var(--uiify-color-picker-value),var(--uiify-color-picker-value))] [&_[data-part=native-input]]:absolute [&_[data-part=native-input]]:inset-0 [&_[data-part=native-input]]:w-full [&_[data-part=native-input]]:h-full [&_[data-part=native-input]]:m-0 [&_[data-part=native-input]]:opacity-0 [&_[data-part=native-input]]:z-[2] [&_[data-part=native-input]]:cursor-pointer [&_[data-part=surface]:has([data-part=native-input]:focus-visible)_[data-part=control]]:border-primary [&_[data-part=surface]:has([data-part=native-input]:focus-visible)_[data-part=control]]:[box-shadow:0_0_0_var(--ring-width)_color-mix(in_oklch,_var(--ring)_16%,_transparent)] [&_[data-part=surface]:has([data-part=native-input]:disabled)_[data-part=control]]:cursor-not-allowed [&_[data-part=native-input]:disabled]:cursor-not-allowed [&_[data-part=label][data-disabled]]:text-muted-foreground [&_[data-part=label][data-disabled]]:cursor-not-allowed');
@source inline("[&_[data-part=surface]::before]:content-[''] [&_[data-part=surface]::after]:content-['']");
@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
ColorPicker
| الخاصية | النوع | افتراضي | الوصف |
|---|---|---|---|
label* | string | — | تسمية مرئية لمدخل اللون الأصلي. |
value | string | — | نص لون CSS الحالي؛ يجعل المنتقي متحكّمًا به. |
defaultValue | string | — | نص لون CSS الأولي للاستخدام غير المتحكّم به، مثل "#2563eb". |
onValueChange | (value: string) => void | — | تُستدعى باللون المحدّد عند تغيّر المنتقي الأصلي. |
onChange | ChangeEventHandler<HTMLInputElement> | — | حدث change الأصلي لمدخل اللون؛ اقرأ اللون من currentTarget.value. |
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