@pixpilot/shadcn 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/components/index.cjs +6 -4
  2. package/dist/components/index.d.cts +6 -4
  3. package/dist/components/index.d.ts +6 -4
  4. package/dist/components/index.js +7 -5
  5. package/dist/components/ui/OrContinueWithSeparator.d.cts +2 -2
  6. package/dist/components/ui/OrContinueWithSeparator.d.ts +2 -2
  7. package/dist/components/ui/button.cjs +3 -1
  8. package/dist/components/ui/button.js +3 -1
  9. package/dist/components/ui/color-picker.cjs +1171 -0
  10. package/dist/components/ui/color-picker.d.cts +94 -0
  11. package/dist/components/ui/color-picker.d.ts +94 -0
  12. package/dist/components/ui/color-picker.js +1152 -0
  13. package/dist/components/ui/command.d.cts +10 -10
  14. package/dist/components/ui/command.d.ts +10 -10
  15. package/dist/components/ui/dialog.d.cts +11 -11
  16. package/dist/components/ui/dialog.d.ts +11 -11
  17. package/dist/components/ui/dropdown-menu.d.cts +16 -16
  18. package/dist/components/ui/dropdown-menu.d.ts +16 -16
  19. package/dist/components/ui/file-upload.d.cts +11 -11
  20. package/dist/components/ui/file-upload.d.ts +11 -11
  21. package/dist/components/ui/form.d.cts +7 -7
  22. package/dist/components/ui/form.d.ts +7 -7
  23. package/dist/components/ui/index.cjs +6 -4
  24. package/dist/components/ui/index.d.cts +6 -4
  25. package/dist/components/ui/index.d.ts +6 -4
  26. package/dist/components/ui/index.js +7 -5
  27. package/dist/components/ui/input-group.cjs +90 -0
  28. package/dist/components/ui/input-group.d.cts +43 -0
  29. package/dist/components/ui/input-group.d.ts +43 -0
  30. package/dist/components/ui/input-group.js +81 -0
  31. package/dist/components/ui/input.d.cts +2 -2
  32. package/dist/components/ui/input.d.ts +2 -2
  33. package/dist/components/ui/label.d.cts +2 -2
  34. package/dist/components/ui/label.d.ts +2 -2
  35. package/dist/components/ui/pagination.d.cts +8 -8
  36. package/dist/components/ui/pagination.d.ts +8 -8
  37. package/dist/components/ui/popover.d.cts +5 -5
  38. package/dist/components/ui/popover.d.ts +5 -5
  39. package/dist/components/ui/radio-group.d.cts +3 -3
  40. package/dist/components/ui/radio-group.d.ts +3 -3
  41. package/dist/components/ui/select.d.cts +11 -11
  42. package/dist/components/ui/select.d.ts +11 -11
  43. package/dist/components/ui/separator.d.cts +2 -2
  44. package/dist/components/ui/separator.d.ts +2 -2
  45. package/dist/components/ui/shadcn-io/tags/index.cjs +1 -1
  46. package/dist/components/ui/shadcn-io/tags/index.d.cts +10 -10
  47. package/dist/components/ui/shadcn-io/tags/index.d.ts +10 -10
  48. package/dist/components/ui/shadcn-io/tags/index.js +1 -1
  49. package/dist/components/ui/shadcn-io/tags-input-inline/index.d.cts +7 -7
  50. package/dist/components/ui/shadcn-io/tags-input-inline/index.d.ts +7 -7
  51. package/dist/components/ui/sheet.d.cts +9 -9
  52. package/dist/components/ui/sheet.d.ts +9 -9
  53. package/dist/components/ui/slider.d.cts +2 -2
  54. package/dist/components/ui/slider.d.ts +2 -2
  55. package/dist/components/ui/switch.d.cts +2 -2
  56. package/dist/components/ui/switch.d.ts +2 -2
  57. package/dist/components/ui/tabs.cjs +24 -4
  58. package/dist/components/ui/tabs.d.cts +15 -5
  59. package/dist/components/ui/tabs.d.ts +15 -5
  60. package/dist/components/ui/tabs.js +23 -4
  61. package/dist/components/ui/textarea.d.cts +2 -2
  62. package/dist/components/ui/textarea.d.ts +2 -2
  63. package/dist/components/visually-hidden-input.cjs +116 -0
  64. package/dist/components/visually-hidden-input.js +113 -0
  65. package/dist/hooks/use-as-ref.cjs +16 -0
  66. package/dist/hooks/use-as-ref.js +14 -0
  67. package/dist/hooks/use-isomorphic-layout-effect.cjs +9 -0
  68. package/dist/hooks/use-isomorphic-layout-effect.js +7 -0
  69. package/dist/hooks/use-lazy-ref.cjs +13 -0
  70. package/dist/hooks/use-lazy-ref.js +11 -0
  71. package/dist/index.cjs +24 -4
  72. package/dist/index.d.cts +7 -5
  73. package/dist/index.d.ts +7 -5
  74. package/dist/index.js +8 -6
  75. package/dist/lib/compose-refs.cjs +44 -0
  76. package/dist/lib/compose-refs.js +42 -0
  77. package/package.json +3 -3
