@justanarthur/modo-ui 0.0.0-stage → 0.2.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE.beui +21 -0
  3. package/LICENSE.fluid-functionalism +21 -0
  4. package/LICENSE.motion-primitives +21 -0
  5. package/LICENSE.sileo +21 -0
  6. package/README.md +608 -2
  7. package/dist/base.css +994 -0
  8. package/dist/blocks/sidebar-app/index.d.ts +34 -0
  9. package/dist/blocks/sidebar-app/index.js +31 -0
  10. package/dist/components/badge/index.d.ts +59 -0
  11. package/dist/components/badge/index.js +16 -0
  12. package/dist/components/button/index.d.ts +59 -0
  13. package/dist/components/button/index.js +14 -0
  14. package/dist/components/card/index.d.ts +141 -0
  15. package/dist/components/card/index.js +42 -0
  16. package/dist/components/inputs/checkbox-group/index.d.ts +50 -0
  17. package/dist/components/inputs/checkbox-group/index.js +21 -0
  18. package/dist/components/inputs/color-picker/index.d.ts +137 -0
  19. package/dist/components/inputs/color-picker/index.js +35 -0
  20. package/dist/components/inputs/combobox/index.d.ts +161 -0
  21. package/dist/components/inputs/combobox/index.js +38 -0
  22. package/dist/components/inputs/date-time/calendar/index.d.ts +45 -0
  23. package/dist/components/inputs/date-time/calendar/index.js +18 -0
  24. package/dist/components/inputs/date-time/date-picker/index.d.ts +82 -0
  25. package/dist/components/inputs/date-time/date-picker/index.js +32 -0
  26. package/dist/components/inputs/date-time/date-range-picker/index.d.ts +64 -0
  27. package/dist/components/inputs/date-time/date-range-picker/index.js +31 -0
  28. package/dist/components/inputs/date-time/duration-picker/index.d.ts +57 -0
  29. package/dist/components/inputs/date-time/duration-picker/index.js +31 -0
  30. package/dist/components/inputs/date-time/month-picker/index.d.ts +57 -0
  31. package/dist/components/inputs/date-time/month-picker/index.js +30 -0
  32. package/dist/components/inputs/date-time/time-picker/index.d.ts +59 -0
  33. package/dist/components/inputs/date-time/time-picker/index.js +31 -0
  34. package/dist/components/inputs/input/index.d.ts +84 -0
  35. package/dist/components/inputs/input/index.js +19 -0
  36. package/dist/components/inputs/input-copy/index.d.ts +44 -0
  37. package/dist/components/inputs/input-copy/index.js +16 -0
  38. package/dist/components/inputs/input-message/index.d.ts +125 -0
  39. package/dist/components/inputs/input-message/index.js +25 -0
  40. package/dist/components/inputs/radio-group/index.d.ts +58 -0
  41. package/dist/components/inputs/radio-group/index.js +20 -0
  42. package/dist/components/inputs/search/index.d.ts +83 -0
  43. package/dist/components/inputs/search/index.js +25 -0
  44. package/dist/components/inputs/select/index.d.ts +105 -0
  45. package/dist/components/inputs/select/index.js +34 -0
  46. package/dist/components/inputs/slider/index.d.ts +108 -0
  47. package/dist/components/inputs/slider/index.js +14 -0
  48. package/dist/components/inputs/switch/index.d.ts +43 -0
  49. package/dist/components/inputs/switch/index.js +14 -0
  50. package/dist/components/navigation/accordion/index.d.ts +117 -0
  51. package/dist/components/navigation/accordion/index.js +28 -0
  52. package/dist/components/navigation/sidebar/index.d.ts +388 -0
  53. package/dist/components/navigation/sidebar/index.js +99 -0
  54. package/dist/components/navigation/tabs/index.d.ts +70 -0
  55. package/dist/components/navigation/tabs/index.js +23 -0
  56. package/dist/components/navigation/tabs-subtle/index.d.ts +73 -0
  57. package/dist/components/navigation/tabs-subtle/index.js +21 -0
  58. package/dist/components/overlays/alert-dialog/index.d.ts +67 -0
  59. package/dist/components/overlays/alert-dialog/index.js +22 -0
  60. package/dist/components/overlays/command/index.d.ts +121 -0
  61. package/dist/components/overlays/command/index.js +36 -0
  62. package/dist/components/overlays/context-menu/index.d.ts +97 -0
  63. package/dist/components/overlays/context-menu/index.js +29 -0
  64. package/dist/components/overlays/dialog/index.d.ts +130 -0
  65. package/dist/components/overlays/dialog/index.js +37 -0
  66. package/dist/components/overlays/dropdown/index.d.ts +222 -0
  67. package/dist/components/overlays/dropdown/index.js +44 -0
  68. package/dist/components/overlays/popover/index.d.ts +87 -0
  69. package/dist/components/overlays/popover/index.js +26 -0
  70. package/dist/components/overlays/preview-card/index.d.ts +75 -0
  71. package/dist/components/overlays/preview-card/index.js +19 -0
  72. package/dist/components/overlays/sheet/index.d.ts +67 -0
  73. package/dist/components/overlays/sheet/index.js +24 -0
  74. package/dist/components/overlays/toast/index.d.ts +107 -0
  75. package/dist/components/overlays/toast/index.js +21 -0
  76. package/dist/components/overlays/tooltip/index.d.ts +75 -0
  77. package/dist/components/overlays/tooltip/index.js +17 -0
  78. package/dist/components/table/index.d.ts +44 -0
  79. package/dist/components/table/index.js +26 -0
  80. package/dist/components/thinking-indicator/index.d.ts +32 -0
  81. package/dist/components/thinking-indicator/index.js +13 -0
  82. package/dist/index.d.ts +3926 -0
  83. package/dist/index.js +511 -0
  84. package/dist/preset.d.ts +104 -0
  85. package/dist/preset.js +124 -0
  86. package/dist/primitives/code/index.d.ts +23 -0
  87. package/dist/primitives/code/index.js +11 -0
  88. package/dist/primitives/craft/index.d.ts +31 -0
  89. package/dist/primitives/craft/index.js +11 -0
  90. package/dist/primitives/fluid-hover/index.d.ts +233 -0
  91. package/dist/primitives/fluid-hover/index.js +25 -0
  92. package/dist/primitives/morph/index.d.ts +127 -0
  93. package/dist/primitives/morph/index.js +19 -0
  94. package/dist/primitives/motion/index.d.ts +115 -0
  95. package/dist/primitives/motion/index.js +19 -0
  96. package/dist/primitives/scroll-area/index.d.ts +41 -0
  97. package/dist/primitives/scroll-area/index.js +12 -0
  98. package/dist/primitives/sizes/index.d.ts +128 -0
  99. package/dist/primitives/sizes/index.js +21 -0
  100. package/dist/primitives/surface/index.d.ts +69 -0
  101. package/dist/primitives/surface/index.js +17 -0
  102. package/dist/shared/components-0ke6xada.js +123 -0
  103. package/dist/shared/components-0q0sqfh4.js +146 -0
  104. package/dist/shared/components-0sn7ypjw.js +61 -0
  105. package/dist/shared/components-1j9791sn.js +345 -0
  106. package/dist/shared/components-1rfwbyyc.js +361 -0
  107. package/dist/shared/components-1v7rxytx.js +30 -0
  108. package/dist/shared/components-1xekx2hx.js +215 -0
  109. package/dist/shared/components-39jq9va1.js +86 -0
  110. package/dist/shared/components-3gae8nta.js +719 -0
  111. package/dist/shared/components-3k8xpnpq.js +1759 -0
  112. package/dist/shared/components-3ky44908.js +9 -0
  113. package/dist/shared/components-3mkepka5.js +111 -0
  114. package/dist/shared/components-3wk0w46f.js +667 -0
  115. package/dist/shared/components-4cnjmgex.js +124 -0
  116. package/dist/shared/components-59efxjd9.js +298 -0
  117. package/dist/shared/components-5xc2j8jz.js +159 -0
  118. package/dist/shared/components-62ybc7t2.js +496 -0
  119. package/dist/shared/components-66mv71kx.js +262 -0
  120. package/dist/shared/components-7ans7ce5.js +120 -0
  121. package/dist/shared/components-7btqt08d.js +270 -0
  122. package/dist/shared/components-7r3etddy.js +171 -0
  123. package/dist/shared/components-7x9kawxv.js +152 -0
  124. package/dist/shared/components-8fpr3s4p.js +292 -0
  125. package/dist/shared/components-9jvzzvt1.js +198 -0
  126. package/dist/shared/components-apdwtweq.js +484 -0
  127. package/dist/shared/components-asr5pg50.js +191 -0
  128. package/dist/shared/components-b2wyq2cq.js +232 -0
  129. package/dist/shared/components-c6s6b43g.js +15 -0
  130. package/dist/shared/components-ca2c898n.js +1828 -0
  131. package/dist/shared/components-cbxjn9p8.js +141 -0
  132. package/dist/shared/components-chacnk61.js +216 -0
  133. package/dist/shared/components-cv16mryv.js +62 -0
  134. package/dist/shared/components-ez65vtbq.js +110 -0
  135. package/dist/shared/components-ezxhrmer.js +17 -0
  136. package/dist/shared/components-gc5vtq2f.js +149 -0
  137. package/dist/shared/components-gf5s6ap9.js +42 -0
  138. package/dist/shared/components-gvr9w41t.js +193 -0
  139. package/dist/shared/components-h2dpcwgc.js +137 -0
  140. package/dist/shared/components-hawvy2qz.js +105 -0
  141. package/dist/shared/components-hqeq3w9q.js +375 -0
  142. package/dist/shared/components-jjw69c4c.js +28 -0
  143. package/dist/shared/components-jwst3vtj.js +346 -0
  144. package/dist/shared/components-kvr7f9hy.js +45 -0
  145. package/dist/shared/components-men63rwj.js +9 -0
  146. package/dist/shared/components-mhd39z7x.js +22 -0
  147. package/dist/shared/components-n7mjr357.js +26 -0
  148. package/dist/shared/components-ng72k97e.js +128 -0
  149. package/dist/shared/components-nh8tma1n.js +986 -0
  150. package/dist/shared/components-njzgqdwy.js +445 -0
  151. package/dist/shared/components-ny774h8p.js +293 -0
  152. package/dist/shared/components-q4daerx0.js +58 -0
  153. package/dist/shared/components-q5xj5c16.js +79 -0
  154. package/dist/shared/components-rr7a6ja9.js +160 -0
  155. package/dist/shared/components-s2bz1xpk.js +63 -0
  156. package/dist/shared/components-tqvarbfv.js +288 -0
  157. package/dist/shared/components-v6xp325t.js +304 -0
  158. package/dist/shared/components-v7wtz8hk.js +144 -0
  159. package/dist/shared/components-vc7vq5nz.js +32 -0
  160. package/dist/shared/components-vfbhxf5r.js +58 -0
  161. package/dist/shared/components-vynjtrk6.js +19 -0
  162. package/dist/shared/components-wvp1m52g.js +1200 -0
  163. package/dist/shared/components-yh3kwdhr.js +981 -0
  164. package/dist/shared/components-ytb2tefr.js +291 -0
  165. package/dist/shared/components-zfnmn5d4.js +220 -0
  166. package/dist/shared/components-zrkzcayz.js +141 -0
  167. package/dist/shared/components-zx6b6yby.js +42 -0
  168. package/dist/styles.css +1949 -0
  169. package/dist/tailwind.css +219 -0
  170. package/dist/tokens.css +345 -0
  171. package/package.json +103 -4