@@ -0,0 +1,1152 @@
1
+ 'use client';
2
+
3
+
4
+ import { cn } from "../../lib/utils.js";
5
+ import "../../lib/index.js";
6
+ import { Button } from "./button.js";
7
+ import { Input } from "./input.js";
8
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./select.js";
10
+ import { useComposedRefs } from "../../lib/compose-refs.js";
11
+ import { VisuallyHiddenInput } from "../visually-hidden-input.js";
12
+ import { useIsomorphicLayoutEffect } from "../../hooks/use-isomorphic-layout-effect.js";
13
+ import { useAsRef } from "../../hooks/use-as-ref.js";
14
+ import { useLazyRef } from "../../hooks/use-lazy-ref.js";
15
+ import { cva } from "class-variance-authority";
16
+ import * as React from "react";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
18
+ import { Slot } from "@radix-ui/react-slot";
19
+ import { PipetteIcon } from "lucide-react";
20
+ import { useDirection } from "@radix-ui/react-direction";
21
+ import * as SliderPrimitive from "@radix-ui/react-slider";
22
+
23
+ //#region src/components/ui/color-picker.tsx
24
+ const ROOT_NAME = "ColorPicker";
25
+ const ROOT_IMPL_NAME = "ColorPickerImpl";
26
+ const TRIGGER_NAME = "ColorPickerTrigger";
27
+ const CONTENT_NAME = "ColorPickerContent";
28
+ const AREA_NAME = "ColorPickerArea";
29
+ const HUE_SLIDER_NAME = "ColorPickerHueSlider";
30
+ const ALPHA_SLIDER_NAME = "ColorPickerAlphaSlider";
31
+ const SWATCH_NAME = "ColorPickerSwatch";
32
+ const EYE_DROPPER_NAME = "ColorPickerEyeDropper";
33
+ const FORMAT_SELECT_NAME = "ColorPickerFormatSelect";
34
+ const INPUT_NAME = "ColorPickerInput";
35
+ const colorFormats = [
36
+ "hex",
37
+ "rgb",
38
+ "hsl",
39
+ "hsb"
40
+ ];
41
+ function hexToRgb(hex, alpha) {
42
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
43
+ return result ? {
44
+ r: Number.parseInt(result[1] ?? "0", 16),
45
+ g: Number.parseInt(result[2] ?? "0", 16),
46
+ b: Number.parseInt(result[3] ?? "0", 16),
47
+ a: alpha ?? 1
48
+ } : {
49
+ r: 0,
50
+ g: 0,
51
+ b: 0,
52
+ a: alpha ?? 1
53
+ };
54
+ }
55
+ function rgbToHex(color) {
56
+ const toHex = (n) => {
57
+ const hex = Math.round(n).toString(16);
58
+ return hex.length === 1 ? `0${hex}` : hex;
59
+ };
60
+ return `#${toHex(color.r)}${toHex(color.g)}${toHex(color.b)}`;
61
+ }
62
+ function rgbToHexWithAlpha(color) {
63
+ const toHex = (n) => {
64
+ const hex = Math.round(n).toString(16);
65
+ return hex.length === 1 ? `0${hex}` : hex;
66
+ };
67
+ const alphaByte = Math.min(255, Math.max(0, Math.round((color.a ?? 1) * 255)));
68
+ return `#${toHex(color.r)}${toHex(color.g)}${toHex(color.b)}${toHex(alphaByte)}`;
69
+ }
70
+ function rgbToHsv(color) {
71
+ const r = color.r / 255;
72
+ const g = color.g / 255;
73
+ const b = color.b / 255;
74
+ const max = Math.max(r, g, b);
75
+ const diff = max - Math.min(r, g, b);
76
+ let h = 0;
77
+ if (diff !== 0) switch (max) {
78
+ case r:
79
+ h = (g - b) / diff % 6;
80
+ break;
81
+ case g:
82
+ h = (b - r) / diff + 2;
83
+ break;
84
+ case b:
85
+ h = (r - g) / diff + 4;
86
+ break;
87
+ }
88
+ h = Math.round(h * 60);
89
+ if (h < 0) h += 360;
90
+ const s = max === 0 ? 0 : diff / max;
91
+ const v = max;
92
+ return {
93
+ h,
94
+ s: Math.round(s * 100),
95
+ v: Math.round(v * 100),
96
+ a: color.a
97
+ };
98
+ }
99
+ function hsvToRgb(hsv) {
100
+ const h = hsv.h / 360;
101
+ const s = hsv.s / 100;
102
+ const v = hsv.v / 100;
103
+ const i = Math.floor(h * 6);
104
+ const f = h * 6 - i;
105
+ const p = v * (1 - s);
106
+ const q = v * (1 - f * s);
107
+ const t = v * (1 - (1 - f) * s);
108
+ let r;
109
+ let g;
110
+ let b;
111
+ switch (i % 6) {
112
+ case 0:
113
+ r = v;
114
+ g = t;
115
+ b = p;
116
+ break;
117
+ case 1:
118
+ r = q;
119
+ g = v;
120
+ b = p;
121
+ break;
122
+ case 2:
123
+ r = p;
124
+ g = v;
125
+ b = t;
126
+ break;
127
+ case 3:
128
+ r = p;
129
+ g = q;
130
+ b = v;
131
+ break;
132
+ case 4:
133
+ r = t;
134
+ g = p;
135
+ b = v;
136
+ break;
137
+ case 5:
138
+ r = v;
139
+ g = p;
140
+ b = q;
141
+ break;
142
+ default:
143
+ r = 0;
144
+ g = 0;
145
+ b = 0;
146
+ }
147
+ return {
148
+ r: Math.round(r * 255),
149
+ g: Math.round(g * 255),
150
+ b: Math.round(b * 255),
151
+ a: hsv.a
152
+ };
153
+ }
154
+ function colorToString(color, format = "hex") {
155
+ switch (format) {
156
+ case "hex": return color.a < 1 ? rgbToHexWithAlpha(color) : rgbToHex(color);
157
+ case "rgb": return color.a < 1 ? `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})` : `rgb(${color.r}, ${color.g}, ${color.b})`;
158
+ case "hsl": {
159
+ const hsl = rgbToHsl(color);
160
+ return color.a < 1 ? `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${color.a})` : `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
161
+ }
162
+ case "hsb": {
163
+ const hsv = rgbToHsv(color);
164
+ return color.a < 1 ? `hsba(${hsv.h}, ${hsv.s}%, ${hsv.v}%, ${color.a})` : `hsb(${hsv.h}, ${hsv.s}%, ${hsv.v}%)`;
165
+ }
166
+ default: return rgbToHex(color);
167
+ }
168
+ }
169
+ function rgbToHsl(color) {
170
+ const r = color.r / 255;
171
+ const g = color.g / 255;
172
+ const b = color.b / 255;
173
+ const max = Math.max(r, g, b);
174
+ const min = Math.min(r, g, b);
175
+ const diff = max - min;
176
+ const sum = max + min;
177
+ const l = sum / 2;
178
+ let h = 0;
179
+ let s = 0;
180
+ if (diff !== 0) {
181
+ s = l > .5 ? diff / (2 - sum) : diff / sum;
182
+ if (max === r) h = (g - b) / diff + (g < b ? 6 : 0);
183
+ else if (max === g) h = (b - r) / diff + 2;
184
+ else if (max === b) h = (r - g) / diff + 4;
185
+ h /= 6;
186
+ }
187
+ return {
188
+ h: Math.round(h * 360),
189
+ s: Math.round(s * 100),
190
+ l: Math.round(l * 100)
191
+ };
192
+ }
193
+ function hslToRgb(hsl, alpha = 1) {
194
+ const h = hsl.h / 360;
195
+ const s = hsl.s / 100;
196
+ const l = hsl.l / 100;
197
+ const c = (1 - Math.abs(2 * l - 1)) * s;
198
+ const x = c * (1 - Math.abs(h * 6 % 2 - 1));
199
+ const m = l - c / 2;
200
+ let r = 0;
201
+ let g = 0;
202
+ let b = 0;
203
+ if (h >= 0 && h < 1 / 6) {
204
+ r = c;
205
+ g = x;
206
+ b = 0;
207
+ } else if (h >= 1 / 6 && h < 2 / 6) {
208
+ r = x;
209
+ g = c;
210
+ b = 0;
211
+ } else if (h >= 2 / 6 && h < 3 / 6) {
212
+ r = 0;
213
+ g = c;
214
+ b = x;
215
+ } else if (h >= 3 / 6 && h < 4 / 6) {
216
+ r = 0;
217
+ g = x;
218
+ b = c;
219
+ } else if (h >= 4 / 6 && h < 5 / 6) {
220
+ r = x;
221
+ g = 0;
222
+ b = c;
223
+ } else if (h >= 5 / 6 && h < 1) {
224
+ r = c;
225
+ g = 0;
226
+ b = x;
227
+ }
228
+ return {
229
+ r: Math.round((r + m) * 255),
230
+ g: Math.round((g + m) * 255),
231
+ b: Math.round((b + m) * 255),
232
+ a: alpha
233
+ };
234
+ }
235
+ function parseColorString(value) {
236
+ const trimmed = value.trim();
237
+ if (trimmed.startsWith("#")) {
238
+ const hexMatch = trimmed.match(/^#([a-f0-9]{3}|[a-f0-9]{4}|[a-f0-9]{6}|[a-f0-9]{8})$/i);
239
+ if (hexMatch) {
240
+ const hex = (hexMatch[1] ?? "").toLowerCase();
241
+ if (hex.length === 3 || hex.length === 4) return {
242
+ r: Number.parseInt(hex[0] ? `${hex[0]}${hex[0]}` : "00", 16),
243
+ g: Number.parseInt(hex[1] ? `${hex[1]}${hex[1]}` : "00", 16),
244
+ b: Number.parseInt(hex[2] ? `${hex[2]}${hex[2]}` : "00", 16),
245
+ a: hex.length === 4 ? Number.parseInt(hex[3] ? `${hex[3]}${hex[3]}` : "ff", 16) / 255 : 1
246
+ };
247
+ if (hex.length === 6 || hex.length === 8) return {
248
+ r: Number.parseInt(hex.slice(0, 2) || "00", 16),
249
+ g: Number.parseInt(hex.slice(2, 4) || "00", 16),
250
+ b: Number.parseInt(hex.slice(4, 6) || "00", 16),
251
+ a: hex.length === 8 ? Number.parseInt(hex.slice(6, 8) || "ff", 16) / 255 : 1
252
+ };
253
+ }
254
+ }
255
+ const rgbMatch = trimmed.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)$/);
256
+ if (rgbMatch) return {
257
+ r: Number.parseInt(rgbMatch[1] ?? "0", 10),
258
+ g: Number.parseInt(rgbMatch[2] ?? "0", 10),
259
+ b: Number.parseInt(rgbMatch[3] ?? "0", 10),
260
+ a: rgbMatch[4] ? Number.parseFloat(rgbMatch[4]) : 1
261
+ };
262
+ const hslMatch = trimmed.match(/^hsla?\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(?:,\s*([\d.]+)\s*)?\)$/);
263
+ if (hslMatch) {
264
+ const h = Number.parseInt(hslMatch[1] ?? "0", 10);
265
+ const s = Number.parseInt(hslMatch[2] ?? "0", 10) / 100;
266
+ const l = Number.parseInt(hslMatch[3] ?? "0", 10) / 100;
267
+ const a = hslMatch[4] ? Number.parseFloat(hslMatch[4]) : 1;
268
+ const c = (1 - Math.abs(2 * l - 1)) * s;
269
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
270
+ const m = l - c / 2;
271
+ let r = 0;
272
+ let g = 0;
273
+ let b = 0;
274
+ if (h >= 0 && h < 60) {
275
+ r = c;
276
+ g = x;
277
+ b = 0;
278
+ } else if (h >= 60 && h < 120) {
279
+ r = x;
280
+ g = c;
281
+ b = 0;
282
+ } else if (h >= 120 && h < 180) {
283
+ r = 0;
284
+ g = c;
285
+ b = x;
286
+ } else if (h >= 180 && h < 240) {
287
+ r = 0;
288
+ g = x;
289
+ b = c;
290
+ } else if (h >= 240 && h < 300) {
291
+ r = x;
292
+ g = 0;
293
+ b = c;
294
+ } else if (h >= 300 && h < 360) {
295
+ r = c;
296
+ g = 0;
297
+ b = x;
298
+ }
299
+ return {
300
+ r: Math.round((r + m) * 255),
301
+ g: Math.round((g + m) * 255),
302
+ b: Math.round((b + m) * 255),
303
+ a
304
+ };
305
+ }
306
+ const hsbMatch = trimmed.match(/^hsba?\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(?:,\s*([\d.]+)\s*)?\)$/);
307
+ if (hsbMatch) return hsvToRgb({
308
+ h: Number.parseInt(hsbMatch[1] ?? "0", 10),
309
+ s: Number.parseInt(hsbMatch[2] ?? "0", 10),
310
+ v: Number.parseInt(hsbMatch[3] ?? "0", 10),
311
+ a: hsbMatch[4] ? Number.parseFloat(hsbMatch[4]) : 1
312
+ });
313
+ return null;
314
+ }
315
+ function areColorsEqual(a, b) {
316
+ return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;
317
+ }
318
+ function areHsvEqual(a, b) {
319
+ return a.h === b.h && a.s === b.s && a.v === b.v && a.a === b.a;
320
+ }
321
+ const StoreContext = React.createContext(null);
322
+ function useStoreContext(consumerName) {
323
+ const context = React.use(StoreContext);
324
+ if (!context) throw new Error(`\`${consumerName}\` must be used within \`ColorPickerRoot\``);
325
+ return context;
326
+ }
327
+ function useStore(selector) {
328
+ const store = useStoreContext("useStore");
329
+ const getSnapshot = React.useCallback(() => selector(store.getState()), [store, selector]);
330
+ return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
331
+ }
332
+ const ColorPickerContext = React.createContext(null);
333
+ function useColorPickerContext(consumerName) {
334
+ const context = React.use(ColorPickerContext);
335
+ if (!context) throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
336
+ return context;
337
+ }
338
+ function ColorPicker(props) {
339
+ const { value: valueProp, defaultValue = "#000000", onValueChange, format: formatProp, defaultFormat = "hex", onFormatChange, defaultOpen, open: openProp, onOpenChange, name, disabled, inline, readOnly, required,...rootProps } = props;
340
+ const listenersRef = useLazyRef(() => /* @__PURE__ */ new Set());
341
+ const stateRef = useLazyRef(() => {
342
+ const color = hexToRgb(valueProp ?? defaultValue);
343
+ return {
344
+ color,
345
+ hsv: rgbToHsv(color),
346
+ open: openProp ?? defaultOpen ?? false,
347
+ format: formatProp ?? defaultFormat
348
+ };
349
+ });
350
+ const propsRef = useAsRef({
351
+ onValueChange,
352
+ onOpenChange,
353
+ onFormatChange
354
+ });
355
+ const store = React.useMemo(() => {
356
+ return {
357
+ subscribe: (cb) => {
358
+ listenersRef.current.add(cb);
359
+ return () => listenersRef.current.delete(cb);
360
+ },
361
+ getState: () => stateRef.current,
362
+ setColor: (value) => {
363
+ if (areColorsEqual(stateRef.current.color, value)) return;
364
+ const prevState = { ...stateRef.current };
365
+ stateRef.current.color = value;
366
+ if (propsRef.current.onValueChange) {
367
+ const colorString = colorToString(value, prevState.format);
368
+ propsRef.current.onValueChange(colorString);
369
+ }
370
+ store.notify();
371
+ },
372
+ setHsv: (value) => {
373
+ if (areHsvEqual(stateRef.current.hsv, value)) return;
374
+ const prevState = { ...stateRef.current };
375
+ stateRef.current.hsv = value;
376
+ if (propsRef.current.onValueChange) {
377
+ const colorString = colorToString(hsvToRgb(value), prevState.format);
378
+ propsRef.current.onValueChange(colorString);
379
+ }
380
+ store.notify();
381
+ },
382
+ syncFromValueProp: (value) => {
383
+ const currentState = stateRef.current;
384
+ const parsed = parseColorString(value);
385
+ let color = parsed || {
386
+ r: 0,
387
+ g: 0,
388
+ b: 0,
389
+ a: currentState.color.a
390
+ };
391
+ if (parsed && typeof currentState.color.a === "number") {
392
+ const trimmed = value.trim().toLowerCase();
393
+ if (trimmed.startsWith("#") && (trimmed.length === 4 || trimmed.length === 7) && parsed.a === 1 && currentState.color.a !== 1) color = {
394
+ ...parsed,
395
+ a: currentState.color.a
396
+ };
397
+ }
398
+ const nextColor = color;
399
+ const nextHsv = rgbToHsv(nextColor);
400
+ const didChangeColor = !areColorsEqual(currentState.color, nextColor);
401
+ const didChangeHsv = !areHsvEqual(currentState.hsv, nextHsv);
402
+ if (!didChangeColor && !didChangeHsv) return;
403
+ if (didChangeColor) currentState.color = nextColor;
404
+ if (didChangeHsv) currentState.hsv = nextHsv;
405
+ store.notify();
406
+ },
407
+ setOpen: (value) => {
408
+ if (Object.is(stateRef.current.open, value)) return;
409
+ stateRef.current.open = value;
410
+ if (propsRef.current.onOpenChange) propsRef.current.onOpenChange(value);
411
+ store.notify();
412
+ },
413
+ setFormat: (value) => {
414
+ if (Object.is(stateRef.current.format, value)) return;
415
+ stateRef.current.format = value;
416
+ if (propsRef.current.onFormatChange) propsRef.current.onFormatChange(value);
417
+ store.notify();
418
+ },
419
+ notify: () => {
420
+ for (const cb of listenersRef.current) cb();
421
+ }
422
+ };
423
+ }, [
424
+ listenersRef,
425
+ stateRef,
426
+ propsRef
427
+ ]);
428
+ return /* @__PURE__ */ jsx(StoreContext.Provider, {
429
+ value: store,
430
+ children: /* @__PURE__ */ jsx(ColorPickerImpl, {
431
+ ...rootProps,
432
+ value: valueProp,
433
+ defaultOpen,
434
+ open: openProp,
435
+ name,
436
+ disabled,
437
+ inline,
438
+ readOnly,
439
+ required
440
+ })
441
+ });
442
+ }
443
+ function ColorPickerImpl(props) {
444
+ const { value: valueProp, dir: dirProp, defaultOpen, open: openProp, name, ref, asChild, disabled, inline, modal, readOnly, required,...rootProps } = props;
445
+ const store = useStoreContext(ROOT_IMPL_NAME);
446
+ const dir = useDirection(dirProp);
447
+ const [formTrigger, setFormTrigger] = React.useState(null);
448
+ const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));
449
+ const isFormControl = formTrigger ? Boolean(formTrigger.closest("form")) : true;
450
+ useIsomorphicLayoutEffect(() => {
451
+ if (valueProp !== void 0) store.syncFromValueProp(valueProp);
452
+ }, [valueProp]);
453
+ useIsomorphicLayoutEffect(() => {
454
+ if (openProp !== void 0) store.setOpen(openProp);
455
+ }, [openProp]);
456
+ const contextValue = React.useMemo(() => ({
457
+ dir,
458
+ disabled,
459
+ inline,
460
+ readOnly,
461
+ required
462
+ }), [
463
+ dir,
464
+ disabled,
465
+ inline,
466
+ readOnly,
467
+ required
468
+ ]);
469
+ const value = useStore((state) => rgbToHex(state.color));
470
+ const open = useStore((state) => state.open);
471
+ const RootPrimitive = asChild ? Slot : "div";
472
+ if (inline) return /* @__PURE__ */ jsxs(ColorPickerContext.Provider, {
473
+ value: contextValue,
474
+ children: [/* @__PURE__ */ jsx(RootPrimitive, {
475
+ ...rootProps,
476
+ ref: composedRef
477
+ }), isFormControl && /* @__PURE__ */ jsx(VisuallyHiddenInput, {
478
+ type: "hidden",
479
+ control: formTrigger,
480
+ name,
481
+ value,
482
+ disabled,
483
+ readOnly,
484
+ required
485
+ })]
486
+ });
487
+ return /* @__PURE__ */ jsx(ColorPickerContext.Provider, {
488
+ value: contextValue,
489
+ children: /* @__PURE__ */ jsxs(Popover, {
490
+ defaultOpen,
491
+ open,
492
+ onOpenChange: store.setOpen,
493
+ modal,
494
+ children: [/* @__PURE__ */ jsx(RootPrimitive, {
495
+ ...rootProps,
496
+ ref: composedRef
497
+ }), isFormControl && /* @__PURE__ */ jsx(VisuallyHiddenInput, {
498
+ type: "hidden",
499
+ control: formTrigger,
500
+ name,
501
+ value,
502
+ disabled,
503
+ readOnly,
504
+ required
505
+ })]
506
+ })
507
+ });
508
+ }
509
+ function ColorPickerTrigger({ variant,...props }) {
510
+ const { asChild, disabled,...triggerProps } = props;
511
+ const context = useColorPickerContext(TRIGGER_NAME);
512
+ return /* @__PURE__ */ jsx(PopoverTrigger, {
513
+ asChild: true,
514
+ disabled: disabled || context.disabled,
515
+ children: /* @__PURE__ */ jsx(asChild ? Slot : Button, {
516
+ "data-slot": "color-picker-trigger",
517
+ ...asChild ? {} : { variant },
518
+ ...triggerProps
519
+ })
520
+ });
521
+ }
522
+ function ColorPickerContent(props) {
523
+ const { asChild, className, children,...popoverContentProps } = props;
524
+ if (useColorPickerContext(CONTENT_NAME).inline) return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
525
+ "data-slot": "color-picker-content",
526
+ ...popoverContentProps,
527
+ className: cn("flex w-[340px] flex-col gap-4 p-4", className),
528
+ children
529
+ });
530
+ return /* @__PURE__ */ jsx(PopoverContent, {
531
+ "data-slot": "color-picker-content",
532
+ asChild,
533
+ ...popoverContentProps,
534
+ className: cn("flex w-[340px] flex-col gap-4 p-4", className),
535
+ children
536
+ });
537
+ }
538
+ function ColorPickerArea(props) {
539
+ const { asChild, onPointerDown: onPointerDownProp, onPointerMove: onPointerMoveProp, onPointerUp: onPointerUpProp, className, ref,...areaProps } = props;
540
+ const propsRef = useAsRef({
541
+ onPointerDown: onPointerDownProp,
542
+ onPointerMove: onPointerMoveProp,
543
+ onPointerUp: onPointerUpProp
544
+ });
545
+ const context = useColorPickerContext(AREA_NAME);
546
+ const store = useStoreContext(AREA_NAME);
547
+ const hsv = useStore((state) => state.hsv);
548
+ const isDraggingRef = React.useRef(false);
549
+ const areaRef = React.useRef(null);
550
+ const composedRef = useComposedRefs(ref, areaRef);
551
+ const updateColorFromPosition = React.useCallback((clientX, clientY) => {
552
+ if (!areaRef.current) return;
553
+ const rect = areaRef.current.getBoundingClientRect();
554
+ const x = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
555
+ const y = Math.max(0, Math.min(1, 1 - (clientY - rect.top) / rect.height));
556
+ const newHsv = {
557
+ h: hsv?.h ?? 0,
558
+ s: Math.round(x * 100),
559
+ v: Math.round(y * 100),
560
+ a: hsv?.a ?? 1
561
+ };
562
+ store.setHsv(newHsv);
563
+ store.setColor(hsvToRgb(newHsv));
564
+ }, [hsv, store]);
565
+ const onPointerDown = React.useCallback((event) => {
566
+ if (context.disabled) return;
567
+ propsRef.current.onPointerDown?.(event);
568
+ if (event.defaultPrevented) return;
569
+ isDraggingRef.current = true;
570
+ areaRef.current?.setPointerCapture(event.pointerId);
571
+ updateColorFromPosition(event.clientX, event.clientY);
572
+ }, [
573
+ context.disabled,
574
+ updateColorFromPosition,
575
+ propsRef
576
+ ]);
577
+ const onPointerMove = React.useCallback((event) => {
578
+ propsRef.current.onPointerMove?.(event);
579
+ if (event.defaultPrevented) return;
580
+ if (isDraggingRef.current) updateColorFromPosition(event.clientX, event.clientY);
581
+ }, [updateColorFromPosition, propsRef]);
582
+ const onPointerUp = React.useCallback((event) => {
583
+ propsRef.current.onPointerUp?.(event);
584
+ if (event.defaultPrevented) return;
585
+ isDraggingRef.current = false;
586
+ areaRef.current?.releasePointerCapture(event.pointerId);
587
+ }, [propsRef]);
588
+ const backgroundHue = hsvToRgb({
589
+ h: hsv?.h ?? 0,
590
+ s: 100,
591
+ v: 100,
592
+ a: 1
593
+ });
594
+ return /* @__PURE__ */ jsxs(asChild ? Slot : "div", {
595
+ "data-slot": "color-picker-area",
596
+ ...areaProps,
597
+ className: cn("relative h-40 w-full cursor-crosshair touch-none rounded-sm border", context.disabled && "pointer-events-none opacity-50", className),
598
+ ref: composedRef,
599
+ onPointerDown,
600
+ onPointerMove,
601
+ onPointerUp,
602
+ children: [/* @__PURE__ */ jsxs("div", {
603
+ className: "absolute inset-0 overflow-hidden rounded-sm",
604
+ children: [
605
+ /* @__PURE__ */ jsx("div", {
606
+ className: "absolute inset-0",
607
+ style: { backgroundColor: `rgb(${backgroundHue.r}, ${backgroundHue.g}, ${backgroundHue.b})` }
608
+ }),
609
+ /* @__PURE__ */ jsx("div", {
610
+ className: "absolute inset-0",
611
+ style: { background: "linear-gradient(to right, #fff, transparent)" }
612
+ }),
613
+ /* @__PURE__ */ jsx("div", {
614
+ className: "absolute inset-0",
615
+ style: { background: "linear-gradient(to bottom, transparent, #000)" }
616
+ })
617
+ ]
618
+ }), /* @__PURE__ */ jsx("div", {
619
+ className: "absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm",
620
+ style: {
621
+ left: `${hsv?.s ?? 0}%`,
622
+ top: `${100 - (hsv?.v ?? 0)}%`
623
+ }
624
+ })]
625
+ });
626
+ }
627
+ function ColorPickerHueSlider(props) {
628
+ const { className,...sliderProps } = props;
629
+ const context = useColorPickerContext(HUE_SLIDER_NAME);
630
+ const store = useStoreContext(HUE_SLIDER_NAME);
631
+ const hsv = useStore((state) => state.hsv);
632
+ const onValueChange = React.useCallback((values) => {
633
+ const newHsv = {
634
+ h: values[0] ?? 0,
635
+ s: hsv?.s ?? 0,
636
+ v: hsv?.v ?? 0,
637
+ a: hsv?.a ?? 1
638
+ };
639
+ store.setHsv(newHsv);
640
+ store.setColor(hsvToRgb(newHsv));
641
+ }, [hsv, store]);
642
+ return /* @__PURE__ */ jsxs(SliderPrimitive.Root, {
643
+ "data-slot": "color-picker-hue-slider",
644
+ ...sliderProps,
645
+ max: 360,
646
+ step: 1,
647
+ className: cn("relative flex w-full touch-none select-none items-center", className),
648
+ value: [hsv?.h ?? 0],
649
+ onValueChange,
650
+ disabled: context.disabled,
651
+ children: [/* @__PURE__ */ jsx(SliderPrimitive.Track, {
652
+ className: "relative h-3 w-full grow overflow-hidden rounded-full bg-[linear-gradient(to_right,#ff0000_0%,#ffff00_16.66%,#00ff00_33.33%,#00ffff_50%,#0000ff_66.66%,#ff00ff_83.33%,#ff0000_100%)]",
653
+ children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full" })
654
+ }), /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "block size-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" })]
655
+ });
656
+ }
657
+ function ColorPickerAlphaSlider(props) {
658
+ const { className,...sliderProps } = props;
659
+ const context = useColorPickerContext(ALPHA_SLIDER_NAME);
660
+ const store = useStoreContext(ALPHA_SLIDER_NAME);
661
+ const color = useStore((state) => state.color);
662
+ const hsv = useStore((state) => state.hsv);
663
+ const onValueChange = React.useCallback((values) => {
664
+ const alpha = (values[0] ?? 0) / 100;
665
+ const newColor = {
666
+ ...color,
667
+ a: alpha
668
+ };
669
+ const newHsv = {
670
+ ...hsv,
671
+ a: alpha
672
+ };
673
+ store.setColor(newColor);
674
+ store.setHsv(newHsv);
675
+ }, [
676
+ color,
677
+ hsv,
678
+ store
679
+ ]);
680
+ const gradientColor = `rgb(${color?.r ?? 0}, ${color?.g ?? 0}, ${color?.b ?? 0})`;
681
+ return /* @__PURE__ */ jsxs(SliderPrimitive.Root, {
682
+ "data-slot": "color-picker-alpha-slider",
683
+ ...sliderProps,
684
+ max: 100,
685
+ step: 1,
686
+ disabled: context.disabled,
687
+ className: cn("relative flex w-full touch-none select-none items-center", className),
688
+ value: [Math.round((color?.a ?? 1) * 100)],
689
+ onValueChange,
690
+ children: [/* @__PURE__ */ jsxs(SliderPrimitive.Track, {
691
+ className: "relative h-3 w-full grow overflow-hidden rounded-full",
692
+ style: {
693
+ background: "linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%)",
694
+ backgroundSize: "8px 8px",
695
+ backgroundPosition: "0 0, 0 4px, 4px -4px, -4px 0px"
696
+ },
697
+ children: [/* @__PURE__ */ jsx("div", {
698
+ className: "absolute inset-0 rounded-full",
699
+ style: { background: `linear-gradient(to right, transparent, ${gradientColor})` }
700
+ }), /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full" })]
701
+ }), /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "block size-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" })]
702
+ });
703
+ }
704
+ function ColorPickerSwatch(props) {
705
+ const { asChild, className,...swatchProps } = props;
706
+ const context = useColorPickerContext(SWATCH_NAME);
707
+ const color = useStore((state) => state.color);
708
+ const format = useStore((state) => state.format);
709
+ const backgroundStyle = React.useMemo(() => {
710
+ if (!color) return { background: "linear-gradient(to bottom right, transparent calc(50% - 1px), hsl(var(--destructive)) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) no-repeat" };
711
+ const colorString = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`;
712
+ if (color.a < 1) return { background: `linear-gradient(${colorString}, ${colorString}), repeating-conic-gradient(#ccc 0% 25%, #fff 0% 50%) 0% 50% / 8px 8px` };
713
+ return { backgroundColor: colorString };
714
+ }, [color]);
715
+ const ariaLabel = !color ? "No color selected" : `Current color: ${colorToString(color, format)}`;
716
+ return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
717
+ role: "img",
718
+ "aria-label": ariaLabel,
719
+ "data-slot": "color-picker-swatch",
720
+ ...swatchProps,
721
+ className: cn("box-border size-8 rounded-sm border shadow-sm", context.disabled && "opacity-50", className),
722
+ style: {
723
+ ...backgroundStyle,
724
+ forcedColorAdjust: "none"
725
+ }
726
+ });
727
+ }
728
+ function ColorPickerEyeDropper(props) {
729
+ const { size: sizeProp, children, disabled,...buttonProps } = props;
730
+ const context = useColorPickerContext(EYE_DROPPER_NAME);
731
+ const store = useStoreContext(EYE_DROPPER_NAME);
732
+ const color = useStore((state) => state.color);
733
+ const isDisabled = disabled || context.disabled;
734
+ const onEyeDropper = React.useCallback(async () => {
735
+ if (!window.EyeDropper) return;
736
+ try {
737
+ const result = await new window.EyeDropper().open();
738
+ if (result.sRGBHex) {
739
+ const currentAlpha = color?.a ?? 1;
740
+ const newColor = hexToRgb(result.sRGBHex, currentAlpha);
741
+ const newHsv = rgbToHsv(newColor);
742
+ store.setColor(newColor);
743
+ store.setHsv(newHsv);
744
+ }
745
+ } catch (error) {
746
+ console.warn("EyeDropper error:", error);
747
+ }
748
+ }, [color, store]);
749
+ if (!(typeof window !== "undefined" && Boolean(window.EyeDropper))) return null;
750
+ const size = sizeProp ?? (children ? "default" : "icon");
751
+ return /* @__PURE__ */ jsx(Button, {
752
+ "data-slot": "color-picker-eye-dropper",
753
+ ...buttonProps,
754
+ variant: "outline",
755
+ size,
756
+ onClick: onEyeDropper,
757
+ disabled: isDisabled,
758
+ children: children ?? /* @__PURE__ */ jsx(PipetteIcon, {})
759
+ });
760
+ }
761
+ function ColorPickerFormatSelect(props) {
762
+ const { size, disabled, className,...selectProps } = props;
763
+ const context = useColorPickerContext(FORMAT_SELECT_NAME);
764
+ const store = useStoreContext(FORMAT_SELECT_NAME);
765
+ const isDisabled = disabled || context.disabled;
766
+ const format = useStore((state) => state.format);
767
+ const onFormatChange = React.useCallback((value) => {
768
+ store.setFormat(value);
769
+ }, [store]);
770
+ return /* @__PURE__ */ jsxs(Select, {
771
+ "data-slot": "color-picker-format-select",
772
+ ...selectProps,
773
+ value: format,
774
+ onValueChange: onFormatChange,
775
+ disabled: isDisabled,
776
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
777
+ "data-slot": "color-picker-format-select-trigger",
778
+ size: size ?? "sm",
779
+ className: cn(className),
780
+ children: /* @__PURE__ */ jsx(SelectValue, {})
781
+ }), /* @__PURE__ */ jsx(SelectContent, { children: colorFormats.map((format$1) => /* @__PURE__ */ jsx(SelectItem, {
782
+ value: format$1,
783
+ children: format$1.toUpperCase()
784
+ }, format$1)) })]
785
+ });
786
+ }
787
+ function ColorPickerInput(props) {
788
+ const store = useStoreContext(INPUT_NAME);
789
+ const context = useColorPickerContext(INPUT_NAME);
790
+ const color = useStore((state) => state.color);
791
+ const format = useStore((state) => state.format);
792
+ const hsv = useStore((state) => state.hsv);
793
+ const onColorChange = React.useCallback((newColor) => {
794
+ const newHsv = rgbToHsv(newColor);
795
+ store.setColor(newColor);
796
+ store.setHsv(newHsv);
797
+ }, [store]);
798
+ if (format === "hex") return /* @__PURE__ */ jsx(HexInput, {
799
+ color,
800
+ onColorChange,
801
+ context,
802
+ ...props
803
+ });
804
+ if (format === "rgb") return /* @__PURE__ */ jsx(RgbInput, {
805
+ color,
806
+ onColorChange,
807
+ context,
808
+ ...props
809
+ });
810
+ if (format === "hsl") return /* @__PURE__ */ jsx(HslInput, {
811
+ color,
812
+ onColorChange,
813
+ context,
814
+ ...props
815
+ });
816
+ if (format === "hsb") return /* @__PURE__ */ jsx(HsbInput, {
817
+ hsv,
818
+ onColorChange,
819
+ context,
820
+ ...props
821
+ });
822
+ }
823
+ const inputGroupItemVariants = cva("h-8 [-moz-appearance:textfield] focus-visible:z-10 focus-visible:ring-1 [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none", {
824
+ variants: { position: {
825
+ first: "rounded-e-none",
826
+ middle: "-ms-px rounded-none border-l-0",
827
+ last: "-ms-px rounded-s-none border-l-0",
828
+ isolated: ""
829
+ } },
830
+ defaultVariants: { position: "isolated" }
831
+ });
832
+ function InputGroupItem({ className, position,...props }) {
833
+ return /* @__PURE__ */ jsx(Input, {
834
+ "data-slot": "color-picker-input",
835
+ className: cn(inputGroupItemVariants({
836
+ position,
837
+ className
838
+ })),
839
+ ...props
840
+ });
841
+ }
842
+ function HexInput(props) {
843
+ const { color, onColorChange, context, withoutAlpha, className,...inputProps } = props;
844
+ const hexValue = rgbToHex(color);
845
+ const alphaValue = Math.round((color?.a ?? 1) * 100);
846
+ const onHexChange = React.useCallback((event) => {
847
+ const { value } = event.target;
848
+ const parsedColor = parseColorString(value);
849
+ if (parsedColor) {
850
+ const trimmed = value.trim().toLowerCase();
851
+ onColorChange(trimmed.startsWith("#") && (trimmed.length === 4 || trimmed.length === 7) ? {
852
+ ...parsedColor,
853
+ a: color?.a ?? 1
854
+ } : parsedColor);
855
+ }
856
+ }, [color, onColorChange]);
857
+ const onAlphaChange = React.useCallback((event) => {
858
+ const value = Number.parseInt(event.target.value, 10);
859
+ if (!Number.isNaN(value) && value >= 0 && value <= 100) onColorChange({
860
+ ...color,
861
+ a: value / 100
862
+ });
863
+ }, [color, onColorChange]);
864
+ if (withoutAlpha) return /* @__PURE__ */ jsx(InputGroupItem, {
865
+ "aria-label": "Hex color value",
866
+ position: "isolated",
867
+ ...inputProps,
868
+ placeholder: "#000000",
869
+ className: cn("font-mono", className),
870
+ value: hexValue,
871
+ onChange: onHexChange,
872
+ disabled: context.disabled
873
+ });
874
+ return /* @__PURE__ */ jsxs("div", {
875
+ "data-slot": "color-picker-input-wrapper",
876
+ className: cn("flex items-center", className),
877
+ children: [/* @__PURE__ */ jsx(InputGroupItem, {
878
+ "aria-label": "Hex color value",
879
+ position: "first",
880
+ ...inputProps,
881
+ placeholder: "#000000",
882
+ className: "flex-1 font-mono",
883
+ value: hexValue,
884
+ onChange: onHexChange,
885
+ disabled: context.disabled
886
+ }), /* @__PURE__ */ jsx(InputGroupItem, {
887
+ "aria-label": "Alpha transparency percentage",
888
+ position: "last",
889
+ ...inputProps,
890
+ placeholder: "100",
891
+ inputMode: "numeric",
892
+ pattern: "[0-9]*",
893
+ min: "0",
894
+ max: "100",
895
+ className: "w-14",
896
+ value: alphaValue,
897
+ onChange: onAlphaChange,
898
+ disabled: context.disabled
899
+ })]
900
+ });
901
+ }
902
+ function RgbInput(props) {
903
+ const { color, onColorChange, context, withoutAlpha, className,...inputProps } = props;
904
+ const rValue = Math.round(color?.r ?? 0);
905
+ const gValue = Math.round(color?.g ?? 0);
906
+ const bValue = Math.round(color?.b ?? 0);
907
+ const alphaValue = Math.round((color?.a ?? 1) * 100);
908
+ const onChannelChange = React.useCallback((channel, max, isAlpha = false) => (event) => {
909
+ const value = Number.parseInt(event.target.value, 10);
910
+ if (!Number.isNaN(value) && value >= 0 && value <= max) {
911
+ const newValue = isAlpha ? value / 100 : value;
912
+ onColorChange({
913
+ ...color,
914
+ [channel]: newValue
915
+ });
916
+ }
917
+ }, [color, onColorChange]);
918
+ return /* @__PURE__ */ jsxs("div", {
919
+ "data-slot": "color-picker-input-wrapper",
920
+ className: cn("flex items-center", className),
921
+ children: [
922
+ /* @__PURE__ */ jsx(InputGroupItem, {
923
+ "aria-label": "Red color component (0-255)",
924
+ position: "first",
925
+ ...inputProps,
926
+ placeholder: "0",
927
+ inputMode: "numeric",
928
+ pattern: "[0-9]*",
929
+ min: "0",
930
+ max: "255",
931
+ className: "w-14",
932
+ value: rValue,
933
+ onChange: onChannelChange("r", 255),
934
+ disabled: context.disabled
935
+ }),
936
+ /* @__PURE__ */ jsx(InputGroupItem, {
937
+ "aria-label": "Green color component (0-255)",
938
+ position: "middle",
939
+ ...inputProps,
940
+ placeholder: "0",
941
+ inputMode: "numeric",
942
+ pattern: "[0-9]*",
943
+ min: "0",
944
+ max: "255",
945
+ className: "w-14",
946
+ value: gValue,
947
+ onChange: onChannelChange("g", 255),
948
+ disabled: context.disabled
949
+ }),
950
+ /* @__PURE__ */ jsx(InputGroupItem, {
951
+ "aria-label": "Blue color component (0-255)",
952
+ position: withoutAlpha ? "last" : "middle",
953
+ ...inputProps,
954
+ placeholder: "0",
955
+ inputMode: "numeric",
956
+ pattern: "[0-9]*",
957
+ min: "0",
958
+ max: "255",
959
+ className: "w-14",
960
+ value: bValue,
961
+ onChange: onChannelChange("b", 255),
962
+ disabled: context.disabled
963
+ }),
964
+ !withoutAlpha && /* @__PURE__ */ jsx(InputGroupItem, {
965
+ "aria-label": "Alpha transparency percentage",
966
+ position: "last",
967
+ ...inputProps,
968
+ placeholder: "100",
969
+ inputMode: "numeric",
970
+ pattern: "[0-9]*",
971
+ min: "0",
972
+ max: "100",
973
+ className: "w-14",
974
+ value: alphaValue,
975
+ onChange: onChannelChange("a", 100, true),
976
+ disabled: context.disabled
977
+ })
978
+ ]
979
+ });
980
+ }
981
+ function HslInput(props) {
982
+ const { color, onColorChange, context, withoutAlpha, className,...inputProps } = props;
983
+ const hsl = React.useMemo(() => rgbToHsl(color), [color]);
984
+ const alphaValue = Math.round((color?.a ?? 1) * 100);
985
+ const onHslChannelChange = React.useCallback((channel, max) => (event) => {
986
+ const value = Number.parseInt(event.target.value, 10);
987
+ if (!Number.isNaN(value) && value >= 0 && value <= max) onColorChange(hslToRgb({
988
+ ...hsl,
989
+ [channel]: value
990
+ }, color?.a ?? 1));
991
+ }, [
992
+ hsl,
993
+ color,
994
+ onColorChange
995
+ ]);
996
+ const onAlphaChange = React.useCallback((event) => {
997
+ const value = Number.parseInt(event.target.value, 10);
998
+ if (!Number.isNaN(value) && value >= 0 && value <= 100) onColorChange({
999
+ ...color,
1000
+ a: value / 100
1001
+ });
1002
+ }, [color, onColorChange]);
1003
+ return /* @__PURE__ */ jsxs("div", {
1004
+ "data-slot": "color-picker-input-wrapper",
1005
+ className: cn("flex items-center", className),
1006
+ children: [
1007
+ /* @__PURE__ */ jsx(InputGroupItem, {
1008
+ "aria-label": "Hue degree (0-360)",
1009
+ position: "first",
1010
+ ...inputProps,
1011
+ placeholder: "0",
1012
+ inputMode: "numeric",
1013
+ pattern: "[0-9]*",
1014
+ min: "0",
1015
+ max: "360",
1016
+ className: "w-14",
1017
+ value: hsl.h,
1018
+ onChange: onHslChannelChange("h", 360),
1019
+ disabled: context.disabled
1020
+ }),
1021
+ /* @__PURE__ */ jsx(InputGroupItem, {
1022
+ "aria-label": "Saturation percentage (0-100)",
1023
+ position: "middle",
1024
+ ...inputProps,
1025
+ placeholder: "0",
1026
+ inputMode: "numeric",
1027
+ pattern: "[0-9]*",
1028
+ min: "0",
1029
+ max: "100",
1030
+ className: "w-14",
1031
+ value: hsl.s,
1032
+ onChange: onHslChannelChange("s", 100),
1033
+ disabled: context.disabled
1034
+ }),
1035
+ /* @__PURE__ */ jsx(InputGroupItem, {
1036
+ "aria-label": "Lightness percentage (0-100)",
1037
+ position: withoutAlpha ? "last" : "middle",
1038
+ ...inputProps,
1039
+ placeholder: "0",
1040
+ inputMode: "numeric",
1041
+ pattern: "[0-9]*",
1042
+ min: "0",
1043
+ max: "100",
1044
+ className: "w-14",
1045
+ value: hsl.l,
1046
+ onChange: onHslChannelChange("l", 100),
1047
+ disabled: context.disabled
1048
+ }),
1049
+ !withoutAlpha && /* @__PURE__ */ jsx(InputGroupItem, {
1050
+ "aria-label": "Alpha transparency percentage",
1051
+ position: "last",
1052
+ ...inputProps,
1053
+ placeholder: "100",
1054
+ inputMode: "numeric",
1055
+ pattern: "[0-9]*",
1056
+ min: "0",
1057
+ max: "100",
1058
+ className: "w-14",
1059
+ value: alphaValue,
1060
+ onChange: onAlphaChange,
1061
+ disabled: context.disabled
1062
+ })
1063
+ ]
1064
+ });
1065
+ }
1066
+ function HsbInput(props) {
1067
+ const { hsv, onColorChange, context, withoutAlpha, className,...inputProps } = props;
1068
+ const alphaValue = Math.round((hsv?.a ?? 1) * 100);
1069
+ const onHsvChannelChange = React.useCallback((channel, max) => (event) => {
1070
+ const value = Number.parseInt(event.target.value, 10);
1071
+ if (!Number.isNaN(value) && value >= 0 && value <= max) onColorChange(hsvToRgb({
1072
+ ...hsv,
1073
+ [channel]: value
1074
+ }));
1075
+ }, [hsv, onColorChange]);
1076
+ const onAlphaChange = React.useCallback((event) => {
1077
+ const value = Number.parseInt(event.target.value, 10);
1078
+ if (!Number.isNaN(value) && value >= 0 && value <= 100) onColorChange({
1079
+ ...hsvToRgb(hsv),
1080
+ a: value / 100
1081
+ });
1082
+ }, [hsv, onColorChange]);
1083
+ return /* @__PURE__ */ jsxs("div", {
1084
+ "data-slot": "color-picker-input-wrapper",
1085
+ className: cn("flex items-center", className),
1086
+ children: [
1087
+ /* @__PURE__ */ jsx(InputGroupItem, {
1088
+ "aria-label": "Hue degree (0-360)",
1089
+ position: "first",
1090
+ ...inputProps,
1091
+ placeholder: "0",
1092
+ inputMode: "numeric",
1093
+ pattern: "[0-9]*",
1094
+ min: "0",
1095
+ max: "360",
1096
+ className: "w-14",
1097
+ value: hsv?.h ?? 0,
1098
+ onChange: onHsvChannelChange("h", 360),
1099
+ disabled: context.disabled
1100
+ }),
1101
+ /* @__PURE__ */ jsx(InputGroupItem, {
1102
+ "aria-label": "Saturation percentage (0-100)",
1103
+ position: "middle",
1104
+ ...inputProps,
1105
+ placeholder: "0",
1106
+ inputMode: "numeric",
1107
+ pattern: "[0-9]*",
1108
+ min: "0",
1109
+ max: "100",
1110
+ className: "w-14",
1111
+ value: hsv?.s ?? 0,
1112
+ onChange: onHsvChannelChange("s", 100),
1113
+ disabled: context.disabled
1114
+ }),
1115
+ /* @__PURE__ */ jsx(InputGroupItem, {
1116
+ "aria-label": "Brightness percentage (0-100)",
1117
+ position: withoutAlpha ? "last" : "middle",
1118
+ ...inputProps,
1119
+ placeholder: "0",
1120
+ inputMode: "numeric",
1121
+ pattern: "[0-9]*",
1122
+ min: "0",
1123
+ max: "100",
1124
+ className: "w-14",
1125
+ value: hsv?.v ?? 0,
1126
+ onChange: onHsvChannelChange("v", 100),
1127
+ disabled: context.disabled
1128
+ }),
1129
+ !withoutAlpha && /* @__PURE__ */ jsx(InputGroupItem, {
1130
+ "aria-label": "Alpha transparency percentage",
1131
+ position: "last",
1132
+ ...inputProps,
1133
+ placeholder: "100",
1134
+ inputMode: "numeric",
1135
+ pattern: "[0-9]*",
1136
+ min: "0",
1137
+ max: "100",
1138
+ className: "w-14",
1139
+ value: alphaValue,
1140
+ onChange: onAlphaChange,
1141
+ disabled: context.disabled
1142
+ })
1143
+ ]
1144
+ });
1145
+ }
1146
+ const colorUtils = {
1147
+ colorToString,
1148
+ parseColorString
1149
+ };
1150
+
1151
+ //#endregion
1152
+ export { ColorPicker, ColorPickerAlphaSlider, ColorPickerArea, ColorPickerContent, ColorPickerEyeDropper, ColorPickerFormatSelect, ColorPickerHueSlider, ColorPickerInput, ColorPickerSwatch, ColorPickerTrigger, colorUtils, useStore };