@@ -0,0 +1,1759 @@
1
+ import {
2
+ opensInPlace,
3
+ inPlaceOffset,
4
+ useMorphOrigin,
5
+ useMorph
6
+ } from "./components-hqeq3w9q.js";
7
+ import {
8
+ cn2
9
+ } from "./components-ezxhrmer.js";
10
+ import {
11
+ FluidHoverHighlight2
12
+ } from "./components-kvr7f9hy.js";
13
+ import {
14
+ useIcon
15
+ } from "./components-zrkzcayz.js";
16
+ import {
17
+ MorphSurface
18
+ } from "./components-0q0sqfh4.js";
19
+ import {
20
+ shapeMap,
21
+ useShape
22
+ } from "./components-cv16mryv.js";
23
+ import {
24
+ useSize2
25
+ } from "./components-0sn7ypjw.js";
26
+ import {
27
+ SURFACE_BG,
28
+ SURFACE_SHADOW,
29
+ surfaceClasses2,
30
+ useSurface2,
31
+ SurfaceProvider2
32
+ } from "./components-zx6b6yby.js";
33
+ import {
34
+ useFluidHover2,
35
+ useRegisterFluidHoverItem2
36
+ } from "./components-59efxjd9.js";
37
+ import {
38
+ SizeProvider2
39
+ } from "./components-jjw69c4c.js";
40
+ import {
41
+ Tooltip2
42
+ } from "./components-ng72k97e.js";
43
+ import {
44
+ Slider2
45
+ } from "./components-wvp1m52g.js";
46
+ import {
47
+ spring2
48
+ } from "./components-1v7rxytx.js";
49
+
50
+ // components/inputs/color-picker/index.tsx
51
+ import { Menu } from "@base-ui/react/menu";
52
+ import { NumberField } from "@base-ui/react/number-field";
53
+ import { Popover } from "@base-ui/react/popover";
54
+ import { AnimatePresence, motion } from "motion/react";
55
+ import {
56
+ createContext,
57
+ forwardRef,
58
+ useCallback,
59
+ useContext,
60
+ useEffect,
61
+ useMemo,
62
+ useRef,
63
+ useState
64
+ } from "react";
65
+ import { jsx, jsxs } from "react/jsx-runtime";
66
+ var ColorPickerPortalContainerContext = createContext(null);
67
+ function ColorPickerPortalContainer2({ value, children }) {
68
+ return /* @__PURE__ */ jsx(ColorPickerPortalContainerContext.Provider, {
69
+ value,
70
+ children
71
+ });
72
+ }
73
+ var PanelSurfaceContext = createContext(true);
74
+ function clamp01(n) {
75
+ return Math.max(0, Math.min(1, n));
76
+ }
77
+ function clamp255(n) {
78
+ return Math.max(0, Math.min(255, n));
79
+ }
80
+ function hsvToRgb(h, s, v) {
81
+ const c = v * s;
82
+ const hh = (h % 360 + 360) % 360 / 60;
83
+ const x = c * (1 - Math.abs(hh % 2 - 1));
84
+ let r = 0, g = 0, b = 0;
85
+ if (hh < 1) {
86
+ r = c;
87
+ g = x;
88
+ b = 0;
89
+ } else if (hh < 2) {
90
+ r = x;
91
+ g = c;
92
+ b = 0;
93
+ } else if (hh < 3) {
94
+ r = 0;
95
+ g = c;
96
+ b = x;
97
+ } else if (hh < 4) {
98
+ r = 0;
99
+ g = x;
100
+ b = c;
101
+ } else if (hh < 5) {
102
+ r = x;
103
+ g = 0;
104
+ b = c;
105
+ } else {
106
+ r = c;
107
+ g = 0;
108
+ b = x;
109
+ }
110
+ const m = v - c;
111
+ return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };
112
+ }
113
+ function rgbToHsv(r, g, b) {
114
+ r /= 255;
115
+ g /= 255;
116
+ b /= 255;
117
+ const max = Math.max(r, g, b);
118
+ const min = Math.min(r, g, b);
119
+ const v = max;
120
+ const d = max - min;
121
+ const s = max === 0 ? 0 : d / max;
122
+ let h = 0;
123
+ if (d > 0) {
124
+ if (max === r)
125
+ h = (g - b) / d % 6;
126
+ else if (max === g)
127
+ h = (b - r) / d + 2;
128
+ else
129
+ h = (r - g) / d + 4;
130
+ h *= 60;
131
+ if (h < 0)
132
+ h += 360;
133
+ }
134
+ return { h, s, v };
135
+ }
136
+ function rgbToHsl(r, g, b) {
137
+ r /= 255;
138
+ g /= 255;
139
+ b /= 255;
140
+ const max = Math.max(r, g, b);
141
+ const min = Math.min(r, g, b);
142
+ const l = (max + min) / 2;
143
+ const d = max - min;
144
+ let h = 0, s = 0;
145
+ if (d > 0) {
146
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
147
+ if (max === r)
148
+ h = (g - b) / d % 6;
149
+ else if (max === g)
150
+ h = (b - r) / d + 2;
151
+ else
152
+ h = (r - g) / d + 4;
153
+ h *= 60;
154
+ if (h < 0)
155
+ h += 360;
156
+ }
157
+ return { h, s, l };
158
+ }
159
+ function hslToRgb(h, s, l) {
160
+ const c = (1 - Math.abs(2 * l - 1)) * s;
161
+ const hh = (h % 360 + 360) % 360 / 60;
162
+ const x = c * (1 - Math.abs(hh % 2 - 1));
163
+ let r = 0, g = 0, b = 0;
164
+ if (hh < 1) {
165
+ r = c;
166
+ g = x;
167
+ } else if (hh < 2) {
168
+ r = x;
169
+ g = c;
170
+ } else if (hh < 3) {
171
+ g = c;
172
+ b = x;
173
+ } else if (hh < 4) {
174
+ g = x;
175
+ b = c;
176
+ } else if (hh < 5) {
177
+ r = x;
178
+ b = c;
179
+ } else {
180
+ r = c;
181
+ b = x;
182
+ }
183
+ const m = l - c / 2;
184
+ return { r: (r + m) * 255, g: (g + m) * 255, b: (b + m) * 255 };
185
+ }
186
+ function srgbToLinear(c) {
187
+ c = c / 255;
188
+ return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
189
+ }
190
+ function linearToSrgb(c) {
191
+ const v = c <= 0.0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;
192
+ return clamp01(v) * 255;
193
+ }
194
+ function linearRgbToOklab(r, g, b) {
195
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
196
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
197
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
198
+ const l_ = Math.cbrt(l);
199
+ const m_ = Math.cbrt(m);
200
+ const s_ = Math.cbrt(s);
201
+ return {
202
+ L: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
203
+ a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
204
+ b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_
205
+ };
206
+ }
207
+ function oklabToLinearRgb(L, a, b) {
208
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
209
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
210
+ const s_ = L - 0.0894841775 * a - 1.291485548 * b;
211
+ const l = l_ * l_ * l_;
212
+ const m = m_ * m_ * m_;
213
+ const s = s_ * s_ * s_;
214
+ return {
215
+ r: 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
216
+ g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
217
+ b: -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
218
+ };
219
+ }
220
+ function rgbToOklch(r, g, b) {
221
+ const lr = srgbToLinear(r);
222
+ const lg = srgbToLinear(g);
223
+ const lb = srgbToLinear(b);
224
+ const lab = linearRgbToOklab(lr, lg, lb);
225
+ const C = Math.sqrt(lab.a * lab.a + lab.b * lab.b);
226
+ let H = Math.atan2(lab.b, lab.a) * 180 / Math.PI;
227
+ if (H < 0)
228
+ H += 360;
229
+ return { L: lab.L, C, H };
230
+ }
231
+ function oklchToRgb(L, C, H) {
232
+ const a = C * Math.cos(H * Math.PI / 180);
233
+ const b = C * Math.sin(H * Math.PI / 180);
234
+ const lin = oklabToLinearRgb(L, a, b);
235
+ return {
236
+ r: clamp255(linearToSrgb(lin.r)),
237
+ g: clamp255(linearToSrgb(lin.g)),
238
+ b: clamp255(linearToSrgb(lin.b))
239
+ };
240
+ }
241
+ function to2hex(n) {
242
+ return Math.round(clamp255(n)).toString(16).padStart(2, "0");
243
+ }
244
+ function rgbToHexStr(r, g, b, a) {
245
+ if (a >= 1)
246
+ return `#${to2hex(r)}${to2hex(g)}${to2hex(b)}`;
247
+ return `#${to2hex(r)}${to2hex(g)}${to2hex(b)}${to2hex(a * 255)}`;
248
+ }
249
+ function expandShortHex(h) {
250
+ if (h.length === 3)
251
+ return h.split("").map((c) => c + c).join("");
252
+ if (h.length === 4)
253
+ return h.split("").map((c) => c + c).join("");
254
+ return h;
255
+ }
256
+ function parseHex(input) {
257
+ const m = input.trim().match(/^#?([0-9a-fA-F]{3,8})$/);
258
+ if (!m)
259
+ return null;
260
+ let h = m[1];
261
+ if (h.length === 3 || h.length === 4)
262
+ h = expandShortHex(h);
263
+ if (h.length === 6) {
264
+ return {
265
+ r: parseInt(h.slice(0, 2), 16),
266
+ g: parseInt(h.slice(2, 4), 16),
267
+ b: parseInt(h.slice(4, 6), 16),
268
+ a: 1
269
+ };
270
+ }
271
+ if (h.length === 8) {
272
+ return {
273
+ r: parseInt(h.slice(0, 2), 16),
274
+ g: parseInt(h.slice(2, 4), 16),
275
+ b: parseInt(h.slice(4, 6), 16),
276
+ a: parseInt(h.slice(6, 8), 16) / 255
277
+ };
278
+ }
279
+ return null;
280
+ }
281
+ function parseAlphaPart(part) {
282
+ if (part === undefined)
283
+ return 1;
284
+ return part.endsWith("%") ? parseFloat(part) / 100 : parseFloat(part);
285
+ }
286
+ function parseColor2(input) {
287
+ const s = input.trim();
288
+ if (!s)
289
+ return null;
290
+ if (s.startsWith("#") || /^[0-9a-fA-F]{3,8}$/.test(s)) {
291
+ return parseHex(s);
292
+ }
293
+ const rgbM = s.match(/^rgba?\(\s*([^)]+)\)$/i);
294
+ if (rgbM) {
295
+ const parts = rgbM[1].split(/[\s,/]+/).filter(Boolean);
296
+ if (parts.length < 3)
297
+ return null;
298
+ const r = parseFloat(parts[0]);
299
+ const g = parseFloat(parts[1]);
300
+ const b = parseFloat(parts[2]);
301
+ const a = parseAlphaPart(parts[3]);
302
+ if ([r, g, b, a].some(Number.isNaN))
303
+ return null;
304
+ return { r: clamp255(r), g: clamp255(g), b: clamp255(b), a: clamp01(a) };
305
+ }
306
+ const hslM = s.match(/^hsla?\(\s*([^)]+)\)$/i);
307
+ if (hslM) {
308
+ const parts = hslM[1].split(/[\s,/]+/).filter(Boolean);
309
+ if (parts.length < 3)
310
+ return null;
311
+ const h = parseFloat(parts[0]);
312
+ const sat = parts[1].endsWith("%") ? parseFloat(parts[1]) / 100 : parseFloat(parts[1]);
313
+ const l = parts[2].endsWith("%") ? parseFloat(parts[2]) / 100 : parseFloat(parts[2]);
314
+ const a = parseAlphaPart(parts[3]);
315
+ if ([h, sat, l, a].some(Number.isNaN))
316
+ return null;
317
+ const rgb = hslToRgb(h, clamp01(sat), clamp01(l));
318
+ return { r: clamp255(rgb.r), g: clamp255(rgb.g), b: clamp255(rgb.b), a: clamp01(a) };
319
+ }
320
+ const oklchM = s.match(/^oklch\(\s*([^)]+)\)$/i);
321
+ if (oklchM) {
322
+ const parts = oklchM[1].split(/[\s,/]+/).filter(Boolean);
323
+ if (parts.length < 3)
324
+ return null;
325
+ const L = parts[0].endsWith("%") ? parseFloat(parts[0]) / 100 : parseFloat(parts[0]);
326
+ const C = parseFloat(parts[1]);
327
+ const H = parseFloat(parts[2]);
328
+ const a = parseAlphaPart(parts[3]);
329
+ if ([L, C, H, a].some(Number.isNaN))
330
+ return null;
331
+ const rgb = oklchToRgb(clamp01(L), Math.max(0, C), H);
332
+ return { r: clamp255(rgb.r), g: clamp255(rgb.g), b: clamp255(rgb.b), a: clamp01(a) };
333
+ }
334
+ return null;
335
+ }
336
+ var cssColorCtx = null;
337
+ function resolveCssColor(input) {
338
+ const direct = parseColor2(input);
339
+ if (direct)
340
+ return direct;
341
+ const s = input.trim();
342
+ if (!s || typeof document === "undefined")
343
+ return null;
344
+ if (!cssColorCtx) {
345
+ cssColorCtx = document.createElement("canvas").getContext("2d");
346
+ if (!cssColorCtx)
347
+ return null;
348
+ }
349
+ const ctx = cssColorCtx;
350
+ ctx.fillStyle = "#000000";
351
+ ctx.fillStyle = s;
352
+ const first = String(ctx.fillStyle);
353
+ ctx.fillStyle = "#ffffff";
354
+ ctx.fillStyle = s;
355
+ const second = String(ctx.fillStyle);
356
+ if (first !== second)
357
+ return null;
358
+ return parseColor2(first);
359
+ }
360
+ function buildParsed2(h, s, v, a) {
361
+ const { r, g, b } = hsvToRgb(h, s, v);
362
+ const hsl = rgbToHsl(r, g, b);
363
+ const oklch = rgbToOklch(r, g, b);
364
+ const hex = rgbToHexStr(r, g, b, a);
365
+ const rgbStr = a >= 1 ? `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})` : `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${Number(a.toFixed(3))})`;
366
+ const hslStr = a >= 1 ? `hsl(${Math.round(hsl.h)}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%)` : `hsla(${Math.round(hsl.h)}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%, ${Number(a.toFixed(3))})`;
367
+ const oklchStr = a >= 1 ? `oklch(${(oklch.L * 100).toFixed(1)}% ${oklch.C.toFixed(3)} ${oklch.H.toFixed(1)})` : `oklch(${(oklch.L * 100).toFixed(1)}% ${oklch.C.toFixed(3)} ${oklch.H.toFixed(1)} / ${Number(a.toFixed(3))})`;
368
+ return {
369
+ h,
370
+ s,
371
+ v,
372
+ a,
373
+ r: Math.round(r),
374
+ g: Math.round(g),
375
+ b: Math.round(b),
376
+ hex,
377
+ rgb: rgbStr,
378
+ hsl: hslStr,
379
+ oklch: oklchStr
380
+ };
381
+ }
382
+ function formatValueByFormat(parsed, fmt) {
383
+ switch (fmt) {
384
+ case "hex":
385
+ return parsed.hex;
386
+ case "rgb":
387
+ return parsed.rgb;
388
+ case "hsl":
389
+ return parsed.hsl;
390
+ case "oklch":
391
+ return parsed.oklch;
392
+ }
393
+ }
394
+ var PANEL_WIDTH = 280;
395
+ var SQUARE_HEIGHT = 156;
396
+ var CHECKER_BG = {
397
+ backgroundImage: "conic-gradient(var(--checker-a) 0 25%, var(--checker-b) 0 50%, var(--checker-a) 0 75%, var(--checker-b) 0)",
398
+ backgroundSize: "8px 8px"
399
+ };
400
+ function SaturationSquare({ h, s, v, onChange }) {
401
+ const ref = useRef(null);
402
+ const [dragging, setDragging] = useState(false);
403
+ const hasMoved = useRef(false);
404
+ const [focused, setFocused] = useState(false);
405
+ const [hovered, setHovered] = useState(false);
406
+ const [cursorPos, setCursorPos] = useState(null);
407
+ const shape = useShape();
408
+ const updateFromPointer = useCallback((clientX, clientY) => {
409
+ const rect = ref.current?.getBoundingClientRect();
410
+ if (!rect)
411
+ return;
412
+ const x = clamp01((clientX - rect.left) / rect.width);
413
+ const y = clamp01((clientY - rect.top) / rect.height);
414
+ onChange(x, 1 - y);
415
+ }, [onChange]);
416
+ const updateCursorPos = useCallback((clientX, clientY) => {
417
+ const rect = ref.current?.getBoundingClientRect();
418
+ if (!rect)
419
+ return;
420
+ setCursorPos({
421
+ x: clamp01((clientX - rect.left) / rect.width) * 100,
422
+ y: clamp01((clientY - rect.top) / rect.height) * 100
423
+ });
424
+ }, []);
425
+ const onPointerDown = useCallback((e) => {
426
+ if (e.pointerType === "mouse" && e.button !== 0)
427
+ return;
428
+ e.preventDefault();
429
+ setDragging(true);
430
+ hasMoved.current = false;
431
+ e.currentTarget.setPointerCapture(e.pointerId);
432
+ updateFromPointer(e.clientX, e.clientY);
433
+ }, [updateFromPointer]);
434
+ const onPointerMove = useCallback((e) => {
435
+ updateCursorPos(e.clientX, e.clientY);
436
+ if (!dragging)
437
+ return;
438
+ hasMoved.current = true;
439
+ updateFromPointer(e.clientX, e.clientY);
440
+ }, [dragging, updateFromPointer, updateCursorPos]);
441
+ const onPointerUp = useCallback(() => {
442
+ setDragging(false);
443
+ hasMoved.current = false;
444
+ }, []);
445
+ const onKeyDown = useCallback((e) => {
446
+ const step = e.shiftKey ? 0.1 : 0.01;
447
+ let nextS = s, nextV = v, handled = true;
448
+ if (e.key === "ArrowLeft")
449
+ nextS = clamp01(s - step);
450
+ else if (e.key === "ArrowRight")
451
+ nextS = clamp01(s + step);
452
+ else if (e.key === "ArrowUp")
453
+ nextV = clamp01(v + step);
454
+ else if (e.key === "ArrowDown")
455
+ nextV = clamp01(v - step);
456
+ else
457
+ handled = false;
458
+ if (handled) {
459
+ e.preventDefault();
460
+ onChange(nextS, nextV);
461
+ }
462
+ }, [onChange, s, v]);
463
+ const { r, g, b } = hsvToRgb(h, s, v);
464
+ const thumbColor = `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;
465
+ return /* @__PURE__ */ jsxs("div", {
466
+ ref,
467
+ role: "application",
468
+ "aria-label": "Saturation and brightness",
469
+ tabIndex: 0,
470
+ onFocus: (e) => {
471
+ if (e.currentTarget.matches(":focus-visible"))
472
+ setFocused(true);
473
+ },
474
+ onBlur: () => setFocused(false),
475
+ onPointerEnter: () => setHovered(true),
476
+ onPointerLeave: () => {
477
+ setHovered(false);
478
+ setCursorPos(null);
479
+ },
480
+ onPointerDown,
481
+ onPointerMove,
482
+ onPointerUp,
483
+ onKeyDown,
484
+ className: cn2("relative w-full select-none touch-none cursor-none outline-none", focused && "ring-2 ring-focus-ring", shape.bg),
485
+ style: {
486
+ height: SQUARE_HEIGHT
487
+ },
488
+ children: [
489
+ /* @__PURE__ */ jsx("div", {
490
+ className: cn2("absolute inset-0 overflow-hidden", shape.bg === "rounded-[20px]" ? "rounded-2xl" : shape.bg),
491
+ style: {
492
+ background: `linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${h}, 100%, 50%))`
493
+ }
494
+ }),
495
+ /* @__PURE__ */ jsx(motion.div, {
496
+ className: "absolute pointer-events-none rounded-full border border-thumb shadow-picker-thumb",
497
+ initial: false,
498
+ animate: {
499
+ left: `${s * 100}%`,
500
+ top: `${(1 - v) * 100}%`,
501
+ width: 18,
502
+ height: 18
503
+ },
504
+ transition: { duration: 0 },
505
+ style: {
506
+ transform: "translate(-50%, -50%)",
507
+ backgroundColor: thumbColor
508
+ }
509
+ }),
510
+ hovered && !dragging && cursorPos && /* @__PURE__ */ jsx("div", {
511
+ className: "absolute pointer-events-none rounded-full border-2 border-picker-ring shadow-picker-cursor",
512
+ style: {
513
+ left: `${cursorPos.x}%`,
514
+ top: `${cursorPos.y}%`,
515
+ width: 18,
516
+ height: 18,
517
+ transform: "translate(-50%, -50%)"
518
+ }
519
+ })
520
+ ]
521
+ });
522
+ }
523
+ function HueSlider({ h, onChange }) {
524
+ const hueColor = `hsl(${h}, 100%, 50%)`;
525
+ return /* @__PURE__ */ jsx(Slider2, {
526
+ value: h,
527
+ onChange: (v) => onChange(typeof v === "number" ? v : v[0] ?? 0),
528
+ min: 0,
529
+ max: 360,
530
+ step: 1,
531
+ showValue: false,
532
+ hideFill: true,
533
+ thumbColor: hueColor,
534
+ thumbBorderColor: "var(--picker-thumb-border)",
535
+ trackStyle: {
536
+ background: "linear-gradient(to right, hsl(0,100%,50%), hsl(60,100%,50%), hsl(120,100%,50%), hsl(180,100%,50%), hsl(240,100%,50%), hsl(300,100%,50%), hsl(360,100%,50%))",
537
+ borderColor: "transparent"
538
+ },
539
+ "aria-label": "Hue"
540
+ });
541
+ }
542
+ function AlphaSlider({
543
+ a,
544
+ solidColor,
545
+ solidR,
546
+ solidG,
547
+ solidB,
548
+ onChange
549
+ }) {
550
+ const transparentColor = `rgba(${solidR}, ${solidG}, ${solidB}, 0)`;
551
+ return /* @__PURE__ */ jsx(Slider2, {
552
+ value: Math.round(a * 100),
553
+ onChange: (v) => onChange((typeof v === "number" ? v : v[0] ?? 0) / 100),
554
+ min: 0,
555
+ max: 100,
556
+ step: 1,
557
+ showValue: false,
558
+ hideFill: true,
559
+ thumbColor: solidColor,
560
+ thumbBorderColor: "var(--picker-thumb-border)",
561
+ trackStyle: {
562
+ backgroundImage: `linear-gradient(to right, ${transparentColor} 0%, ${solidColor} 98%), conic-gradient(var(--checker-a) 0 25%, var(--checker-b) 0 50%, var(--checker-a) 0 75%, var(--checker-b) 0)`,
563
+ backgroundSize: "100% 100%, 8px 8px",
564
+ borderWidth: 0
565
+ },
566
+ "aria-label": "Alpha"
567
+ });
568
+ }
569
+ var FORMAT_LABELS = {
570
+ hex: "HEX",
571
+ rgb: "RGB",
572
+ hsl: "HSL",
573
+ oklch: "OKLCH"
574
+ };
575
+ var FORMATS = ["hex", "rgb", "hsl", "oklch"];
576
+ var menuShape = shapeMap.rounded;
577
+ var FormatMenuContext = createContext(null);
578
+ function FormatItem({
579
+ index,
580
+ value,
581
+ label,
582
+ checked
583
+ }) {
584
+ const ref = useRef(null);
585
+ const menuCtx = useContext(FormatMenuContext);
586
+ const shape = useShape();
587
+ const sizeClasses = useSize2();
588
+ const compact = sizeClasses.variant === "compact";
589
+ useRegisterFluidHoverItem2(menuCtx?.registerItem, index, ref);
590
+ const isActive = menuCtx?.activeIndex === index;
591
+ return /* @__PURE__ */ jsx(Menu.RadioItem, {
592
+ value,
593
+ label,
594
+ closeOnClick: true,
595
+ render: /* @__PURE__ */ jsx("div", {
596
+ ref,
597
+ "data-fluid-hover-index": index,
598
+ className: cn2("relative z-10 flex items-center cursor-pointer outline-none", compact ? "px-2.5 py-1.5" : "px-3 py-2", sizeClasses.text, shape.item)
599
+ }),
600
+ children: /* @__PURE__ */ jsxs("span", {
601
+ className: "inline-grid",
602
+ children: [
603
+ /* @__PURE__ */ jsx("span", {
604
+ className: "col-start-1 row-start-1 invisible weight-semibold",
605
+ "aria-hidden": "true",
606
+ children: label
607
+ }),
608
+ /* @__PURE__ */ jsx("span", {
609
+ className: cn2("col-start-1 row-start-1 transition-[color,font-variation-settings] duration-fast", isActive || checked ? "text-foreground" : "text-muted-foreground", checked ? "weight-semibold" : "weight-normal"),
610
+ children: label
611
+ })
612
+ ]
613
+ })
614
+ });
615
+ }
616
+ function FormatDropdown({
617
+ value,
618
+ onChange,
619
+ open: openProp,
620
+ defaultOpen = false
621
+ }) {
622
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
623
+ const isControlled = openProp !== undefined;
624
+ const open = isControlled ? openProp : internalOpen;
625
+ const { origin, capture } = useMorphOrigin();
626
+ const morph = useMorph(open, origin, { tier: "moderate" });
627
+ const level = Math.min(useSurface2() + 2, 8);
628
+ const shape = useShape();
629
+ const sizeClasses = useSize2();
630
+ const portalContainer = useContext(ColorPickerPortalContainerContext);
631
+ const containerRef = useRef(null);
632
+ const ChevronDownIcon = useIcon("chevron-down");
633
+ const hover = useFluidHover2(containerRef);
634
+ const { activeIndex, setActiveIndex, itemRects, handlers, registerItem, remeasure } = hover;
635
+ const [focusedIndex, setFocusedIndex] = useState(null);
636
+ useEffect(() => {
637
+ if (!open)
638
+ return;
639
+ remeasure();
640
+ }, [open, remeasure]);
641
+ const checkedIndex = FORMATS.indexOf(value);
642
+ const checkedRect = checkedIndex !== -1 ? itemRects[checkedIndex] ?? null : null;
643
+ const focusRect = focusedIndex !== null ? itemRects[focusedIndex] ?? null : null;
644
+ const menuCtx = useMemo(() => ({ registerItem, activeIndex, checkedIndex }), [registerItem, activeIndex, checkedIndex]);
645
+ return /* @__PURE__ */ jsxs(Menu.Root, {
646
+ open,
647
+ onOpenChange: (next, details) => {
648
+ if (next)
649
+ capture(details);
650
+ if (!isControlled)
651
+ setInternalOpen(next);
652
+ },
653
+ modal: false,
654
+ children: [
655
+ /* @__PURE__ */ jsxs(Menu.Trigger, {
656
+ className: cn2("flex items-center justify-between bg-transparent hover:bg-hover hover:text-foreground transition-colors duration-fast outline-none focus-visible:ring-1 focus-visible:ring-focus-ring cursor-pointer", sizeClasses.gap, sizeClasses.control, sizeClasses.px, sizeClasses.text, open ? "bg-active text-foreground" : "text-muted-foreground active:bg-active", shape.input, "weight-medium"),
657
+ children: [
658
+ /* @__PURE__ */ jsx("span", {
659
+ children: FORMAT_LABELS[value]
660
+ }),
661
+ /* @__PURE__ */ jsx(ChevronDownIcon, {
662
+ size: 14,
663
+ strokeWidth: 1.5,
664
+ className: cn2("text-muted-foreground transition-transform duration-150", open && "rotate-180")
665
+ })
666
+ ]
667
+ }),
668
+ /* @__PURE__ */ jsx(Menu.Portal, {
669
+ container: portalContainer ?? undefined,
670
+ children: /* @__PURE__ */ jsx(Menu.Positioner, {
671
+ side: "bottom",
672
+ align: "start",
673
+ sideOffset: 6,
674
+ className: "z-[60] outline-none",
675
+ children: /* @__PURE__ */ jsx(FormatMenuContext.Provider, {
676
+ value: menuCtx,
677
+ children: /* @__PURE__ */ jsx(Menu.Popup, {
678
+ ref: morph.popupRef,
679
+ onMouseEnter: () => {
680
+ handlers.onMouseEnter();
681
+ setFocusedIndex(null);
682
+ },
683
+ onMouseMove: handlers.onMouseMove,
684
+ onMouseLeave: handlers.onMouseLeave,
685
+ onClick: handlers.onClick,
686
+ onFocus: (e) => {
687
+ const indexAttr = e.target.closest("[data-fluid-hover-index]")?.getAttribute("data-fluid-hover-index");
688
+ if (indexAttr != null) {
689
+ const idx = Number(indexAttr);
690
+ setActiveIndex(idx);
691
+ setFocusedIndex(e.target.matches(":focus-visible") ? idx : null);
692
+ }
693
+ },
694
+ onBlur: (e) => {
695
+ if (e.currentTarget.contains(e.relatedTarget))
696
+ return;
697
+ setFocusedIndex(null);
698
+ setActiveIndex(null);
699
+ },
700
+ className: "relative select-none outline-none",
701
+ children: /* @__PURE__ */ jsx(SurfaceProvider2, {
702
+ value: level,
703
+ children: /* @__PURE__ */ jsx(MorphSurface, {
704
+ morph,
705
+ bg: SURFACE_BG[level],
706
+ shadow: SURFACE_SHADOW[3],
707
+ radius: menuShape.container,
708
+ className: "min-w-[var(--anchor-width)]",
709
+ children: /* @__PURE__ */ jsxs("div", {
710
+ ref: containerRef,
711
+ className: "relative flex flex-col p-1",
712
+ children: [
713
+ /* @__PURE__ */ jsx(AnimatePresence, {
714
+ children: checkedRect && /* @__PURE__ */ jsx(motion.div, {
715
+ className: `absolute ${menuShape.bg} bg-active pointer-events-none`,
716
+ initial: false,
717
+ animate: {
718
+ top: checkedRect.top,
719
+ left: checkedRect.left,
720
+ width: checkedRect.width,
721
+ height: checkedRect.height,
722
+ opacity: 1
723
+ },
724
+ exit: { opacity: 0, transition: spring2.moderate.exit },
725
+ transition: {
726
+ ...spring2.moderate,
727
+ opacity: { duration: spring2.fast.duration }
728
+ }
729
+ })
730
+ }),
731
+ /* @__PURE__ */ jsx(FluidHoverHighlight2, {
732
+ hover,
733
+ from: checkedRect,
734
+ className: menuShape.bg
735
+ }),
736
+ /* @__PURE__ */ jsx(AnimatePresence, {
737
+ children: focusRect && /* @__PURE__ */ jsx(motion.div, {
738
+ className: `absolute ${menuShape.focusRing} pointer-events-none z-20 border border-focus-ring`,
739
+ initial: false,
740
+ animate: {
741
+ left: focusRect.left - 2,
742
+ top: focusRect.top - 2,
743
+ width: focusRect.width + 4,
744
+ height: focusRect.height + 4
745
+ },
746
+ exit: { opacity: 0, transition: spring2.fast.exit },
747
+ transition: {
748
+ ...spring2.fast,
749
+ opacity: { duration: spring2.fast.duration }
750
+ }
751
+ })
752
+ }),
753
+ /* @__PURE__ */ jsx(Menu.RadioGroup, {
754
+ value,
755
+ onValueChange: (next) => onChange(next),
756
+ className: "contents",
757
+ children: FORMATS.map((fmt, i) => /* @__PURE__ */ jsx(FormatItem, {
758
+ index: i,
759
+ value: fmt,
760
+ label: FORMAT_LABELS[fmt],
761
+ checked: value === fmt
762
+ }, fmt))
763
+ })
764
+ ]
765
+ })
766
+ })
767
+ })
768
+ })
769
+ })
770
+ })
771
+ })
772
+ ]
773
+ });
774
+ }
775
+ var TextColorInput = forwardRef(({
776
+ value,
777
+ onCommit,
778
+ ariaLabel,
779
+ width,
780
+ className,
781
+ inputClassName,
782
+ align = "left",
783
+ prefix,
784
+ inputMode = "text",
785
+ nudgeStep,
786
+ nudgeShiftStep,
787
+ hasPercent = false,
788
+ decimals,
789
+ min,
790
+ max,
791
+ wrap = false
792
+ }, ref) => {
793
+ const [draft, setDraft] = useState(value);
794
+ const interactingRef = useRef(false);
795
+ const shape = useShape();
796
+ const sizeClasses = useSize2();
797
+ const compact = sizeClasses.variant === "compact";
798
+ useEffect(() => {
799
+ if (!interactingRef.current)
800
+ setDraft(value);
801
+ }, [value]);
802
+ const formatNumber = (n) => decimals != null ? n.toFixed(decimals) : String(Math.round(n));
803
+ const commitNumber = (n) => {
804
+ let bounded = n;
805
+ if (wrap && min != null && max != null) {
806
+ const range = max - min;
807
+ bounded = ((bounded - min) % range + range) % range + min;
808
+ } else {
809
+ if (min != null)
810
+ bounded = Math.max(min, bounded);
811
+ if (max != null)
812
+ bounded = Math.min(max, bounded);
813
+ }
814
+ const formatted = formatNumber(bounded);
815
+ const withSuffix = hasPercent ? `${formatted}%` : formatted;
816
+ setDraft(withSuffix);
817
+ onCommit(withSuffix);
818
+ };
819
+ const nudge = (direction, shift) => {
820
+ const baseStep = shift ? nudgeShiftStep ?? 10 : nudgeStep ?? 1;
821
+ const cur = parseFloat(draft.replace("%", ""));
822
+ if (Number.isNaN(cur))
823
+ return;
824
+ commitNumber(cur + direction * baseStep);
825
+ };
826
+ return /* @__PURE__ */ jsxs("div", {
827
+ className: cn2("flex items-center px-2 bg-transparent hover:bg-hover active:bg-active transition-colors duration-fast focus-within:ring-1 focus-within:ring-focus-ring select-none", sizeClasses.control, shape.input, className),
828
+ style: { width },
829
+ children: [
830
+ prefix && /* @__PURE__ */ jsx("span", {
831
+ className: cn2("text-muted-foreground mr-1 select-none", compact ? "text-caption-compact" : "text-caption"),
832
+ children: prefix
833
+ }),
834
+ /* @__PURE__ */ jsx("input", {
835
+ ref,
836
+ value: draft,
837
+ onChange: (e) => setDraft(e.target.value),
838
+ onFocus: (e) => {
839
+ interactingRef.current = true;
840
+ e.currentTarget.select();
841
+ },
842
+ onBlur: () => {
843
+ interactingRef.current = false;
844
+ if (draft !== value) {
845
+ const numeric = parseFloat(draft.replace("%", ""));
846
+ if (!Number.isNaN(numeric) && (min != null || max != null)) {
847
+ commitNumber(numeric);
848
+ } else {
849
+ onCommit(draft);
850
+ }
851
+ } else
852
+ setDraft(value);
853
+ },
854
+ onKeyDown: (e) => {
855
+ if (e.key === "Enter") {
856
+ e.currentTarget.blur();
857
+ } else if (e.key === "Escape") {
858
+ setDraft(value);
859
+ e.currentTarget.blur();
860
+ } else if ((nudgeStep != null || nudgeShiftStep != null) && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
861
+ e.preventDefault();
862
+ nudge(e.key === "ArrowUp" ? 1 : -1, e.shiftKey);
863
+ }
864
+ },
865
+ inputMode,
866
+ "aria-label": ariaLabel,
867
+ className: cn2("flex-1 min-w-0 bg-transparent text-foreground outline-none tabular-nums", sizeClasses.text, align === "center" && "text-center", align === "right" && "text-right", "weight-medium", inputClassName)
868
+ })
869
+ ]
870
+ });
871
+ });
872
+ TextColorInput.displayName = "TextColorInput";
873
+ var ScrubColorInput = forwardRef(({
874
+ value,
875
+ onCommit,
876
+ ariaLabel,
877
+ width,
878
+ className,
879
+ inputClassName,
880
+ align = "left",
881
+ prefix,
882
+ inputMode = "numeric",
883
+ nudgeStep,
884
+ nudgeShiftStep,
885
+ hasPercent = false,
886
+ decimals,
887
+ min,
888
+ max,
889
+ wrap = false
890
+ }, ref) => {
891
+ const shape = useShape();
892
+ const sizeClasses = useSize2();
893
+ const compact = sizeClasses.variant === "compact";
894
+ const inputRef = useRef(null);
895
+ const [editing, setEditing] = useState(false);
896
+ const pointerDownRef = useRef(false);
897
+ const numeric = parseFloat(String(value).replace("%", ""));
898
+ const fieldValue = Number.isNaN(numeric) ? null : numeric;
899
+ const format = useMemo(() => {
900
+ const f = { useGrouping: false };
901
+ if (decimals != null) {
902
+ f.minimumFractionDigits = decimals;
903
+ f.maximumFractionDigits = decimals;
904
+ } else {
905
+ f.maximumFractionDigits = 0;
906
+ }
907
+ if (hasPercent) {
908
+ f.style = "unit";
909
+ f.unit = "percent";
910
+ }
911
+ return f;
912
+ }, [decimals, hasPercent]);
913
+ const setInputRef = useCallback((node) => {
914
+ inputRef.current = node;
915
+ if (typeof ref === "function")
916
+ ref(node);
917
+ else if (ref)
918
+ ref.current = node;
919
+ }, [ref]);
920
+ const commit = useCallback((n) => {
921
+ let bounded = n;
922
+ if (wrap && min != null && max != null) {
923
+ if (bounded < min || bounded > max) {
924
+ const range = max - min;
925
+ bounded = ((bounded - min) % range + range) % range + min;
926
+ }
927
+ } else {
928
+ if (min != null)
929
+ bounded = Math.max(min, bounded);
930
+ if (max != null)
931
+ bounded = Math.min(max, bounded);
932
+ }
933
+ const formatted = decimals != null ? bounded.toFixed(decimals) : String(Math.round(bounded));
934
+ onCommit(hasPercent ? `${formatted}%` : formatted);
935
+ }, [wrap, min, max, decimals, hasPercent, onCommit]);
936
+ return /* @__PURE__ */ jsx(NumberField.Root, {
937
+ value: fieldValue,
938
+ onValueChange: (next, eventDetails) => {
939
+ if (next == null)
940
+ return;
941
+ const reason = eventDetails.reason;
942
+ if (reason === "input-change" || reason === "input-paste" || reason === "input-clear") {
943
+ return;
944
+ }
945
+ commit(next);
946
+ },
947
+ onValueCommitted: (_, eventDetails) => {
948
+ if (eventDetails.reason === "scrub") {
949
+ pointerDownRef.current = false;
950
+ inputRef.current?.blur();
951
+ }
952
+ },
953
+ min: wrap ? undefined : min,
954
+ max: wrap ? undefined : max,
955
+ step: nudgeStep ?? 1,
956
+ largeStep: nudgeShiftStep ?? 10,
957
+ format,
958
+ className: cn2("flex items-center bg-transparent hover:bg-hover active:bg-active transition-colors duration-fast focus-within:ring-1 focus-within:ring-focus-ring select-none", sizeClasses.control, shape.input, className),
959
+ style: { width },
960
+ children: /* @__PURE__ */ jsxs(NumberField.ScrubArea, {
961
+ direction: "horizontal",
962
+ pixelSensitivity: 1,
963
+ onPointerDownCapture: () => {
964
+ pointerDownRef.current = true;
965
+ },
966
+ onClick: () => {
967
+ pointerDownRef.current = false;
968
+ setEditing(true);
969
+ inputRef.current?.focus();
970
+ inputRef.current?.select();
971
+ },
972
+ className: cn2("flex flex-1 min-w-0 items-center self-stretch px-2", !editing && "cursor-ew-resize"),
973
+ children: [
974
+ /* @__PURE__ */ jsx(NumberField.ScrubAreaCursor, {
975
+ className: "drop-shadow-picker-cursor",
976
+ children: /* @__PURE__ */ jsx("svg", {
977
+ width: 24,
978
+ height: 14,
979
+ viewBox: "0 0 24 14",
980
+ className: "fill-picker-edge stroke-thumb",
981
+ strokeWidth: 1,
982
+ "aria-hidden": "true",
983
+ children: /* @__PURE__ */ jsx("path", {
984
+ d: "M0.5 7l5-5v3.5h13V2l5 5-5 5V8.5h-13V12l-5-5z"
985
+ })
986
+ })
987
+ }),
988
+ prefix && /* @__PURE__ */ jsx("span", {
989
+ className: cn2("text-muted-foreground mr-1 select-none", compact ? "text-caption-compact" : "text-caption"),
990
+ children: prefix
991
+ }),
992
+ /* @__PURE__ */ jsx(NumberField.Input, {
993
+ ref: setInputRef,
994
+ "aria-label": ariaLabel,
995
+ inputMode,
996
+ onPointerDown: (e) => {
997
+ if (editing)
998
+ e.stopPropagation();
999
+ },
1000
+ onFocus: (e) => {
1001
+ if (pointerDownRef.current)
1002
+ return;
1003
+ setEditing(true);
1004
+ e.currentTarget.select();
1005
+ },
1006
+ onBlur: () => {
1007
+ setEditing(false);
1008
+ },
1009
+ onKeyDown: (e) => {
1010
+ if (e.key === "Enter") {
1011
+ e.currentTarget.blur();
1012
+ } else if (e.key === "Escape") {
1013
+ const input = e.currentTarget;
1014
+ const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
1015
+ if (setter && fieldValue != null) {
1016
+ const restored = decimals != null ? fieldValue.toFixed(decimals) : String(Math.round(fieldValue));
1017
+ setter.call(input, hasPercent ? `${restored}%` : restored);
1018
+ input.dispatchEvent(new Event("input", { bubbles: true }));
1019
+ }
1020
+ input.blur();
1021
+ }
1022
+ },
1023
+ className: cn2("flex-1 min-w-0 bg-transparent text-foreground outline-none tabular-nums", sizeClasses.text, align === "center" && "text-center", align === "right" && "text-right", !editing && "pointer-events-none", "weight-medium", inputClassName)
1024
+ })
1025
+ ]
1026
+ })
1027
+ });
1028
+ });
1029
+ ScrubColorInput.displayName = "ScrubColorInput";
1030
+ var ColorInput = forwardRef(({ scrubbable = false, ...props }, ref) => scrubbable ? /* @__PURE__ */ jsx(ScrubColorInput, {
1031
+ ref,
1032
+ ...props
1033
+ }) : /* @__PURE__ */ jsx(TextColorInput, {
1034
+ ref,
1035
+ ...props
1036
+ }));
1037
+ ColorInput.displayName = "ColorInput";
1038
+ function EyeDropperButton({ onPick }) {
1039
+ const [supported, setSupported] = useState(false);
1040
+ const shape = useShape();
1041
+ const sizeClasses = useSize2();
1042
+ const PipetteIcon = useIcon("pipette");
1043
+ useEffect(() => {
1044
+ setSupported(typeof window !== "undefined" && "EyeDropper" in window);
1045
+ }, []);
1046
+ if (!supported)
1047
+ return null;
1048
+ const handleClick = async () => {
1049
+ try {
1050
+ const Ctor = window.EyeDropper;
1051
+ const eye = new Ctor;
1052
+ const result = await eye.open();
1053
+ onPick(result.sRGBHex);
1054
+ } catch {}
1055
+ };
1056
+ return /* @__PURE__ */ jsx("button", {
1057
+ type: "button",
1058
+ onClick: handleClick,
1059
+ "aria-label": "Pick color from screen",
1060
+ className: cn2("flex items-center justify-center text-muted-foreground bg-transparent hover:bg-hover hover:text-foreground active:bg-active transition-colors duration-fast outline-none focus-visible:ring-1 focus-visible:ring-focus-ring cursor-pointer", sizeClasses.control, sizeClasses.px, shape.input),
1061
+ children: /* @__PURE__ */ jsx(PipetteIcon, {
1062
+ size: sizeClasses.icon,
1063
+ strokeWidth: 1.5
1064
+ })
1065
+ });
1066
+ }
1067
+ function ColorTile2({ color, size = 24, className, style }) {
1068
+ const shape = useShape();
1069
+ return /* @__PURE__ */ jsx("span", {
1070
+ className: cn2("inline-block relative shrink-0 overflow-hidden shadow-swatch", shape.bg, className),
1071
+ style: {
1072
+ width: size,
1073
+ height: size,
1074
+ ...CHECKER_BG,
1075
+ ...style
1076
+ },
1077
+ children: /* @__PURE__ */ jsx("span", {
1078
+ className: "absolute inset-0",
1079
+ style: { backgroundColor: color }
1080
+ })
1081
+ });
1082
+ }
1083
+ var ColorSwatch2 = forwardRef(({ color, size = 28, selected, className, onMouseEnter, onMouseLeave, ...props }, ref) => {
1084
+ const shape = useShape();
1085
+ const [hovered, setHovered] = useState(false);
1086
+ const ring = selected ? "shadow-swatch-selected" : hovered ? "shadow-swatch-hover" : "shadow-swatch";
1087
+ return /* @__PURE__ */ jsx("button", {
1088
+ ref,
1089
+ type: "button",
1090
+ "aria-label": `Select color ${color}`,
1091
+ className: cn2("relative shrink-0 overflow-hidden cursor-pointer outline-none transition-shadow duration-100", shape.bg, ring, className),
1092
+ style: {
1093
+ width: size,
1094
+ height: size,
1095
+ ...CHECKER_BG
1096
+ },
1097
+ onMouseEnter: (e) => {
1098
+ setHovered(true);
1099
+ onMouseEnter?.(e);
1100
+ },
1101
+ onMouseLeave: (e) => {
1102
+ setHovered(false);
1103
+ onMouseLeave?.(e);
1104
+ },
1105
+ ...props,
1106
+ children: /* @__PURE__ */ jsx("span", {
1107
+ className: "absolute inset-0",
1108
+ style: { backgroundColor: color }
1109
+ })
1110
+ });
1111
+ });
1112
+ ColorSwatch2.displayName = "ColorSwatch";
1113
+ function SwatchStrip({
1114
+ swatches,
1115
+ current,
1116
+ onPick
1117
+ }) {
1118
+ const normalizedCurrent = useMemo(() => {
1119
+ const p = parseColor2(current);
1120
+ return p ? rgbToHexStr(p.r, p.g, p.b, p.a).toLowerCase() : "";
1121
+ }, [current]);
1122
+ const [resolvedSwatches, setResolvedSwatches] = useState({});
1123
+ useEffect(() => {
1124
+ const next = {};
1125
+ for (const sw of swatches) {
1126
+ if (!parseColor2(sw)) {
1127
+ const p = resolveCssColor(sw);
1128
+ if (p)
1129
+ next[sw] = rgbToHexStr(p.r, p.g, p.b, p.a).toLowerCase();
1130
+ }
1131
+ }
1132
+ setResolvedSwatches(next);
1133
+ }, [swatches]);
1134
+ return /* @__PURE__ */ jsx("div", {
1135
+ className: "flex flex-wrap gap-2",
1136
+ children: swatches.map((sw, i) => {
1137
+ const parsed = parseColor2(sw);
1138
+ const normalized = parsed ? rgbToHexStr(parsed.r, parsed.g, parsed.b, parsed.a).toLowerCase() : resolvedSwatches[sw] ?? sw.toLowerCase();
1139
+ const isSelected = normalized === normalizedCurrent;
1140
+ return /* @__PURE__ */ jsx(ColorSwatch2, {
1141
+ color: sw,
1142
+ size: 28,
1143
+ selected: isSelected,
1144
+ onClick: () => onPick(sw)
1145
+ }, `${sw}-${i}`);
1146
+ })
1147
+ });
1148
+ }
1149
+ var ColorPicker2 = forwardRef(({
1150
+ value,
1151
+ defaultValue = "#6B97FF",
1152
+ onValueChange,
1153
+ format,
1154
+ defaultFormat = "hex",
1155
+ onFormatChange,
1156
+ swatches,
1157
+ hideEyedropper,
1158
+ formatOpen,
1159
+ defaultFormatOpen,
1160
+ size,
1161
+ className,
1162
+ ...props
1163
+ }, ref) => {
1164
+ const isControlled = value !== undefined;
1165
+ const [internalValue, setInternalValue] = useState(value ?? defaultValue);
1166
+ const currentRawValue = isControlled ? value : internalValue;
1167
+ const isFormatControlled = format !== undefined;
1168
+ const [internalFormat, setInternalFormat] = useState(defaultFormat);
1169
+ const currentFormat = isFormatControlled ? format : internalFormat;
1170
+ const initialParsed = useMemo(() => {
1171
+ const p = parseColor2(currentRawValue);
1172
+ if (!p)
1173
+ return { h: 0, s: 1, v: 1, a: 1 };
1174
+ const hsv = rgbToHsv(p.r, p.g, p.b);
1175
+ return { h: hsv.s === 0 ? 0 : hsv.h, s: hsv.s, v: hsv.v, a: p.a };
1176
+ }, []);
1177
+ const [hsv, setHsv] = useState(initialParsed);
1178
+ const oklchHueRef = useRef(null);
1179
+ const lastEmittedRef = useRef("");
1180
+ useEffect(() => {
1181
+ if (!isControlled)
1182
+ return;
1183
+ const emitted = lastEmittedRef.current;
1184
+ const cur = value;
1185
+ if (cur === emitted)
1186
+ return;
1187
+ const p = parseColor2(cur);
1188
+ if (!p)
1189
+ return;
1190
+ oklchHueRef.current = null;
1191
+ const newHsv = rgbToHsv(p.r, p.g, p.b);
1192
+ setHsv((prev) => ({
1193
+ h: newHsv.s === 0 ? prev.h : newHsv.h,
1194
+ s: newHsv.s,
1195
+ v: newHsv.v,
1196
+ a: p.a
1197
+ }));
1198
+ }, [value, isControlled]);
1199
+ const parsed = useMemo(() => buildParsed2(hsv.h, hsv.s, hsv.v, hsv.a), [hsv]);
1200
+ const updateHsv = useCallback((next) => {
1201
+ const merged = { ...hsv, ...next };
1202
+ setHsv(merged);
1203
+ const p = buildParsed2(merged.h, merged.s, merged.v, merged.a);
1204
+ const formatted = formatValueByFormat(p, currentFormat);
1205
+ lastEmittedRef.current = formatted;
1206
+ if (!isControlled)
1207
+ setInternalValue(formatted);
1208
+ onValueChange?.(formatted, p);
1209
+ }, [hsv, currentFormat, isControlled, onValueChange]);
1210
+ const handleFormatChange = useCallback((f) => {
1211
+ if (!isFormatControlled)
1212
+ setInternalFormat(f);
1213
+ onFormatChange?.(f);
1214
+ const formatted = formatValueByFormat(parsed, f);
1215
+ lastEmittedRef.current = formatted;
1216
+ if (!isControlled)
1217
+ setInternalValue(formatted);
1218
+ onValueChange?.(formatted, parsed);
1219
+ }, [isFormatControlled, isControlled, onFormatChange, onValueChange, parsed]);
1220
+ const handleHexCommit = useCallback((input) => {
1221
+ const p = resolveCssColor(input);
1222
+ if (!p)
1223
+ return;
1224
+ oklchHueRef.current = null;
1225
+ const newHsv = rgbToHsv(p.r, p.g, p.b);
1226
+ const merged = {
1227
+ h: newHsv.s === 0 ? hsv.h : newHsv.h,
1228
+ s: newHsv.s,
1229
+ v: newHsv.v,
1230
+ a: p.a
1231
+ };
1232
+ setHsv(merged);
1233
+ const next = buildParsed2(merged.h, merged.s, merged.v, merged.a);
1234
+ const formatted = formatValueByFormat(next, currentFormat);
1235
+ lastEmittedRef.current = formatted;
1236
+ if (!isControlled)
1237
+ setInternalValue(formatted);
1238
+ onValueChange?.(formatted, next);
1239
+ }, [hsv.h, currentFormat, isControlled, onValueChange]);
1240
+ const handleSwatchPick = useCallback((sw) => {
1241
+ handleHexCommit(sw);
1242
+ }, [handleHexCommit]);
1243
+ const handleEyedrop = useCallback((hex) => {
1244
+ handleHexCommit(hex);
1245
+ }, [handleHexCommit]);
1246
+ const solidHueRgb = useMemo(() => hsvToRgb(hsv.h, hsv.s, hsv.v), [hsv.h, hsv.s, hsv.v]);
1247
+ const solidR = Math.round(solidHueRgb.r);
1248
+ const solidG = Math.round(solidHueRgb.g);
1249
+ const solidB = Math.round(solidHueRgb.b);
1250
+ const solidColorString = `rgb(${solidR}, ${solidG}, ${solidB})`;
1251
+ const shape = useShape();
1252
+ const substrate = useSurface2();
1253
+ const pickerLevel = Math.max(substrate, 3);
1254
+ const paintsSurface = useContext(PanelSurfaceContext);
1255
+ const root = /* @__PURE__ */ jsx(SurfaceProvider2, {
1256
+ value: pickerLevel,
1257
+ children: /* @__PURE__ */ jsxs("div", {
1258
+ ref,
1259
+ className: cn2("flex flex-col gap-2 p-3", paintsSurface && surfaceClasses2(pickerLevel, 1), shape.container, className),
1260
+ style: { width: PANEL_WIDTH },
1261
+ ...props,
1262
+ children: [
1263
+ /* @__PURE__ */ jsx(SaturationSquare, {
1264
+ h: hsv.h,
1265
+ s: hsv.s,
1266
+ v: hsv.v,
1267
+ onChange: (s, v) => updateHsv({ s, v })
1268
+ }),
1269
+ /* @__PURE__ */ jsxs("div", {
1270
+ className: "flex flex-col [&>*]:mb-0 [&>*+*]:-mt-px",
1271
+ children: [
1272
+ /* @__PURE__ */ jsx(HueSlider, {
1273
+ h: hsv.h,
1274
+ onChange: (h) => {
1275
+ oklchHueRef.current = null;
1276
+ updateHsv({ h });
1277
+ }
1278
+ }),
1279
+ /* @__PURE__ */ jsx(AlphaSlider, {
1280
+ a: hsv.a,
1281
+ solidColor: solidColorString,
1282
+ solidR,
1283
+ solidG,
1284
+ solidB,
1285
+ onChange: (a) => updateHsv({ a })
1286
+ })
1287
+ ]
1288
+ }),
1289
+ /* @__PURE__ */ jsxs("div", {
1290
+ className: "grid grid-cols-2 gap-2",
1291
+ children: [
1292
+ /* @__PURE__ */ jsx(FormatDropdown, {
1293
+ value: currentFormat,
1294
+ onChange: handleFormatChange,
1295
+ open: formatOpen,
1296
+ defaultOpen: defaultFormatOpen
1297
+ }),
1298
+ !hideEyedropper && /* @__PURE__ */ jsx(EyeDropperButton, {
1299
+ onPick: handleEyedrop
1300
+ })
1301
+ ]
1302
+ }),
1303
+ /* @__PURE__ */ jsx(ColorInputsRow, {
1304
+ parsed,
1305
+ format: currentFormat,
1306
+ oklchHue: oklchHueRef.current,
1307
+ onChannelChange: (channel, value) => {
1308
+ const p = { ...parsed };
1309
+ switch (channel) {
1310
+ case "hex":
1311
+ handleHexCommit(value);
1312
+ return;
1313
+ case "r":
1314
+ case "g":
1315
+ case "b": {
1316
+ oklchHueRef.current = null;
1317
+ const r = channel === "r" ? Number(value) : p.r;
1318
+ const g = channel === "g" ? Number(value) : p.g;
1319
+ const b = channel === "b" ? Number(value) : p.b;
1320
+ const hsvVal = rgbToHsv(r, g, b);
1321
+ updateHsv({
1322
+ h: hsvVal.s === 0 ? hsv.h : hsvVal.h,
1323
+ s: hsvVal.s,
1324
+ v: hsvVal.v
1325
+ });
1326
+ return;
1327
+ }
1328
+ case "hSL":
1329
+ case "sSL":
1330
+ case "lSL": {
1331
+ if (channel === "hSL")
1332
+ oklchHueRef.current = null;
1333
+ const hsl = rgbToHsl(p.r, p.g, p.b);
1334
+ const h2 = channel === "hSL" ? Number(value) : hsl.h;
1335
+ const s2 = channel === "sSL" ? Number(value) / 100 : hsl.s;
1336
+ const l2 = channel === "lSL" ? Number(value) / 100 : hsl.l;
1337
+ const rgb = hslToRgb(h2, clamp01(s2), clamp01(l2));
1338
+ const hsvVal = rgbToHsv(rgb.r, rgb.g, rgb.b);
1339
+ updateHsv({
1340
+ h: hsvVal.s === 0 ? h2 : hsvVal.h,
1341
+ s: hsvVal.s,
1342
+ v: hsvVal.v
1343
+ });
1344
+ return;
1345
+ }
1346
+ case "L":
1347
+ case "C":
1348
+ case "H": {
1349
+ const cur = rgbToOklch(p.r, p.g, p.b);
1350
+ const baseH = oklchHueRef.current ?? cur.H;
1351
+ const L = channel === "L" ? Number(value) / 100 : cur.L;
1352
+ const C = channel === "C" ? Number(value) : cur.C;
1353
+ const H = channel === "H" ? Number(value) : baseH;
1354
+ oklchHueRef.current = H;
1355
+ const rgb = oklchToRgb(clamp01(L), Math.max(0, C), H);
1356
+ const hsvVal = rgbToHsv(rgb.r, rgb.g, rgb.b);
1357
+ updateHsv({
1358
+ h: hsvVal.s === 0 ? hsv.h : hsvVal.h,
1359
+ s: hsvVal.s,
1360
+ v: hsvVal.v
1361
+ });
1362
+ return;
1363
+ }
1364
+ case "alphaPercent": {
1365
+ const a = clamp01(Number(value) / 100);
1366
+ updateHsv({ a });
1367
+ return;
1368
+ }
1369
+ }
1370
+ }
1371
+ }),
1372
+ swatches && swatches.length > 0 && /* @__PURE__ */ jsx(SwatchStrip, {
1373
+ swatches,
1374
+ current: parsed.hex,
1375
+ onPick: handleSwatchPick
1376
+ })
1377
+ ]
1378
+ })
1379
+ });
1380
+ return size ? /* @__PURE__ */ jsx(SizeProvider2, {
1381
+ size,
1382
+ children: root
1383
+ }) : root;
1384
+ });
1385
+ ColorPicker2.displayName = "ColorPicker";
1386
+ function ColorInputsRow({
1387
+ parsed,
1388
+ format,
1389
+ oklchHue,
1390
+ onChannelChange
1391
+ }) {
1392
+ const alphaPct = Math.round(parsed.a * 100);
1393
+ if (format === "hex") {
1394
+ const hexNoHash = parsed.hex.replace(/^#/, "").toUpperCase();
1395
+ return /* @__PURE__ */ jsxs("div", {
1396
+ className: "grid grid-cols-2 gap-2",
1397
+ children: [
1398
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1399
+ label: "Hex",
1400
+ children: /* @__PURE__ */ jsx(ColorInput, {
1401
+ value: hexNoHash,
1402
+ onCommit: (next) => onChannelChange("hex", next.startsWith("#") ? next : `#${next}`),
1403
+ ariaLabel: "Hex value",
1404
+ prefix: "#"
1405
+ })
1406
+ }),
1407
+ /* @__PURE__ */ jsx(AlphaInput, {
1408
+ value: alphaPct,
1409
+ onCommit: (n) => onChannelChange("alphaPercent", String(n))
1410
+ })
1411
+ ]
1412
+ });
1413
+ }
1414
+ if (format === "rgb") {
1415
+ return /* @__PURE__ */ jsxs("div", {
1416
+ className: "grid grid-cols-4 gap-1",
1417
+ children: [
1418
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1419
+ label: "Red",
1420
+ children: /* @__PURE__ */ jsx(ColorInput, {
1421
+ value: String(parsed.r),
1422
+ onCommit: (n) => onChannelChange("r", n),
1423
+ ariaLabel: "Red",
1424
+ align: "center",
1425
+ inputMode: "numeric",
1426
+ nudgeStep: 1,
1427
+ nudgeShiftStep: 10,
1428
+ scrubbable: true,
1429
+ min: 0,
1430
+ max: 255
1431
+ })
1432
+ }),
1433
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1434
+ label: "Green",
1435
+ children: /* @__PURE__ */ jsx(ColorInput, {
1436
+ value: String(parsed.g),
1437
+ onCommit: (n) => onChannelChange("g", n),
1438
+ ariaLabel: "Green",
1439
+ align: "center",
1440
+ inputMode: "numeric",
1441
+ nudgeStep: 1,
1442
+ nudgeShiftStep: 10,
1443
+ scrubbable: true,
1444
+ min: 0,
1445
+ max: 255
1446
+ })
1447
+ }),
1448
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1449
+ label: "Blue",
1450
+ children: /* @__PURE__ */ jsx(ColorInput, {
1451
+ value: String(parsed.b),
1452
+ onCommit: (n) => onChannelChange("b", n),
1453
+ ariaLabel: "Blue",
1454
+ align: "center",
1455
+ inputMode: "numeric",
1456
+ nudgeStep: 1,
1457
+ nudgeShiftStep: 10,
1458
+ scrubbable: true,
1459
+ min: 0,
1460
+ max: 255
1461
+ })
1462
+ }),
1463
+ /* @__PURE__ */ jsx(AlphaInput, {
1464
+ value: alphaPct,
1465
+ onCommit: (n) => onChannelChange("alphaPercent", String(n))
1466
+ })
1467
+ ]
1468
+ });
1469
+ }
1470
+ if (format === "hsl") {
1471
+ const hsl = rgbToHsl(parsed.r, parsed.g, parsed.b);
1472
+ return /* @__PURE__ */ jsxs("div", {
1473
+ className: "grid grid-cols-4 gap-1",
1474
+ children: [
1475
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1476
+ label: "Hue",
1477
+ children: /* @__PURE__ */ jsx(ColorInput, {
1478
+ value: String(Math.round(hsl.h)),
1479
+ onCommit: (n) => onChannelChange("hSL", n),
1480
+ ariaLabel: "Hue",
1481
+ align: "center",
1482
+ inputMode: "numeric",
1483
+ nudgeStep: 1,
1484
+ nudgeShiftStep: 10,
1485
+ scrubbable: true,
1486
+ min: 0,
1487
+ max: 360,
1488
+ wrap: true
1489
+ })
1490
+ }),
1491
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1492
+ label: "Saturation",
1493
+ children: /* @__PURE__ */ jsx(ColorInput, {
1494
+ value: String(Math.round(hsl.s * 100)),
1495
+ onCommit: (n) => onChannelChange("sSL", n),
1496
+ ariaLabel: "Saturation",
1497
+ align: "center",
1498
+ inputMode: "numeric",
1499
+ nudgeStep: 1,
1500
+ nudgeShiftStep: 10,
1501
+ scrubbable: true,
1502
+ min: 0,
1503
+ max: 100
1504
+ })
1505
+ }),
1506
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1507
+ label: "Lightness",
1508
+ children: /* @__PURE__ */ jsx(ColorInput, {
1509
+ value: String(Math.round(hsl.l * 100)),
1510
+ onCommit: (n) => onChannelChange("lSL", n),
1511
+ ariaLabel: "Lightness",
1512
+ align: "center",
1513
+ inputMode: "numeric",
1514
+ nudgeStep: 1,
1515
+ nudgeShiftStep: 10,
1516
+ scrubbable: true,
1517
+ min: 0,
1518
+ max: 100
1519
+ })
1520
+ }),
1521
+ /* @__PURE__ */ jsx(AlphaInput, {
1522
+ value: alphaPct,
1523
+ onCommit: (n) => onChannelChange("alphaPercent", String(n))
1524
+ })
1525
+ ]
1526
+ });
1527
+ }
1528
+ const oklch = rgbToOklch(parsed.r, parsed.g, parsed.b);
1529
+ const displayH = oklchHue ?? oklch.H;
1530
+ return /* @__PURE__ */ jsxs("div", {
1531
+ className: "grid grid-cols-4 gap-1",
1532
+ children: [
1533
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1534
+ label: "Lightness",
1535
+ children: /* @__PURE__ */ jsx(ColorInput, {
1536
+ value: (oklch.L * 100).toFixed(0),
1537
+ onCommit: (n) => onChannelChange("L", n),
1538
+ ariaLabel: "Lightness",
1539
+ align: "center",
1540
+ inputMode: "decimal",
1541
+ nudgeStep: 1,
1542
+ nudgeShiftStep: 10,
1543
+ scrubbable: true,
1544
+ min: 0,
1545
+ max: 100
1546
+ })
1547
+ }),
1548
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1549
+ label: "Chroma",
1550
+ children: /* @__PURE__ */ jsx(ColorInput, {
1551
+ value: oklch.C.toFixed(2),
1552
+ onCommit: (n) => onChannelChange("C", n),
1553
+ ariaLabel: "Chroma",
1554
+ align: "center",
1555
+ inputMode: "decimal",
1556
+ nudgeStep: 0.01,
1557
+ nudgeShiftStep: 0.1,
1558
+ decimals: 2,
1559
+ scrubbable: true,
1560
+ min: 0,
1561
+ max: 0.4
1562
+ })
1563
+ }),
1564
+ /* @__PURE__ */ jsx(ChannelTooltip, {
1565
+ label: "Hue",
1566
+ children: /* @__PURE__ */ jsx(ColorInput, {
1567
+ value: displayH.toFixed(0),
1568
+ onCommit: (n) => onChannelChange("H", n),
1569
+ ariaLabel: "Hue",
1570
+ align: "center",
1571
+ inputMode: "numeric",
1572
+ nudgeStep: 1,
1573
+ nudgeShiftStep: 10,
1574
+ scrubbable: true,
1575
+ min: 0,
1576
+ max: 360,
1577
+ wrap: true
1578
+ })
1579
+ }),
1580
+ /* @__PURE__ */ jsx(AlphaInput, {
1581
+ value: alphaPct,
1582
+ onCommit: (n) => onChannelChange("alphaPercent", String(n))
1583
+ })
1584
+ ]
1585
+ });
1586
+ }
1587
+ function ChannelTooltip({ label, children }) {
1588
+ return /* @__PURE__ */ jsx(Tooltip2, {
1589
+ content: label,
1590
+ delayDuration: 300,
1591
+ children: /* @__PURE__ */ jsx("div", {
1592
+ children
1593
+ })
1594
+ });
1595
+ }
1596
+ function AlphaInput({ value, onCommit }) {
1597
+ return /* @__PURE__ */ jsx(ChannelTooltip, {
1598
+ label: "Alpha",
1599
+ children: /* @__PURE__ */ jsx(ColorInput, {
1600
+ value: `${value}%`,
1601
+ onCommit: (input) => {
1602
+ const n = parseFloat(input.replace("%", ""));
1603
+ if (Number.isNaN(n))
1604
+ return;
1605
+ onCommit(Math.max(0, Math.min(100, Math.round(n))));
1606
+ },
1607
+ ariaLabel: "Alpha",
1608
+ align: "center",
1609
+ inputMode: "numeric",
1610
+ nudgeStep: 1,
1611
+ nudgeShiftStep: 10,
1612
+ hasPercent: true,
1613
+ scrubbable: true,
1614
+ min: 0,
1615
+ max: 100
1616
+ })
1617
+ });
1618
+ }
1619
+ var ColorPickerPopover2 = forwardRef(({
1620
+ triggerLabel,
1621
+ triggerLabelPosition = "left",
1622
+ triggerShowValue = true,
1623
+ triggerShowRemove = false,
1624
+ onTriggerRemove,
1625
+ triggerClassName,
1626
+ open: openProp,
1627
+ defaultOpen = false,
1628
+ onOpenChange,
1629
+ size,
1630
+ from,
1631
+ effect,
1632
+ hideSource,
1633
+ tier,
1634
+ ...pickerProps
1635
+ }, ref) => {
1636
+ const isOpenControlled = openProp !== undefined;
1637
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
1638
+ const open = isOpenControlled ? openProp : internalOpen;
1639
+ const { origin, capture } = useMorphOrigin();
1640
+ const morph = useMorph(open, origin, { from, effect, hideSource, tier });
1641
+ const shape = useShape();
1642
+ const sizeClasses = useSize2(size);
1643
+ const compact = sizeClasses.variant === "compact";
1644
+ const substrate = useSurface2();
1645
+ const level = Math.min(substrate + 2, 8);
1646
+ const handleOpenChange = useCallback((next, details) => {
1647
+ if (next)
1648
+ capture(details);
1649
+ if (!isOpenControlled)
1650
+ setInternalOpen(next);
1651
+ onOpenChange?.(next);
1652
+ }, [isOpenControlled, onOpenChange, capture]);
1653
+ const isControlled = pickerProps.value !== undefined;
1654
+ const [internalValue, setInternalValue] = useState(pickerProps.value ?? pickerProps.defaultValue ?? "#6B97FF");
1655
+ const currentValue = isControlled ? pickerProps.value : internalValue;
1656
+ const handleValueChange = useCallback((v, parsed) => {
1657
+ if (!isControlled)
1658
+ setInternalValue(v);
1659
+ pickerProps.onValueChange?.(v, parsed);
1660
+ }, [isControlled, pickerProps]);
1661
+ const XIcon = useIcon("x");
1662
+ const parsed = useMemo(() => parseColor2(currentValue), [currentValue]);
1663
+ const swatchColor = parsed ? rgbToHexStr(parsed.r, parsed.g, parsed.b, parsed.a) : currentValue;
1664
+ const valueLabel = parsed ? rgbToHexStr(parsed.r, parsed.g, parsed.b, 1).replace(/^#/, "").toUpperCase() : currentValue;
1665
+ const root = /* @__PURE__ */ jsx(Popover.Root, {
1666
+ open,
1667
+ onOpenChange: handleOpenChange,
1668
+ modal: false,
1669
+ children: /* @__PURE__ */ jsxs("div", {
1670
+ ref,
1671
+ className: "inline-flex",
1672
+ children: [
1673
+ /* @__PURE__ */ jsxs(Popover.Trigger, {
1674
+ className: cn2("flex items-center border border-border bg-transparent hover:bg-hover transition-colors duration-fast outline-none focus-visible:ring-1 focus-visible:ring-focus-ring cursor-pointer", sizeClasses.gap, sizeClasses.control, compact ? "px-1.5" : "px-2", shape.input, "weight-medium", triggerClassName),
1675
+ children: [
1676
+ triggerLabel && triggerLabelPosition === "left" && /* @__PURE__ */ jsx("span", {
1677
+ className: cn2("text-muted-foreground px-1 select-none", sizeClasses.text),
1678
+ children: triggerLabel
1679
+ }),
1680
+ /* @__PURE__ */ jsx(ColorTile2, {
1681
+ color: swatchColor,
1682
+ size: compact ? 16 : 20
1683
+ }),
1684
+ triggerShowValue && /* @__PURE__ */ jsx("span", {
1685
+ className: cn2("text-foreground tabular-nums", sizeClasses.text),
1686
+ children: valueLabel
1687
+ }),
1688
+ triggerLabel && triggerLabelPosition === "right" && /* @__PURE__ */ jsx("span", {
1689
+ className: cn2("text-muted-foreground px-1 select-none", sizeClasses.text),
1690
+ children: triggerLabel
1691
+ }),
1692
+ triggerShowRemove && /* @__PURE__ */ jsx("span", {
1693
+ role: "button",
1694
+ "aria-label": "Remove color",
1695
+ tabIndex: 0,
1696
+ onClick: (e) => {
1697
+ e.stopPropagation();
1698
+ onTriggerRemove?.();
1699
+ },
1700
+ onKeyDown: (e) => {
1701
+ if (e.key === "Enter" || e.key === " ") {
1702
+ e.stopPropagation();
1703
+ e.preventDefault();
1704
+ onTriggerRemove?.();
1705
+ }
1706
+ },
1707
+ className: "ml-1 text-muted-foreground hover:text-foreground cursor-pointer flex items-center",
1708
+ children: /* @__PURE__ */ jsx(XIcon, {
1709
+ size: 14,
1710
+ strokeWidth: 1.5
1711
+ })
1712
+ })
1713
+ ]
1714
+ }),
1715
+ /* @__PURE__ */ jsx(Popover.Portal, {
1716
+ children: /* @__PURE__ */ jsx(Popover.Positioner, {
1717
+ side: "bottom",
1718
+ align: "start",
1719
+ sideOffset: opensInPlace({ effect, hideSource }) ? inPlaceOffset : 6,
1720
+ className: "z-50 outline-none",
1721
+ children: /* @__PURE__ */ jsx(Popover.Popup, {
1722
+ ref: morph.popupRef,
1723
+ className: "relative outline-none",
1724
+ children: /* @__PURE__ */ jsx(ColorPickerPortalContainer2, {
1725
+ value: morph.popup,
1726
+ children: /* @__PURE__ */ jsx(SurfaceProvider2, {
1727
+ value: level,
1728
+ children: /* @__PURE__ */ jsx(MorphSurface, {
1729
+ morph,
1730
+ bg: SURFACE_BG[level],
1731
+ shadow: SURFACE_SHADOW[3],
1732
+ radius: shape.container,
1733
+ children: /* @__PURE__ */ jsx(PanelSurfaceContext.Provider, {
1734
+ value: false,
1735
+ children: /* @__PURE__ */ jsx(ColorPicker2, {
1736
+ ...pickerProps,
1737
+ value: currentValue,
1738
+ onValueChange: handleValueChange
1739
+ })
1740
+ })
1741
+ })
1742
+ })
1743
+ })
1744
+ })
1745
+ })
1746
+ })
1747
+ ]
1748
+ })
1749
+ });
1750
+ return size ? /* @__PURE__ */ jsx(SizeProvider2, {
1751
+ size,
1752
+ children: root
1753
+ }) : root;
1754
+ });
1755
+ ColorPickerPopover2.displayName = "ColorPickerPopover";
1756
+ Object.assign(ColorPicker2, { Popover: ColorPickerPopover2 });
1757
+ var color_picker_default = ColorPicker2;
1758
+
1759
+ export { ColorPickerPortalContainer2, parseColor2, buildParsed2, ColorTile2, ColorSwatch2, ColorPicker2, ColorPickerPopover2, color_picker_default };