xiod-ui 1.0.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 (224) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +167 -0
  3. package/dist/components/accordion.d.ts +9 -0
  4. package/dist/components/accordion.js +46 -0
  5. package/dist/components/agent-steps.d.ts +47 -0
  6. package/dist/components/agent-steps.js +223 -0
  7. package/dist/components/alert-dialog.d.ts +21 -0
  8. package/dist/components/alert-dialog.js +74 -0
  9. package/dist/components/alert.d.ts +12 -0
  10. package/dist/components/alert.js +45 -0
  11. package/dist/components/aspect-ratio.d.ts +9 -0
  12. package/dist/components/aspect-ratio.js +22 -0
  13. package/dist/components/autocomplete.d.ts +35 -0
  14. package/dist/components/autocomplete.js +160 -0
  15. package/dist/components/avatar.d.ts +17 -0
  16. package/dist/components/avatar.js +65 -0
  17. package/dist/components/badge.d.ts +15 -0
  18. package/dist/components/badge.js +46 -0
  19. package/dist/components/breadcrumb.d.ts +12 -0
  20. package/dist/components/breadcrumb.js +75 -0
  21. package/dist/components/button-group.d.ts +14 -0
  22. package/dist/components/button-group.js +45 -0
  23. package/dist/components/button-split.d.ts +19 -0
  24. package/dist/components/button-split.js +73 -0
  25. package/dist/components/button.d.ts +15 -0
  26. package/dist/components/button.js +54 -0
  27. package/dist/components/calendar.d.ts +63 -0
  28. package/dist/components/calendar.js +425 -0
  29. package/dist/components/card.d.ts +17 -0
  30. package/dist/components/card.js +139 -0
  31. package/dist/components/carousel.d.ts +59 -0
  32. package/dist/components/carousel.js +503 -0
  33. package/dist/components/checkbox.d.ts +16 -0
  34. package/dist/components/checkbox.js +86 -0
  35. package/dist/components/circular-progress.d.ts +28 -0
  36. package/dist/components/circular-progress.js +127 -0
  37. package/dist/components/collapsible.d.ts +8 -0
  38. package/dist/components/collapsible.js +27 -0
  39. package/dist/components/color-picker.d.ts +159 -0
  40. package/dist/components/color-picker.js +1589 -0
  41. package/dist/components/combobox.d.ts +46 -0
  42. package/dist/components/combobox.js +237 -0
  43. package/dist/components/command.d.ts +22 -0
  44. package/dist/components/command.js +129 -0
  45. package/dist/components/context-menu.d.ts +38 -0
  46. package/dist/components/context-menu.js +164 -0
  47. package/dist/components/copy-to-clipboard.d.ts +32 -0
  48. package/dist/components/copy-to-clipboard.js +83 -0
  49. package/dist/components/corner-badge.d.ts +22 -0
  50. package/dist/components/corner-badge.js +84 -0
  51. package/dist/components/dashboard-grid.d.ts +83 -0
  52. package/dist/components/dashboard-grid.js +486 -0
  53. package/dist/components/date-picker.d.ts +29 -0
  54. package/dist/components/date-picker.js +261 -0
  55. package/dist/components/dialog.d.ts +26 -0
  56. package/dist/components/dialog.js +97 -0
  57. package/dist/components/dot-matrix.d.ts +32 -0
  58. package/dist/components/dot-matrix.js +707 -0
  59. package/dist/components/draggable.d.ts +42 -0
  60. package/dist/components/draggable.js +346 -0
  61. package/dist/components/drawer.d.ts +66 -0
  62. package/dist/components/drawer.js +304 -0
  63. package/dist/components/empty.d.ts +14 -0
  64. package/dist/components/empty.js +75 -0
  65. package/dist/components/field.d.ts +12 -0
  66. package/dist/components/field.js +44 -0
  67. package/dist/components/fieldset.d.ts +7 -0
  68. package/dist/components/fieldset.js +21 -0
  69. package/dist/components/file-upload.d.ts +61 -0
  70. package/dist/components/file-upload.js +482 -0
  71. package/dist/components/form.d.ts +6 -0
  72. package/dist/components/form.js +14 -0
  73. package/dist/components/frame.d.ts +10 -0
  74. package/dist/components/frame.js +47 -0
  75. package/dist/components/gauge.d.ts +27 -0
  76. package/dist/components/gauge.js +74 -0
  77. package/dist/components/grid.d.ts +26 -0
  78. package/dist/components/grid.js +204 -0
  79. package/dist/components/group.d.ts +19 -0
  80. package/dist/components/group.js +45 -0
  81. package/dist/components/input-group.d.ts +15 -0
  82. package/dist/components/input-group.js +61 -0
  83. package/dist/components/input-otp.d.ts +24 -0
  84. package/dist/components/input-otp.js +50 -0
  85. package/dist/components/input-payment.d.ts +131 -0
  86. package/dist/components/input-payment.js +1140 -0
  87. package/dist/components/input-phone.d.ts +70 -0
  88. package/dist/components/input-phone.js +657 -0
  89. package/dist/components/input-sensitive.d.ts +12 -0
  90. package/dist/components/input-sensitive.js +169 -0
  91. package/dist/components/input.d.ts +13 -0
  92. package/dist/components/input.js +26 -0
  93. package/dist/components/kbd.d.ts +6 -0
  94. package/dist/components/kbd.js +19 -0
  95. package/dist/components/kinetic-click.d.ts +48 -0
  96. package/dist/components/kinetic-click.js +1184 -0
  97. package/dist/components/label.d.ts +6 -0
  98. package/dist/components/label.js +18 -0
  99. package/dist/components/list-box.d.ts +20 -0
  100. package/dist/components/list-box.js +148 -0
  101. package/dist/components/loader.d.ts +13 -0
  102. package/dist/components/loader.js +430 -0
  103. package/dist/components/marker.d.ts +15 -0
  104. package/dist/components/marker.js +59 -0
  105. package/dist/components/menu.d.ts +42 -0
  106. package/dist/components/menu.js +186 -0
  107. package/dist/components/menubar.d.ts +40 -0
  108. package/dist/components/menubar.js +107 -0
  109. package/dist/components/message.d.ts +33 -0
  110. package/dist/components/message.js +112 -0
  111. package/dist/components/meter.d.ts +10 -0
  112. package/dist/components/meter.js +42 -0
  113. package/dist/components/morphic-toast.d.ts +61 -0
  114. package/dist/components/morphic-toast.js +916 -0
  115. package/dist/components/navigation-menu.d.ts +26 -0
  116. package/dist/components/navigation-menu.js +116 -0
  117. package/dist/components/number-field.d.ts +15 -0
  118. package/dist/components/number-field.js +86 -0
  119. package/dist/components/option-picker.d.ts +18 -0
  120. package/dist/components/option-picker.js +89 -0
  121. package/dist/components/orb.d.ts +38 -0
  122. package/dist/components/orb.js +1413 -0
  123. package/dist/components/pagination.d.ts +25 -0
  124. package/dist/components/pagination.js +147 -0
  125. package/dist/components/popover.d.ts +22 -0
  126. package/dist/components/popover.js +79 -0
  127. package/dist/components/preview-card.d.ts +16 -0
  128. package/dist/components/preview-card.js +60 -0
  129. package/dist/components/progress.d.ts +21 -0
  130. package/dist/components/progress.js +139 -0
  131. package/dist/components/radio.d.ts +16 -0
  132. package/dist/components/radio.js +68 -0
  133. package/dist/components/resizable.d.ts +58 -0
  134. package/dist/components/resizable.js +964 -0
  135. package/dist/components/ruler-picker.d.ts +27 -0
  136. package/dist/components/ruler-picker.js +253 -0
  137. package/dist/components/scroll-area.d.ts +13 -0
  138. package/dist/components/scroll-area.js +34 -0
  139. package/dist/components/scroll-bar.d.ts +13 -0
  140. package/dist/components/scroll-bar.js +47 -0
  141. package/dist/components/select.d.ts +29 -0
  142. package/dist/components/select.js +140 -0
  143. package/dist/components/separator.d.ts +6 -0
  144. package/dist/components/separator.js +15 -0
  145. package/dist/components/sidebar.d.ts +65 -0
  146. package/dist/components/sidebar.js +408 -0
  147. package/dist/components/skeleton.d.ts +5 -0
  148. package/dist/components/skeleton.js +12 -0
  149. package/dist/components/slider.d.ts +12 -0
  150. package/dist/components/slider.js +96 -0
  151. package/dist/components/sortable.d.ts +44 -0
  152. package/dist/components/sortable.js +327 -0
  153. package/dist/components/switch.d.ts +15 -0
  154. package/dist/components/switch.js +63 -0
  155. package/dist/components/table.d.ts +12 -0
  156. package/dist/components/table.js +65 -0
  157. package/dist/components/tabs.d.ts +12 -0
  158. package/dist/components/tabs.js +39 -0
  159. package/dist/components/text.d.ts +14 -0
  160. package/dist/components/text.js +69 -0
  161. package/dist/components/textarea.d.ts +9 -0
  162. package/dist/components/textarea.js +20 -0
  163. package/dist/components/theme-provider.d.ts +52 -0
  164. package/dist/components/theme-provider.js +148 -0
  165. package/dist/components/timeline.d.ts +34 -0
  166. package/dist/components/timeline.js +147 -0
  167. package/dist/components/toast.d.ts +17 -0
  168. package/dist/components/toast.js +161 -0
  169. package/dist/components/toggle-group.d.ts +14 -0
  170. package/dist/components/toggle-group.js +53 -0
  171. package/dist/components/toggle.d.ts +11 -0
  172. package/dist/components/toggle.js +36 -0
  173. package/dist/components/toolbar.d.ts +11 -0
  174. package/dist/components/toolbar.js +49 -0
  175. package/dist/components/tooltip.d.ts +17 -0
  176. package/dist/components/tooltip.js +56 -0
  177. package/dist/components/waveform.d.ts +61 -0
  178. package/dist/components/waveform.js +500 -0
  179. package/dist/components/wheel-picker.d.ts +44 -0
  180. package/dist/components/wheel-picker.js +771 -0
  181. package/dist/hooks/use-copy-to-clipboard.d.ts +9 -0
  182. package/dist/hooks/use-copy-to-clipboard.js +36 -0
  183. package/dist/hooks/use-media-query.d.ts +21 -0
  184. package/dist/hooks/use-media-query.js +58 -0
  185. package/dist/styles.css +202 -0
  186. package/dist/themes/afterglow.css +89 -0
  187. package/dist/themes/afterglow.scoped.css +90 -0
  188. package/dist/themes/blacklight.css +89 -0
  189. package/dist/themes/blacklight.scoped.css +90 -0
  190. package/dist/themes/cathode.css +89 -0
  191. package/dist/themes/cathode.scoped.css +90 -0
  192. package/dist/themes/cel.css +89 -0
  193. package/dist/themes/cel.scoped.css +90 -0
  194. package/dist/themes/cinder.css +89 -0
  195. package/dist/themes/cinder.scoped.css +90 -0
  196. package/dist/themes/clay.css +89 -0
  197. package/dist/themes/clay.scoped.css +90 -0
  198. package/dist/themes/cobalt.css +89 -0
  199. package/dist/themes/cobalt.scoped.css +90 -0
  200. package/dist/themes/crimson.css +89 -0
  201. package/dist/themes/crimson.scoped.css +90 -0
  202. package/dist/themes/ion.css +89 -0
  203. package/dist/themes/ion.scoped.css +90 -0
  204. package/dist/themes/iris.css +89 -0
  205. package/dist/themes/iris.scoped.css +90 -0
  206. package/dist/themes/lagoon.css +89 -0
  207. package/dist/themes/lagoon.scoped.css +90 -0
  208. package/dist/themes/mochi.css +89 -0
  209. package/dist/themes/mochi.scoped.css +90 -0
  210. package/dist/themes/riso.css +89 -0
  211. package/dist/themes/riso.scoped.css +90 -0
  212. package/dist/themes/roast.css +89 -0
  213. package/dist/themes/roast.scoped.css +90 -0
  214. package/dist/themes/sage.css +89 -0
  215. package/dist/themes/sage.scoped.css +90 -0
  216. package/dist/themes/sepia.css +89 -0
  217. package/dist/themes/sepia.scoped.css +90 -0
  218. package/dist/themes/sorbet.css +89 -0
  219. package/dist/themes/sorbet.scoped.css +90 -0
  220. package/dist/themes/taffy.css +89 -0
  221. package/dist/themes/taffy.scoped.css +90 -0
  222. package/dist/themes/toxin.css +89 -0
  223. package/dist/themes/toxin.scoped.css +90 -0
  224. package/package.json +140 -0
@@ -0,0 +1,1589 @@
1
+ "use client";
2
+ import { cn } from "cn";
3
+ import { ChevronDown } from "xiod-icons/icons/ChevronDown";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import * as React$1 from "react";
6
+ import { Dropper } from "xiod-icons/icons/Dropper";
7
+ //#region src/components/color-picker.tsx
8
+ const OUTER_COLORS = [
9
+ {
10
+ h: 47,
11
+ s: 97,
12
+ l: 65
13
+ },
14
+ {
15
+ h: 37,
16
+ s: 98,
17
+ l: 65
18
+ },
19
+ {
20
+ h: 27,
21
+ s: 95,
22
+ l: 64
23
+ },
24
+ {
25
+ h: 14,
26
+ s: 90,
27
+ l: 64
28
+ },
29
+ {
30
+ h: 0,
31
+ s: 85,
32
+ l: 64
33
+ },
34
+ {
35
+ h: 327,
36
+ s: 75,
37
+ l: 62
38
+ },
39
+ {
40
+ h: 285,
41
+ s: 51,
42
+ l: 59
43
+ },
44
+ {
45
+ h: 257,
46
+ s: 65,
47
+ l: 64
48
+ },
49
+ {
50
+ h: 225,
51
+ s: 71,
52
+ l: 65
53
+ },
54
+ {
55
+ h: 202,
56
+ s: 68,
57
+ l: 65
58
+ },
59
+ {
60
+ h: 151,
61
+ s: 43,
62
+ l: 63
63
+ },
64
+ {
65
+ h: 96,
66
+ s: 49,
67
+ l: 67
68
+ }
69
+ ];
70
+ const INNER_COLORS = [
71
+ {
72
+ h: 50,
73
+ s: 95,
74
+ l: 85
75
+ },
76
+ {
77
+ h: 26,
78
+ s: 89,
79
+ l: 89
80
+ },
81
+ {
82
+ h: 345,
83
+ s: 77,
84
+ l: 88
85
+ },
86
+ {
87
+ h: 283,
88
+ s: 47,
89
+ l: 84
90
+ },
91
+ {
92
+ h: 209,
93
+ s: 70,
94
+ l: 87
95
+ },
96
+ {
97
+ h: 116,
98
+ s: 42,
99
+ l: 87
100
+ }
101
+ ];
102
+ const DEFAULT_COLORS = [...INNER_COLORS, ...OUTER_COLORS];
103
+ const BLOOM_EASING_CSS = "linear(0, 0.060 3%, 0.200 7%, 0.420 13%, 0.680 20%, 0.900 28%, 1.020 35%, 1.060 45%, 1.025 53%, 0.997 62%, 1.0 68%)";
104
+ const PETAL_STAGGER = 20;
105
+ const BAR_GAP = 20;
106
+ const BAR_WIDTH = 12;
107
+ const SLIDER_OFFSET = 30;
108
+ const ARC_GRADIENT_STEPS = 11;
109
+ const DEFAULT_VALUE = {
110
+ hue: 330,
111
+ saturation: 70,
112
+ alpha: 50,
113
+ layer: "outer"
114
+ };
115
+ function lightnessToSliderValue(l) {
116
+ const minLightness = 20;
117
+ const maxLightness = 100;
118
+ return (maxLightness - Math.max(minLightness, Math.min(maxLightness, l))) / 80 * 100;
119
+ }
120
+ function sliderValueToLightness(sliderValue) {
121
+ return 100 - sliderValue / 100 * 80;
122
+ }
123
+ function hexToHsl(hex) {
124
+ let cleanHex = hex.replace(/^#/, "");
125
+ if (cleanHex.length === 3) cleanHex = cleanHex.split("").map((c) => c + c).join("");
126
+ const r = parseInt(cleanHex.slice(0, 2), 16) / 255;
127
+ const g = parseInt(cleanHex.slice(2, 4), 16) / 255;
128
+ const b = parseInt(cleanHex.slice(4, 6), 16) / 255;
129
+ const max = Math.max(r, g, b);
130
+ const min = Math.min(r, g, b);
131
+ const l = (max + min) / 2;
132
+ if (max === min) return {
133
+ h: 0,
134
+ s: 0,
135
+ l: Math.round(l * 100)
136
+ };
137
+ const d = max - min;
138
+ const s = l > .5 ? d / (2 - max - min) : d / (max + min);
139
+ let h = 0;
140
+ switch (max) {
141
+ case r:
142
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
143
+ break;
144
+ case g:
145
+ h = ((b - r) / d + 2) / 6;
146
+ break;
147
+ case b: h = ((r - g) / d + 4) / 6;
148
+ }
149
+ return {
150
+ h: Math.round(h * 360),
151
+ s: Math.round(s * 100),
152
+ l: Math.round(l * 100)
153
+ };
154
+ }
155
+ function rgbToHsl(r, g, b) {
156
+ r /= 255;
157
+ g /= 255;
158
+ b /= 255;
159
+ const max = Math.max(r, g, b);
160
+ const min = Math.min(r, g, b);
161
+ const l = (max + min) / 2;
162
+ if (max === min) return {
163
+ h: 0,
164
+ s: 0,
165
+ l: Math.round(l * 100)
166
+ };
167
+ const d = max - min;
168
+ const s = l > .5 ? d / (2 - max - min) : d / (max + min);
169
+ let h = 0;
170
+ switch (max) {
171
+ case r:
172
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
173
+ break;
174
+ case g:
175
+ h = ((b - r) / d + 2) / 6;
176
+ break;
177
+ case b: h = ((r - g) / d + 4) / 6;
178
+ }
179
+ return {
180
+ h: Math.round(h * 360),
181
+ s: Math.round(s * 100),
182
+ l: Math.round(l * 100)
183
+ };
184
+ }
185
+ function parseColor(input) {
186
+ if (typeof input === "object") return input;
187
+ const str = input.trim().toLowerCase();
188
+ if (str.startsWith("#")) return hexToHsl(str);
189
+ const hslMatch = str.match(/^hsla?\(\s*([\d.]+)[\s,]+([\d.]+)%?[\s,]+([\d.]+)%?/);
190
+ if (hslMatch) return {
191
+ h: Math.round(parseFloat(hslMatch[1])),
192
+ s: Math.round(parseFloat(hslMatch[2])),
193
+ l: Math.round(parseFloat(hslMatch[3]))
194
+ };
195
+ const rgbMatch = str.match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/);
196
+ if (rgbMatch) return rgbToHsl(parseFloat(rgbMatch[1]), parseFloat(rgbMatch[2]), parseFloat(rgbMatch[3]));
197
+ return {
198
+ h: 0,
199
+ s: 0,
200
+ l: 50
201
+ };
202
+ }
203
+ function hslToHex(h, s, l) {
204
+ const sNorm = s / 100;
205
+ const lNorm = l / 100;
206
+ const c = (1 - Math.abs(2 * lNorm - 1)) * sNorm;
207
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
208
+ const m = lNorm - c / 2;
209
+ let r = 0;
210
+ let g = 0;
211
+ let b = 0;
212
+ if (h >= 0 && h < 60) {
213
+ r = c;
214
+ g = x;
215
+ b = 0;
216
+ } else if (h >= 60 && h < 120) {
217
+ r = x;
218
+ g = c;
219
+ b = 0;
220
+ } else if (h >= 120 && h < 180) {
221
+ r = 0;
222
+ g = c;
223
+ b = x;
224
+ } else if (h >= 180 && h < 240) {
225
+ r = 0;
226
+ g = x;
227
+ b = c;
228
+ } else if (h >= 240 && h < 300) {
229
+ r = x;
230
+ g = 0;
231
+ b = c;
232
+ } else {
233
+ r = c;
234
+ g = 0;
235
+ b = x;
236
+ }
237
+ const toHex = (n) => {
238
+ const hex = Math.round((n + m) * 255).toString(16);
239
+ return hex.length === 1 ? `0${hex}` : hex;
240
+ };
241
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
242
+ }
243
+ function getVisualSaturation(sliderValue, baseSaturation) {
244
+ return sliderValue < 10 ? sliderValue / 10 * baseSaturation : baseSaturation;
245
+ }
246
+ function hslToString(h, s, l) {
247
+ return `hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`;
248
+ }
249
+ function hslaToString(h, s, l, a) {
250
+ return `hsla(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%, ${(a / 100).toFixed(2)})`;
251
+ }
252
+ function hslToRgb(h, s, l) {
253
+ const sNorm = s / 100;
254
+ const lNorm = l / 100;
255
+ const k = (n) => (n + h / 30) % 12;
256
+ const a = sNorm * Math.min(lNorm, 1 - lNorm);
257
+ const f = (n) => lNorm - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
258
+ return {
259
+ r: Math.round(255 * f(0)),
260
+ g: Math.round(255 * f(8)),
261
+ b: Math.round(255 * f(4))
262
+ };
263
+ }
264
+ function rgbaToString(r, g, b, a) {
265
+ return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${(a / 100).toFixed(2)})`;
266
+ }
267
+ function createColorOutput(hue, sliderValue, visualSaturation, baseSaturation, lightness, alpha, layer) {
268
+ const { r, g, b } = hslToRgb(hue, visualSaturation, lightness);
269
+ return {
270
+ hue,
271
+ saturation: sliderValue,
272
+ originalSaturation: baseSaturation,
273
+ lightness,
274
+ alpha,
275
+ layer,
276
+ r,
277
+ g,
278
+ b,
279
+ hex: hslToHex(hue, visualSaturation, lightness),
280
+ hsl: hslToString(hue, visualSaturation, lightness),
281
+ hsla: hslaToString(hue, visualSaturation, lightness, alpha),
282
+ rgb: `rgb(${r}, ${g}, ${b})`,
283
+ rgba: rgbaToString(r, g, b, alpha)
284
+ };
285
+ }
286
+ function organizeColorsIntoLayers(colors) {
287
+ if (!colors || colors.length === 0) return [];
288
+ const sortedByLightness = colors.toSorted((a, b) => b.l - a.l);
289
+ const total = sortedByLightness.length;
290
+ let layerCounts = [];
291
+ if (total <= 10) layerCounts = [total];
292
+ else if (total <= 24) {
293
+ const inner = Math.max(4, Math.floor(total * .35));
294
+ layerCounts = [inner, total - inner];
295
+ } else if (total <= 42) {
296
+ const inner = Math.max(5, Math.floor(total * .15));
297
+ const middle = Math.floor(total * .35);
298
+ layerCounts = [
299
+ inner,
300
+ middle,
301
+ total - inner - middle
302
+ ];
303
+ } else {
304
+ const inner = Math.max(6, Math.floor(total * .1));
305
+ const mid1 = Math.floor(total * .2);
306
+ const mid2 = Math.floor(total * .3);
307
+ layerCounts = [
308
+ inner,
309
+ mid1,
310
+ mid2,
311
+ total - inner - mid1 - mid2
312
+ ];
313
+ }
314
+ const layers = [];
315
+ let currentIndex = 0;
316
+ for (let i = 0; i < layerCounts.length; i++) {
317
+ const count = layerCounts[i];
318
+ const itemsForThisLayer = sortedByLightness.slice(currentIndex, currentIndex + count);
319
+ itemsForThisLayer.sort((a, b) => a.h - b.h);
320
+ if (itemsForThisLayer.length > 0) layers.push(itemsForThisLayer);
321
+ currentIndex += count;
322
+ }
323
+ return layers;
324
+ }
325
+ function calculateLayerRadii(layers, coreSize, petalSize) {
326
+ const radii = [];
327
+ const W = petalSize;
328
+ const Rc = coreSize / 2;
329
+ const Rp = petalSize / 2;
330
+ for (let i = 0; i < layers.length; i++) {
331
+ const N = layers[i].length;
332
+ const overlapFactor = N <= 8 ? .45 : N <= 12 ? .5 : .55;
333
+ const lateralGaplessR = N * W * overlapFactor / (2 * Math.PI);
334
+ let r = 0;
335
+ if (i === 0) {
336
+ const coreOverlap = N <= 5 ? W * .35 : W * .25;
337
+ const idealCoreR = Rc + Rp - coreOverlap;
338
+ r = Math.max(idealCoreR, lateralGaplessR);
339
+ } else {
340
+ const prevR = radii[i - 1];
341
+ const prevN = layers[i - 1].length;
342
+ const circumference = 2 * Math.PI * prevR;
343
+ const sparsity = prevN * W / circumference;
344
+ let adaptiveStep = W * .35;
345
+ if (sparsity < .85) adaptiveStep = W * .15;
346
+ else if (sparsity > 1.1) adaptiveStep = W * .45;
347
+ const idealNestleR = prevR + adaptiveStep;
348
+ r = Math.max(idealNestleR, lateralGaplessR);
349
+ r = Math.max(r, prevR + W * .1);
350
+ }
351
+ radii.push(r);
352
+ }
353
+ return radii;
354
+ }
355
+ function calculateLayerRotations(layers) {
356
+ const rotations = [0];
357
+ for (let i = 1; i < layers.length; i++) {
358
+ const offset = 360 / layers[i - 1].length / 2;
359
+ rotations.push(offset);
360
+ }
361
+ return rotations;
362
+ }
363
+ function calculateBarRadius(layerRadii, petalSize, coreSize, barGap) {
364
+ return layerRadii.length > 0 ? layerRadii[layerRadii.length - 1] + petalSize / 2 + barGap : coreSize / 2 + barGap;
365
+ }
366
+ function calculateContainerSize(barRadius, circularBarWidth, showAlphaSlider, showOpacitySlider, sliderOffset, sliderWidth) {
367
+ const barExtent = barRadius + circularBarWidth / 2;
368
+ const sliderExtent = showAlphaSlider || showOpacitySlider ? barRadius + sliderOffset + sliderWidth / 2 : 0;
369
+ return Math.max(barExtent, sliderExtent) * 2 + 4;
370
+ }
371
+ function getPetalZIndex(index, bottomIndex, totalPetals, layerIdx, totalLayers, isBottomLeft = false, isBottomRight = false) {
372
+ const baseZ = (totalLayers - layerIdx) * 100;
373
+ const maxLocalZ = totalPetals + 10;
374
+ if (index === bottomIndex) {
375
+ if (isBottomRight) return baseZ + maxLocalZ;
376
+ if (isBottomLeft) return baseZ;
377
+ return baseZ;
378
+ }
379
+ return baseZ + (index - bottomIndex + totalPetals) % totalPetals;
380
+ }
381
+ function polarToCartesian(cx, cy, r, angleInDegrees) {
382
+ const angleInRadians = angleInDegrees * Math.PI / 180;
383
+ return {
384
+ x: cx + r * Math.cos(angleInRadians),
385
+ y: cy + r * Math.sin(angleInRadians)
386
+ };
387
+ }
388
+ function describeArc(cx, cy, r, startAng, endAng) {
389
+ const start = polarToCartesian(cx, cy, r, startAng);
390
+ const end = polarToCartesian(cx, cy, r, endAng);
391
+ const largeArcFlag = Math.abs(endAng - startAng) > 180 ? "1" : "0";
392
+ return `M ${start.x} ${start.y} A ${r} ${r} 0 ${largeArcFlag} 1 ${end.x} ${end.y}`;
393
+ }
394
+ function getCenterAngle(position) {
395
+ switch (position) {
396
+ case "top": return -90;
397
+ case "bottom": return 90;
398
+ case "left": return 180;
399
+ default: return 0;
400
+ }
401
+ }
402
+ function getOppositePosition(position) {
403
+ switch (position) {
404
+ case "left": return "right";
405
+ case "right": return "left";
406
+ case "top": return "bottom";
407
+ default: return "top";
408
+ }
409
+ }
410
+ function calculateSliderValueFromPoint(dx, dy, centerAngle, halfSweep, position) {
411
+ let normalizedAngle = Math.atan2(dy, dx) * (180 / Math.PI) - centerAngle;
412
+ while (normalizedAngle > 180) normalizedAngle -= 360;
413
+ while (normalizedAngle < -180) normalizedAngle += 360;
414
+ normalizedAngle = Math.max(-halfSweep, Math.min(halfSweep, normalizedAngle));
415
+ let newValue;
416
+ if (position === "left") newValue = (halfSweep - normalizedAngle) / (2 * halfSweep) * 100;
417
+ else newValue = (normalizedAngle + halfSweep) / (2 * halfSweep) * 100;
418
+ return Math.round(Math.max(0, Math.min(100, newValue)));
419
+ }
420
+ function calculateArcGradientColors(hue, baseSaturation, steps) {
421
+ return Array.from({ length: steps }, (_, i) => {
422
+ const t = i / (steps - 1);
423
+ return hslToString(hue, getVisualSaturation(t * 100, baseSaturation), 100 - t * 80);
424
+ });
425
+ }
426
+ function computeAdaptivePosition({ elementRect, containerSize, currentShiftOffset, windowWidth, windowHeight, sliderPosition, adaptivePositioning, circularBarWidth, sliderOffset }) {
427
+ const halfSize = containerSize / 2;
428
+ const centerX = elementRect.left + elementRect.width / 2 - currentShiftOffset.x;
429
+ const centerY = elementRect.top + elementRect.height / 2 - currentShiftOffset.y;
430
+ let newShiftX = 0;
431
+ let newShiftY = 0;
432
+ if (adaptivePositioning) {
433
+ const padding = 10;
434
+ if (centerX + halfSize > windowWidth - padding) newShiftX = windowWidth - padding - (centerX + halfSize);
435
+ else if (centerX - halfSize < padding) newShiftX = padding - (centerX - halfSize);
436
+ if (centerY + halfSize > windowHeight - padding) newShiftY = windowHeight - padding - (centerY + halfSize);
437
+ else if (centerY - halfSize < padding) newShiftY = padding - (centerY - halfSize);
438
+ }
439
+ let effectivePosition = sliderPosition || "right";
440
+ if (!sliderPosition) {
441
+ const spaceRight = windowWidth - (centerX + newShiftX + halfSize);
442
+ const spaceLeft = centerX + newShiftX - halfSize;
443
+ const spaceTop = centerY + newShiftY - halfSize;
444
+ const spaceBottom = windowHeight - (centerY + newShiftY + halfSize);
445
+ const threshold = sliderOffset + circularBarWidth + 20;
446
+ if (spaceRight < threshold && spaceLeft > spaceRight) effectivePosition = "left";
447
+ else if (spaceLeft < threshold && spaceRight > spaceLeft) effectivePosition = "right";
448
+ else if (spaceBottom < threshold && spaceTop > spaceBottom) effectivePosition = "top";
449
+ else if (spaceTop < threshold && spaceBottom > spaceTop) effectivePosition = "bottom";
450
+ else effectivePosition = "right";
451
+ }
452
+ return {
453
+ effectivePosition,
454
+ shiftOffset: {
455
+ x: newShiftX,
456
+ y: newShiftY
457
+ }
458
+ };
459
+ }
460
+ function BlossomColorPicker({ value, defaultValue, colors, onChange, onCollapse, disabled = false, openOnHover = false, initialExpanded = false, animationDuration = 300, showAlphaSlider = true, showOpacitySlider = true, coreSize = 32, petalSize = 32, showCoreColor = true, sliderPosition, adaptivePositioning = true, circularBarWidth = BAR_WIDTH, sliderWidth = BAR_WIDTH, sliderOffset = SLIDER_OFFSET, collapsible = true, className, ref, ...props }) {
461
+ const rootRef = React$1.useRef(null);
462
+ const svgRef = React$1.useRef(null);
463
+ const alphaSvgRef = React$1.useRef(null);
464
+ React$1.useImperativeHandle(ref, () => rootRef.current);
465
+ const [internalValue, setInternalValue] = React$1.useState(defaultValue ?? DEFAULT_VALUE);
466
+ const [isExpanded, setIsExpanded] = React$1.useState(!collapsible || initialExpanded);
467
+ const [mousePos, setMousePos] = React$1.useState(null);
468
+ const [isHoveringCore, setIsHoveringCore] = React$1.useState(false);
469
+ const [hoveredPetal, setHoveredPetal] = React$1.useState(null);
470
+ const [shiftOffset, setShiftOffset] = React$1.useState({
471
+ x: 0,
472
+ y: 0
473
+ });
474
+ const [effectivePosition, setEffectivePosition] = React$1.useState(sliderPosition || "right");
475
+ const [isDraggingSlider, setIsDraggingSlider] = React$1.useState(false);
476
+ const [isDraggingAlpha, setIsDraggingAlpha] = React$1.useState(false);
477
+ const prevExpandedRef = React$1.useRef(isExpanded);
478
+ const [hasEyeDropper, setHasEyeDropper] = React$1.useState(false);
479
+ React$1.useEffect(() => {
480
+ setHasEyeDropper(typeof window !== "undefined" && "EyeDropper" in window);
481
+ }, []);
482
+ const [mounted, setMounted] = React$1.useState(false);
483
+ React$1.useEffect(() => {
484
+ setMounted(true);
485
+ }, []);
486
+ const currentValue = value ?? internalValue;
487
+ const normalizedColors = React$1.useMemo(() => {
488
+ return colors && colors.length > 0 ? colors.map(parseColor) : DEFAULT_COLORS;
489
+ }, [colors]);
490
+ const { layers, allColors, layerPrefixCounts, layerRadii, layerRotations, barRadius, containerSize } = React$1.useMemo(() => {
491
+ const lay = organizeColorsIntoLayers(normalizedColors);
492
+ const allCol = lay.flat();
493
+ const lpc = [0];
494
+ for (let i = 1; i < lay.length; i++) lpc.push(lpc[i - 1] + lay[i - 1].length);
495
+ const radii = calculateLayerRadii(lay, coreSize, petalSize);
496
+ const rots = calculateLayerRotations(lay);
497
+ const bRad = calculateBarRadius(radii, petalSize, coreSize, BAR_GAP);
498
+ return {
499
+ layers: lay,
500
+ allColors: allCol,
501
+ layerPrefixCounts: lpc,
502
+ layerRadii: radii,
503
+ layerRotations: rots,
504
+ barRadius: bRad,
505
+ containerSize: calculateContainerSize(bRad, circularBarWidth, showAlphaSlider, showOpacitySlider, sliderOffset, sliderWidth)
506
+ };
507
+ }, [
508
+ normalizedColors,
509
+ coreSize,
510
+ petalSize,
511
+ circularBarWidth,
512
+ showAlphaSlider,
513
+ showOpacitySlider,
514
+ sliderOffset,
515
+ sliderWidth
516
+ ]);
517
+ const baseSaturation = React$1.useMemo(() => {
518
+ if (currentValue.originalSaturation !== void 0) return currentValue.originalSaturation;
519
+ return allColors.find((c) => c.h === currentValue.hue)?.s ?? 70;
520
+ }, [
521
+ allColors,
522
+ currentValue.hue,
523
+ currentValue.originalSaturation
524
+ ]);
525
+ const currentLightness = React$1.useMemo(() => {
526
+ return currentValue.lightness ?? sliderValueToLightness(currentValue.saturation);
527
+ }, [currentValue.lightness, currentValue.saturation]);
528
+ const visualSaturation = React$1.useMemo(() => {
529
+ return getVisualSaturation(currentValue.saturation, baseSaturation);
530
+ }, [currentValue.saturation, baseSaturation]);
531
+ const coreColorString = React$1.useMemo(() => {
532
+ if (isExpanded && !showCoreColor) return "#FFFFFF";
533
+ return hslaToString(currentValue.hue, baseSaturation, currentLightness, currentValue.alpha);
534
+ }, [
535
+ isExpanded,
536
+ showCoreColor,
537
+ currentValue.hue,
538
+ baseSaturation,
539
+ currentLightness,
540
+ currentValue.alpha
541
+ ]);
542
+ const outputColor = React$1.useMemo(() => {
543
+ return createColorOutput(currentValue.hue, currentValue.saturation, visualSaturation, baseSaturation, currentLightness, currentValue.alpha, currentValue.layer);
544
+ }, [
545
+ currentValue,
546
+ visualSaturation,
547
+ baseSaturation,
548
+ currentLightness
549
+ ]);
550
+ React$1.useEffect(() => {
551
+ if (isExpanded && rootRef.current) {
552
+ const result = computeAdaptivePosition({
553
+ elementRect: rootRef.current.getBoundingClientRect(),
554
+ containerSize,
555
+ currentShiftOffset: {
556
+ x: 0,
557
+ y: 0
558
+ },
559
+ windowWidth: typeof window !== "undefined" ? window.innerWidth : 1e3,
560
+ windowHeight: typeof window !== "undefined" ? window.innerHeight : 800,
561
+ sliderPosition,
562
+ adaptivePositioning,
563
+ circularBarWidth,
564
+ sliderOffset
565
+ });
566
+ setShiftOffset(result.shiftOffset);
567
+ setEffectivePosition(result.effectivePosition);
568
+ } else if (!isExpanded) {
569
+ setShiftOffset({
570
+ x: 0,
571
+ y: 0
572
+ });
573
+ setEffectivePosition(sliderPosition || "right");
574
+ }
575
+ prevExpandedRef.current = isExpanded;
576
+ }, [
577
+ isExpanded,
578
+ containerSize,
579
+ sliderPosition,
580
+ adaptivePositioning,
581
+ circularBarWidth,
582
+ sliderOffset
583
+ ]);
584
+ React$1.useEffect(() => {
585
+ if (!collapsible || !isExpanded) return;
586
+ const handleClick = (e) => {
587
+ if (!rootRef.current) return;
588
+ const rect = rootRef.current.getBoundingClientRect();
589
+ const centerX = rect.left + rect.width / 2;
590
+ const centerY = rect.top + rect.height / 2;
591
+ const dx = e.clientX - centerX;
592
+ const dy = e.clientY - centerY;
593
+ if (Math.sqrt(dx * dx + dy * dy) > Math.max(barRadius + circularBarWidth / 2, showAlphaSlider || showOpacitySlider ? barRadius + sliderOffset + sliderWidth / 2 : 0) + 4 || !rootRef.current.contains(e.target)) {
594
+ setIsExpanded(false);
595
+ if (onCollapse) onCollapse(outputColor);
596
+ }
597
+ };
598
+ document.addEventListener("mousedown", handleClick);
599
+ return () => document.removeEventListener("mousedown", handleClick);
600
+ }, [
601
+ collapsible,
602
+ isExpanded,
603
+ onCollapse,
604
+ outputColor,
605
+ barRadius,
606
+ circularBarWidth,
607
+ showAlphaSlider,
608
+ showOpacitySlider,
609
+ sliderOffset,
610
+ sliderWidth
611
+ ]);
612
+ const updateValue = (nextVal) => {
613
+ if (!value) setInternalValue(nextVal);
614
+ if (onChange) {
615
+ const newBaseSaturation = nextVal.originalSaturation ?? allColors.find((c) => c.h === nextVal.hue)?.s ?? 70;
616
+ const nextLightness = nextVal.lightness ?? sliderValueToLightness(nextVal.saturation);
617
+ const nextVisualSat = getVisualSaturation(nextVal.saturation, newBaseSaturation);
618
+ const { r, g, b } = hslToRgb(nextVal.hue, nextVisualSat, nextLightness);
619
+ onChange({
620
+ ...nextVal,
621
+ originalSaturation: newBaseSaturation,
622
+ lightness: nextLightness,
623
+ hex: hslToHex(nextVal.hue, nextVisualSat, nextLightness),
624
+ hsl: hslToString(nextVal.hue, nextVisualSat, nextLightness),
625
+ hsla: hslaToString(nextVal.hue, nextVisualSat, nextLightness, nextVal.alpha),
626
+ rgb: `rgb(${r}, ${g}, ${b})`,
627
+ rgba: rgbaToString(r, g, b, nextVal.alpha),
628
+ r,
629
+ g,
630
+ b
631
+ });
632
+ }
633
+ };
634
+ const handleCoreClick = async () => {
635
+ if (disabled) return;
636
+ if (isExpanded && hasEyeDropper) {
637
+ try {
638
+ const EyeDropperClass = window.EyeDropper;
639
+ const result = await new EyeDropperClass().open();
640
+ if (result?.sRGBHex) {
641
+ const hex = result.sRGBHex;
642
+ const hsl = hexToHsl(hex);
643
+ updateValue({
644
+ hue: hsl.h,
645
+ saturation: lightnessToSliderValue(hsl.l),
646
+ lightness: hsl.l,
647
+ originalSaturation: hsl.s,
648
+ alpha: currentValue.alpha,
649
+ layer: "outer"
650
+ });
651
+ }
652
+ } catch (err) {
653
+ console.warn("EyeDropper failed or was cancelled:", err);
654
+ }
655
+ return;
656
+ }
657
+ if (collapsible) {
658
+ const next = !isExpanded;
659
+ setIsExpanded(next);
660
+ if (!next && onCollapse) onCollapse(outputColor);
661
+ }
662
+ };
663
+ const handlePetalClick = (color, layerIdx) => {
664
+ updateValue({
665
+ hue: color.h,
666
+ saturation: lightnessToSliderValue(color.l),
667
+ lightness: color.l,
668
+ originalSaturation: color.s,
669
+ alpha: currentValue.alpha,
670
+ layer: layerIdx === 0 ? "inner" : "outer"
671
+ });
672
+ };
673
+ const handleSliderChange = (val) => {
674
+ const lightness = sliderValueToLightness(val);
675
+ updateValue({
676
+ ...currentValue,
677
+ saturation: val,
678
+ lightness,
679
+ originalSaturation: currentValue.originalSaturation ?? baseSaturation
680
+ });
681
+ };
682
+ const handleMouseEnter = () => {
683
+ if (disabled) return;
684
+ if (openOnHover && collapsible) setIsExpanded(true);
685
+ };
686
+ const handleMouseMove = (e) => {
687
+ if (!isExpanded) return;
688
+ const rect = e.currentTarget.getBoundingClientRect();
689
+ const x = e.clientX - (rect.left + rect.width / 2);
690
+ const y = e.clientY - (rect.top + rect.height / 2);
691
+ setMousePos({
692
+ x,
693
+ y
694
+ });
695
+ };
696
+ const handleMouseLeave = () => {
697
+ setMousePos(null);
698
+ };
699
+ const handleSliderPointerDown = (e) => {
700
+ e.preventDefault();
701
+ setIsDraggingSlider(true);
702
+ updateSliderFromPointer(e.clientX, e.clientY);
703
+ };
704
+ const updateSliderFromPointer = (clientX, clientY) => {
705
+ if (!svgRef.current) return;
706
+ const rect = svgRef.current.getBoundingClientRect();
707
+ const centerX = rect.left + rect.width / 2;
708
+ const centerY = rect.top + rect.height / 2;
709
+ const val = calculateSliderValueFromPoint(clientX - centerX, clientY - centerY, getCenterAngle(effectivePosition), 30, effectivePosition);
710
+ handleSliderChange(val);
711
+ };
712
+ const updateSliderFromPointerRef = React$1.useRef(updateSliderFromPointer);
713
+ React$1.useEffect(() => {
714
+ updateSliderFromPointerRef.current = updateSliderFromPointer;
715
+ });
716
+ React$1.useEffect(() => {
717
+ if (!isDraggingSlider) return;
718
+ const handlePointerMove = (e) => {
719
+ updateSliderFromPointerRef.current(e.clientX, e.clientY);
720
+ };
721
+ const handlePointerUp = () => {
722
+ setIsDraggingSlider(false);
723
+ };
724
+ window.addEventListener("pointermove", handlePointerMove);
725
+ window.addEventListener("pointerup", handlePointerUp);
726
+ window.addEventListener("pointercancel", handlePointerUp);
727
+ return () => {
728
+ window.removeEventListener("pointermove", handlePointerMove);
729
+ window.removeEventListener("pointerup", handlePointerUp);
730
+ window.removeEventListener("pointercancel", handlePointerUp);
731
+ };
732
+ }, [isDraggingSlider]);
733
+ const handleAlphaPointerDown = (e) => {
734
+ e.preventDefault();
735
+ setIsDraggingAlpha(true);
736
+ updateAlphaFromPointer(e.clientX, e.clientY);
737
+ };
738
+ const updateAlphaFromPointer = (clientX, clientY) => {
739
+ if (!alphaSvgRef.current) return;
740
+ const rect = alphaSvgRef.current.getBoundingClientRect();
741
+ const centerX = rect.left + rect.width / 2;
742
+ const centerY = rect.top + rect.height / 2;
743
+ const dx = clientX - centerX;
744
+ const dy = clientY - centerY;
745
+ const alphaPosition = getOppositePosition(effectivePosition);
746
+ const val = calculateSliderValueFromPoint(dx, dy, getCenterAngle(alphaPosition), 30, alphaPosition === "bottom" ? "left" : "right");
747
+ updateValue({
748
+ ...currentValue,
749
+ alpha: val
750
+ });
751
+ };
752
+ const updateAlphaFromPointerRef = React$1.useRef(updateAlphaFromPointer);
753
+ React$1.useEffect(() => {
754
+ updateAlphaFromPointerRef.current = updateAlphaFromPointer;
755
+ });
756
+ React$1.useEffect(() => {
757
+ if (!isDraggingAlpha) return;
758
+ const handlePointerMove = (e) => {
759
+ updateAlphaFromPointerRef.current(e.clientX, e.clientY);
760
+ };
761
+ const handlePointerUp = () => {
762
+ setIsDraggingAlpha(false);
763
+ };
764
+ window.addEventListener("pointermove", handlePointerMove);
765
+ window.addEventListener("pointerup", handlePointerUp);
766
+ window.addEventListener("pointercancel", handlePointerUp);
767
+ return () => {
768
+ window.removeEventListener("pointermove", handlePointerMove);
769
+ window.removeEventListener("pointerup", handlePointerUp);
770
+ window.removeEventListener("pointercancel", handlePointerUp);
771
+ };
772
+ }, [isDraggingAlpha]);
773
+ const renderPetals = () => {
774
+ const totalLayers = layers.length;
775
+ const items = [];
776
+ for (let layerIdx = 0; layerIdx < totalLayers; layerIdx++) {
777
+ const layerColors = layers[layerIdx];
778
+ const radius = layerRadii[layerIdx];
779
+ const rotation = layerRotations[layerIdx];
780
+ const previousItemsCount = layerPrefixCounts[layerIdx];
781
+ const totalPetals = layerColors.length;
782
+ const baseZ = (totalLayers - layerIdx) * 100;
783
+ let bottomIndex = 0;
784
+ let minDiff = Infinity;
785
+ for (let i = 0; i < totalPetals; i++) {
786
+ const normalizedAngle = ((i / totalPetals * 360 - 90 + rotation) % 360 + 360) % 360;
787
+ const diff = Math.min(Math.abs(normalizedAngle - 90), 360 - Math.abs(normalizedAngle - 90));
788
+ if (diff < minDiff) {
789
+ minDiff = diff;
790
+ bottomIndex = i;
791
+ }
792
+ }
793
+ for (let index = 0; index < totalPetals; index++) {
794
+ const color = layerColors[index];
795
+ const staggerDelay = previousItemsCount * PETAL_STAGGER + index * PETAL_STAGGER;
796
+ const isSelected = currentValue.hue === color.h;
797
+ const createPetalStyle = (clip, zIndexOverride, isInteraction = false) => {
798
+ const radian = (index / totalPetals * 360 - 90 + rotation) * Math.PI / 180;
799
+ let px = Math.cos(radian) * radius;
800
+ let py = Math.sin(radian) * radius;
801
+ const isHovered = hoveredPetal?.layer === layerIdx && hoveredPetal?.index === index;
802
+ if (isExpanded && mousePos && !isHovered && !isInteraction) {
803
+ const dx = px - mousePos.x;
804
+ const dy = py - mousePos.y;
805
+ const dist = Math.sqrt(dx * dx + dy * dy);
806
+ const minDistance = 60;
807
+ if (dist < minDistance) {
808
+ const pushStrength = (1 - dist / minDistance) * 6;
809
+ const pushAngle = Math.atan2(dy, dx);
810
+ px += Math.cos(pushAngle) * pushStrength;
811
+ py += Math.sin(pushAngle) * pushStrength;
812
+ }
813
+ }
814
+ const scale = isHovered && !isInteraction ? 1.1 : 1;
815
+ return {
816
+ backgroundColor: hslaToString(color.h, color.s, color.l, isInteraction ? 0 : 100),
817
+ transform: isExpanded ? `translate(${px}px, ${py}px) scale(${scale})` : "translate(0px, 0px) scale(0)",
818
+ opacity: isExpanded ? 1 : 0,
819
+ filter: isHovered && !isInteraction ? "brightness(1.1)" : "brightness(1)",
820
+ boxShadow: isExpanded && !isInteraction ? isHovered ? "0 4px 12px rgba(0,0,0,0.25)" : "0 2px 6px rgba(0,0,0,0.15)" : "none",
821
+ zIndex: zIndexOverride ?? baseZ + index,
822
+ pointerEvents: isExpanded ? index === bottomIndex ? isInteraction ? "auto" : "none" : "auto" : "none",
823
+ clipPath: clip === "left" ? "polygon(0% -50%, 50% -50%, 50% 150%, 0% 150%)" : clip === "right" ? "polygon(50% -50%, 100% -50%, 100% 150%, 50% 150%)" : void 0,
824
+ transition: `
825
+ transform ${isExpanded && mousePos && !isHovered ? "150ms ease-out" : `${animationDuration}ms ${BLOOM_EASING_CSS} ${isExpanded && !isHovered ? staggerDelay : 0}ms`},
826
+ opacity ${animationDuration}ms ${BLOOM_EASING_CSS} ${isExpanded && !isHovered ? staggerDelay : 0}ms,
827
+ background-color 200ms ease,
828
+ box-shadow 200ms ease,
829
+ filter 200ms ease
830
+ `
831
+ };
832
+ };
833
+ if (index === bottomIndex) {
834
+ const uZ = baseZ - 1;
835
+ const lZ = getPetalZIndex(index, bottomIndex, totalPetals, layerIdx, totalLayers, true, false);
836
+ const rZ = getPetalZIndex(index, bottomIndex, totalPetals, layerIdx, totalLayers, false, true);
837
+ const iZ = baseZ + totalPetals + 20;
838
+ items.push(/* @__PURE__ */ jsx("div", {
839
+ className: "absolute rounded-full pointer-events-none",
840
+ style: {
841
+ width: `${petalSize}px`,
842
+ height: `${petalSize}px`,
843
+ marginLeft: `${-petalSize / 2}px`,
844
+ marginTop: `${-petalSize / 2}px`,
845
+ left: "50%",
846
+ top: "50%",
847
+ ...createPetalStyle(void 0, uZ)
848
+ }
849
+ }, `${layerIdx}-${index}-underlay`), /* @__PURE__ */ jsx("div", {
850
+ className: cn("absolute rounded-full pointer-events-none", isSelected && isExpanded && "ring-2 ring-white ring-offset-2 ring-offset-background"),
851
+ style: {
852
+ width: `${petalSize}px`,
853
+ height: `${petalSize}px`,
854
+ marginLeft: `${-petalSize / 2}px`,
855
+ marginTop: `${-petalSize / 2}px`,
856
+ left: "50%",
857
+ top: "50%",
858
+ ...createPetalStyle("left", lZ)
859
+ }
860
+ }, `${layerIdx}-${index}-left`), /* @__PURE__ */ jsx("div", {
861
+ className: cn("absolute rounded-full pointer-events-none", isSelected && isExpanded && "ring-2 ring-white ring-offset-2 ring-offset-background"),
862
+ style: {
863
+ width: `${petalSize}px`,
864
+ height: `${petalSize}px`,
865
+ marginLeft: `${-petalSize / 2}px`,
866
+ marginTop: `${-petalSize / 2}px`,
867
+ left: "50%",
868
+ top: "50%",
869
+ ...createPetalStyle("right", rZ)
870
+ }
871
+ }, `${layerIdx}-${index}-right`), /* @__PURE__ */ jsx("button", {
872
+ type: "button",
873
+ tabIndex: isExpanded ? 0 : -1,
874
+ onClick: () => handlePetalClick(color, layerIdx),
875
+ onMouseEnter: () => setHoveredPetal({
876
+ layer: layerIdx,
877
+ index
878
+ }),
879
+ onMouseLeave: () => setHoveredPetal(null),
880
+ "aria-label": `Select color hue ${color.h}`,
881
+ className: "absolute rounded-full cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-white",
882
+ style: {
883
+ width: `${petalSize}px`,
884
+ height: `${petalSize}px`,
885
+ marginLeft: `${-petalSize / 2}px`,
886
+ marginTop: `${-petalSize / 2}px`,
887
+ left: "50%",
888
+ top: "50%",
889
+ ...createPetalStyle(void 0, iZ, true)
890
+ }
891
+ }, `${layerIdx}-${index}-interaction`));
892
+ } else items.push(/* @__PURE__ */ jsx("button", {
893
+ type: "button",
894
+ tabIndex: isExpanded ? 0 : -1,
895
+ onClick: () => handlePetalClick(color, layerIdx),
896
+ onMouseEnter: () => setHoveredPetal({
897
+ layer: layerIdx,
898
+ index
899
+ }),
900
+ onMouseLeave: () => setHoveredPetal(null),
901
+ "aria-label": `Select color hue ${color.h}`,
902
+ className: cn("absolute rounded-full cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-white", isSelected && isExpanded && "ring-2 ring-white ring-offset-2 ring-offset-background"),
903
+ style: {
904
+ width: `${petalSize}px`,
905
+ height: `${petalSize}px`,
906
+ marginLeft: `${-petalSize / 2}px`,
907
+ marginTop: `${-petalSize / 2}px`,
908
+ left: "50%",
909
+ top: "50%",
910
+ ...createPetalStyle(void 0, getPetalZIndex(index, bottomIndex, totalPetals, layerIdx, totalLayers))
911
+ }
912
+ }, `${layerIdx}-${index}`));
913
+ }
914
+ }
915
+ return items;
916
+ };
917
+ const renderArcSlider = () => {
918
+ if (!showAlphaSlider) return null;
919
+ const centerAngle = getCenterAngle(effectivePosition);
920
+ const drawStartAngle = centerAngle - 30;
921
+ const drawEndAngle = centerAngle + 30;
922
+ const size = (barRadius + sliderOffset + sliderWidth / 2 + circularBarWidth) * 2 + 20;
923
+ const center = size / 2;
924
+ const arcD = describeArc(center, center, barRadius + sliderOffset, drawStartAngle, drawEndAngle);
925
+ const valStartAngle = effectivePosition === "left" ? drawEndAngle : drawStartAngle;
926
+ const valEndAngle = effectivePosition === "left" ? drawStartAngle : drawEndAngle;
927
+ const gradStart = polarToCartesian(center, center, barRadius + sliderOffset, valStartAngle);
928
+ const gradEnd = polarToCartesian(center, center, barRadius + sliderOffset, valEndAngle);
929
+ const handleAngle = valStartAngle + currentValue.saturation / 100 * (valEndAngle - valStartAngle);
930
+ const handlePos = polarToCartesian(center, center, barRadius + sliderOffset, handleAngle);
931
+ const handleLightness = sliderValueToLightness(currentValue.saturation);
932
+ const handleSaturation = getVisualSaturation(currentValue.saturation, baseSaturation);
933
+ const handleColor = hslToString(currentValue.hue, handleSaturation, handleLightness);
934
+ const gradientColors = calculateArcGradientColors(currentValue.hue, baseSaturation, ARC_GRADIENT_STEPS);
935
+ return /* @__PURE__ */ jsxs("svg", {
936
+ ref: svgRef,
937
+ width: size,
938
+ height: size,
939
+ onPointerDown: handleSliderPointerDown,
940
+ className: "absolute pointer-events-none select-none",
941
+ style: {
942
+ left: "50%",
943
+ top: "50%",
944
+ marginLeft: `${-size / 2}px`,
945
+ marginTop: `${-size / 2}px`,
946
+ zIndex: 50,
947
+ opacity: isExpanded ? 1 : 0,
948
+ transform: isExpanded ? "scale(1)" : "scale(0.8)",
949
+ transition: `opacity ${animationDuration}ms ${BLOOM_EASING_CSS} ${animationDuration / 2}ms, transform ${animationDuration}ms ${BLOOM_EASING_CSS} ${animationDuration / 2}ms`
950
+ },
951
+ children: [
952
+ /* @__PURE__ */ jsx("title", { children: "Saturation & Lightness Arc Slider" }),
953
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("linearGradient", {
954
+ id: `bcp-arc-grad-${currentValue.hue}`,
955
+ gradientUnits: "userSpaceOnUse",
956
+ x1: gradStart.x,
957
+ y1: gradStart.y,
958
+ x2: gradEnd.x,
959
+ y2: gradEnd.y,
960
+ children: gradientColors.map((col, i) => /* @__PURE__ */ jsx("stop", {
961
+ offset: `${i / 10 * 100}%`,
962
+ stopColor: col
963
+ }, `${col}-${i}`))
964
+ }) }),
965
+ /* @__PURE__ */ jsx("path", {
966
+ d: arcD,
967
+ fill: "none",
968
+ stroke: "rgba(0,0,0,0.06)",
969
+ strokeWidth: sliderWidth,
970
+ strokeLinecap: "round"
971
+ }),
972
+ /* @__PURE__ */ jsx("path", {
973
+ d: arcD,
974
+ fill: "none",
975
+ stroke: `url(#bcp-arc-grad-${currentValue.hue})`,
976
+ strokeWidth: sliderWidth,
977
+ strokeLinecap: "round",
978
+ className: cn("touch-none", isExpanded ? "pointer-events-auto cursor-pointer" : "pointer-events-none")
979
+ }),
980
+ /* @__PURE__ */ jsx("circle", {
981
+ cx: handlePos.x,
982
+ cy: handlePos.y,
983
+ r: sliderWidth / 2,
984
+ fill: handleColor,
985
+ stroke: "white",
986
+ strokeWidth: "2",
987
+ className: cn("touch-none active:cursor-grabbing shadow-[0_1px_4px_rgba(0,0,0,0.3)]", isExpanded ? "pointer-events-auto cursor-grab" : "pointer-events-none"),
988
+ style: { transition: isDraggingSlider ? "none" : `cx ${animationDuration / 3}ms ease, cy ${animationDuration / 3}ms ease` }
989
+ })
990
+ ]
991
+ });
992
+ };
993
+ const renderAlphaSlider = () => {
994
+ if (!showOpacitySlider) return null;
995
+ const alphaPosition = getOppositePosition(effectivePosition);
996
+ const centerAngle = getCenterAngle(alphaPosition);
997
+ const drawStartAngle = centerAngle - 30;
998
+ const drawEndAngle = centerAngle + 30;
999
+ const size = (barRadius + sliderOffset + sliderWidth / 2 + circularBarWidth) * 2 + 20;
1000
+ const center = size / 2;
1001
+ const arcD = describeArc(center, center, barRadius + sliderOffset, drawStartAngle, drawEndAngle);
1002
+ const valStartAngle = alphaPosition === "bottom" ? drawEndAngle : drawStartAngle;
1003
+ const valEndAngle = alphaPosition === "bottom" ? drawStartAngle : drawEndAngle;
1004
+ const gradStart = polarToCartesian(center, center, barRadius + sliderOffset, valStartAngle);
1005
+ const gradEnd = polarToCartesian(center, center, barRadius + sliderOffset, valEndAngle);
1006
+ const handleAngle = valStartAngle + currentValue.alpha / 100 * (valEndAngle - valStartAngle);
1007
+ const handlePos = polarToCartesian(center, center, barRadius + sliderOffset, handleAngle);
1008
+ const colorStart = hslaToString(currentValue.hue, visualSaturation, currentLightness, 0);
1009
+ const colorEnd = hslaToString(currentValue.hue, visualSaturation, currentLightness, 100);
1010
+ return /* @__PURE__ */ jsxs("svg", {
1011
+ ref: alphaSvgRef,
1012
+ width: size,
1013
+ height: size,
1014
+ onPointerDown: handleAlphaPointerDown,
1015
+ className: "absolute pointer-events-none select-none",
1016
+ style: {
1017
+ left: "50%",
1018
+ top: "50%",
1019
+ marginLeft: `${-size / 2}px`,
1020
+ marginTop: `${-size / 2}px`,
1021
+ zIndex: 51,
1022
+ opacity: isExpanded ? 1 : 0,
1023
+ transform: isExpanded ? "scale(1)" : "scale(0.8)",
1024
+ transition: `opacity ${animationDuration}ms ${BLOOM_EASING_CSS} ${animationDuration / 2}ms, transform ${animationDuration}ms ${BLOOM_EASING_CSS} ${animationDuration / 2}ms`
1025
+ },
1026
+ children: [
1027
+ /* @__PURE__ */ jsx("title", { children: "Alpha Opacity Arc Slider" }),
1028
+ /* @__PURE__ */ jsxs("defs", { children: [/* @__PURE__ */ jsxs("pattern", {
1029
+ id: "bcp-checkerboard",
1030
+ width: "8",
1031
+ height: "8",
1032
+ patternUnits: "userSpaceOnUse",
1033
+ children: [
1034
+ /* @__PURE__ */ jsx("rect", {
1035
+ width: "8",
1036
+ height: "8",
1037
+ fill: "white"
1038
+ }),
1039
+ /* @__PURE__ */ jsx("rect", {
1040
+ width: "4",
1041
+ height: "4",
1042
+ fill: "#e2e8f0"
1043
+ }),
1044
+ /* @__PURE__ */ jsx("rect", {
1045
+ x: "4",
1046
+ y: "4",
1047
+ width: "4",
1048
+ height: "4",
1049
+ fill: "#e2e8f0"
1050
+ })
1051
+ ]
1052
+ }), /* @__PURE__ */ jsxs("linearGradient", {
1053
+ id: `bcp-alpha-grad-${currentValue.hue}`,
1054
+ gradientUnits: "userSpaceOnUse",
1055
+ x1: gradStart.x,
1056
+ y1: gradStart.y,
1057
+ x2: gradEnd.x,
1058
+ y2: gradEnd.y,
1059
+ children: [/* @__PURE__ */ jsx("stop", {
1060
+ offset: "0%",
1061
+ stopColor: colorStart
1062
+ }), /* @__PURE__ */ jsx("stop", {
1063
+ offset: "100%",
1064
+ stopColor: colorEnd
1065
+ })]
1066
+ })] }),
1067
+ /* @__PURE__ */ jsx("path", {
1068
+ d: arcD,
1069
+ fill: "none",
1070
+ stroke: "url(#bcp-checkerboard)",
1071
+ strokeWidth: sliderWidth,
1072
+ strokeLinecap: "round"
1073
+ }),
1074
+ /* @__PURE__ */ jsx("path", {
1075
+ d: arcD,
1076
+ fill: "none",
1077
+ stroke: `url(#bcp-alpha-grad-${currentValue.hue})`,
1078
+ strokeWidth: sliderWidth,
1079
+ strokeLinecap: "round",
1080
+ className: cn("touch-none", isExpanded ? "pointer-events-auto cursor-pointer" : "pointer-events-none")
1081
+ }),
1082
+ /* @__PURE__ */ jsx("circle", {
1083
+ cx: handlePos.x,
1084
+ cy: handlePos.y,
1085
+ r: sliderWidth / 2,
1086
+ fill: colorEnd,
1087
+ stroke: "white",
1088
+ strokeWidth: "2",
1089
+ className: cn("touch-none active:cursor-grabbing shadow-[0_1px_4px_rgba(0,0,0,0.3)]", isExpanded ? "pointer-events-auto cursor-grab" : "pointer-events-none"),
1090
+ style: { transition: isDraggingAlpha ? "none" : `cx ${animationDuration / 3}ms ease, cy ${animationDuration / 3}ms ease` }
1091
+ })
1092
+ ]
1093
+ });
1094
+ };
1095
+ const renderColorBar = () => {
1096
+ const size = (barRadius + circularBarWidth / 2) * 2 + 4;
1097
+ const strokeColor = hslaToString(currentValue.hue, visualSaturation, currentLightness, currentValue.alpha);
1098
+ return /* @__PURE__ */ jsxs("svg", {
1099
+ width: size,
1100
+ height: size,
1101
+ className: "absolute pointer-events-none",
1102
+ style: {
1103
+ left: "50%",
1104
+ top: "50%",
1105
+ marginLeft: `${-size / 2}px`,
1106
+ marginTop: `${-size / 2}px`,
1107
+ zIndex: 5,
1108
+ opacity: isExpanded ? 1 : 0,
1109
+ transform: isExpanded ? "scale(1)" : "scale(0.8)",
1110
+ transition: `opacity ${animationDuration}ms ${BLOOM_EASING_CSS}, transform ${animationDuration}ms ${BLOOM_EASING_CSS}`
1111
+ },
1112
+ children: [
1113
+ /* @__PURE__ */ jsx("title", { children: "Current Color Ring" }),
1114
+ /* @__PURE__ */ jsx("circle", {
1115
+ cx: size / 2,
1116
+ cy: size / 2,
1117
+ r: barRadius,
1118
+ fill: "none",
1119
+ stroke: "rgba(0,0,0,0.06)",
1120
+ strokeWidth: circularBarWidth
1121
+ }),
1122
+ /* @__PURE__ */ jsx("circle", {
1123
+ cx: size / 2,
1124
+ cy: size / 2,
1125
+ r: barRadius,
1126
+ fill: "none",
1127
+ stroke: strokeColor,
1128
+ strokeWidth: circularBarWidth
1129
+ })
1130
+ ]
1131
+ });
1132
+ };
1133
+ if (!mounted) {
1134
+ const size = collapsible && !initialExpanded ? coreSize : containerSize;
1135
+ const initialH = defaultValue?.hue ?? DEFAULT_VALUE.hue;
1136
+ const initialS = defaultValue?.saturation ?? DEFAULT_VALUE.saturation;
1137
+ const initialBgColor = `hsla(${initialH}, ${initialS}%, ${defaultValue?.lightness ?? sliderValueToLightness(initialS)}%, ${(defaultValue?.alpha ?? DEFAULT_VALUE.alpha) / 100})`;
1138
+ return /* @__PURE__ */ jsx("div", {
1139
+ ref: rootRef,
1140
+ role: "group",
1141
+ "aria-label": "Color picker",
1142
+ className: cn("relative inline-flex items-center justify-center select-none", className),
1143
+ style: {
1144
+ width: `${size}px`,
1145
+ height: `${size}px`
1146
+ },
1147
+ children: /* @__PURE__ */ jsx("div", {
1148
+ className: "relative rounded-full border border-black/5 dark:border-white/10",
1149
+ style: {
1150
+ width: `${coreSize}px`,
1151
+ height: `${coreSize}px`,
1152
+ backgroundColor: initialBgColor
1153
+ }
1154
+ })
1155
+ });
1156
+ }
1157
+ return /* @__PURE__ */ jsx("div", {
1158
+ ref: rootRef,
1159
+ role: "group",
1160
+ "aria-label": "Color picker",
1161
+ ...props,
1162
+ onMouseEnter: handleMouseEnter,
1163
+ onMouseMove: handleMouseMove,
1164
+ onMouseLeave: handleMouseLeave,
1165
+ className: cn("relative inline-flex items-center justify-center select-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", className),
1166
+ style: {
1167
+ width: isExpanded ? `${containerSize}px` : `${coreSize}px`,
1168
+ height: isExpanded ? `${containerSize}px` : `${coreSize}px`,
1169
+ transition: `width ${animationDuration}ms ${BLOOM_EASING_CSS}, height ${animationDuration}ms ${BLOOM_EASING_CSS}`
1170
+ },
1171
+ children: /* @__PURE__ */ jsxs("div", {
1172
+ className: "absolute flex items-center justify-center",
1173
+ style: {
1174
+ width: isExpanded ? `${containerSize}px` : `${coreSize}px`,
1175
+ height: isExpanded ? `${containerSize}px` : `${coreSize}px`,
1176
+ transform: `translate(calc(-50% + ${shiftOffset.x}px), calc(-50% + ${shiftOffset.y}px))`,
1177
+ transition: `width ${animationDuration}ms ${BLOOM_EASING_CSS}, height ${animationDuration}ms ${BLOOM_EASING_CSS}, transform ${animationDuration}ms ${BLOOM_EASING_CSS}`,
1178
+ left: "50%",
1179
+ top: "50%",
1180
+ zIndex: isExpanded ? 50 : 0
1181
+ },
1182
+ children: [
1183
+ renderColorBar(),
1184
+ renderPetals(),
1185
+ renderArcSlider(),
1186
+ renderAlphaSlider(),
1187
+ /* @__PURE__ */ jsx("button", {
1188
+ type: "button",
1189
+ disabled,
1190
+ onClick: handleCoreClick,
1191
+ onMouseEnter: () => setIsHoveringCore(true),
1192
+ onMouseLeave: () => setIsHoveringCore(false),
1193
+ "aria-label": isExpanded && hasEyeDropper ? "Pick color from screen" : `Color picker${isExpanded ? ", expanded" : ""}`,
1194
+ "aria-expanded": isExpanded,
1195
+ className: cn("relative rounded-full cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:opacity-64 disabled:cursor-not-allowed border border-black/5 dark:border-white/10 flex items-center justify-center text-white"),
1196
+ style: {
1197
+ width: `${coreSize}px`,
1198
+ height: `${coreSize}px`,
1199
+ backgroundColor: coreColorString,
1200
+ transform: isExpanded ? "scale(1)" : isHoveringCore ? "scale(1.08)" : "scale(1)",
1201
+ boxShadow: isExpanded ? "0 0 0 2px rgba(0,0,0,0.1), 0 4px 12px rgba(0,0,0,0.15)" : "0 2px 8px rgba(0,0,0,0.15)",
1202
+ transition: `transform ${animationDuration}ms ${BLOOM_EASING_CSS}, box-shadow ${animationDuration}ms ${BLOOM_EASING_CSS}, background-color 200ms ease`,
1203
+ zIndex: 1e3
1204
+ },
1205
+ children: isExpanded && hasEyeDropper && /* @__PURE__ */ jsx(Dropper, {
1206
+ className: "size-4 shrink-0 transition-opacity duration-200",
1207
+ style: { color: currentLightness > 70 ? "rgba(0,0,0,0.6)" : "white" }
1208
+ })
1209
+ })
1210
+ ]
1211
+ })
1212
+ });
1213
+ }
1214
+ function ColorPicker({ value, defaultValue, colors, onChange, onCollapse, disabled = false, openOnHover = false, initialExpanded = true, animationDuration = 300, showAlphaSlider = true, coreSize = 36, petalSize = 32, showCoreColor = true, sliderPosition, adaptivePositioning = true, circularBarWidth = BAR_WIDTH, sliderWidth = BAR_WIDTH, sliderOffset = SLIDER_OFFSET, collapsible = false, darkMode, className, ref, ...props }) {
1215
+ const [colorMode, setColorMode] = React$1.useState("HEX");
1216
+ const [internalPickerVal, setInternalPickerVal] = React$1.useState(defaultValue ?? {
1217
+ hue: 210,
1218
+ saturation: 50,
1219
+ alpha: 100,
1220
+ layer: "outer"
1221
+ });
1222
+ const currentValue = value ?? internalPickerVal;
1223
+ const normalizedColors = React$1.useMemo(() => {
1224
+ return colors && colors.length > 0 ? colors.map(parseColor) : DEFAULT_COLORS;
1225
+ }, [colors]);
1226
+ const baseSaturation = React$1.useMemo(() => {
1227
+ if (currentValue.originalSaturation !== void 0) return currentValue.originalSaturation;
1228
+ return normalizedColors.find((c) => c.h === currentValue.hue)?.s ?? 70;
1229
+ }, [
1230
+ normalizedColors,
1231
+ currentValue.hue,
1232
+ currentValue.originalSaturation
1233
+ ]);
1234
+ const currentLightness = React$1.useMemo(() => {
1235
+ return currentValue.lightness ?? sliderValueToLightness(currentValue.saturation);
1236
+ }, [currentValue.lightness, currentValue.saturation]);
1237
+ const visualSaturation = React$1.useMemo(() => {
1238
+ return getVisualSaturation(currentValue.saturation, baseSaturation);
1239
+ }, [currentValue.saturation, baseSaturation]);
1240
+ const parsedOutput = React$1.useMemo(() => {
1241
+ return createColorOutput(currentValue.hue, currentValue.saturation, visualSaturation, baseSaturation, currentLightness, currentValue.alpha, currentValue.layer);
1242
+ }, [
1243
+ currentValue,
1244
+ visualSaturation,
1245
+ baseSaturation,
1246
+ currentLightness
1247
+ ]);
1248
+ const [hexInput, setHexInput] = React$1.useState(parsedOutput.hex.toUpperCase());
1249
+ const [rgbaInputs, setRgbaInputs] = React$1.useState({
1250
+ r: String(parsedOutput.r),
1251
+ g: String(parsedOutput.g),
1252
+ b: String(parsedOutput.b),
1253
+ a: String(parsedOutput.alpha === 100 ? 1 : (parsedOutput.alpha / 100).toFixed(2))
1254
+ });
1255
+ const [hslaInputs, setHslaInputs] = React$1.useState({
1256
+ h: String(Math.round(parsedOutput.hue)),
1257
+ s: String(Math.round(parsedOutput.saturation)),
1258
+ l: String(Math.round(parsedOutput.lightness ?? 50)),
1259
+ a: String(parsedOutput.alpha === 100 ? 1 : (parsedOutput.alpha / 100).toFixed(2))
1260
+ });
1261
+ React$1.useEffect(() => {
1262
+ setHexInput(parsedOutput.hex.toUpperCase());
1263
+ setRgbaInputs({
1264
+ r: String(parsedOutput.r),
1265
+ g: String(parsedOutput.g),
1266
+ b: String(parsedOutput.b),
1267
+ a: String(parsedOutput.alpha === 100 ? 1 : (parsedOutput.alpha / 100).toFixed(2))
1268
+ });
1269
+ setHslaInputs({
1270
+ h: String(Math.round(parsedOutput.hue)),
1271
+ s: String(Math.round(parsedOutput.saturation)),
1272
+ l: String(Math.round(parsedOutput.lightness ?? 50)),
1273
+ a: String(parsedOutput.alpha === 100 ? 1 : (parsedOutput.alpha / 100).toFixed(2))
1274
+ });
1275
+ }, [parsedOutput]);
1276
+ const updateColor = (nextVal) => {
1277
+ if (!value) setInternalPickerVal(nextVal);
1278
+ if (onChange) {
1279
+ const newBaseSaturation = nextVal.originalSaturation ?? normalizedColors.find((c) => c.h === nextVal.hue)?.s ?? 70;
1280
+ const nextLightness = nextVal.lightness ?? sliderValueToLightness(nextVal.saturation);
1281
+ const nextVisualSat = getVisualSaturation(nextVal.saturation, newBaseSaturation);
1282
+ const { r, g, b } = hslToRgb(nextVal.hue, nextVisualSat, nextLightness);
1283
+ onChange({
1284
+ ...nextVal,
1285
+ originalSaturation: newBaseSaturation,
1286
+ lightness: nextLightness,
1287
+ hex: hslToHex(nextVal.hue, nextVisualSat, nextLightness),
1288
+ hsl: hslToString(nextVal.hue, nextVisualSat, nextLightness),
1289
+ hsla: hslaToString(nextVal.hue, nextVisualSat, nextLightness, nextVal.alpha),
1290
+ rgb: `rgb(${r}, ${g}, ${b})`,
1291
+ rgba: rgbaToString(r, g, b, nextVal.alpha),
1292
+ r,
1293
+ g,
1294
+ b
1295
+ });
1296
+ }
1297
+ };
1298
+ const handleRadialPickerChange = (color) => {
1299
+ updateColor({
1300
+ hue: color.hue,
1301
+ saturation: color.saturation,
1302
+ lightness: color.lightness,
1303
+ originalSaturation: color.originalSaturation,
1304
+ alpha: currentValue.alpha,
1305
+ layer: color.layer
1306
+ });
1307
+ };
1308
+ const handleAlphaChange = (nextAlpha) => {
1309
+ updateColor({
1310
+ ...currentValue,
1311
+ alpha: nextAlpha
1312
+ });
1313
+ };
1314
+ const toggleMode = () => {
1315
+ setColorMode((prev) => {
1316
+ if (prev === "HEX") return "RGBA";
1317
+ if (prev === "RGBA") return "HSLA";
1318
+ return "HEX";
1319
+ });
1320
+ };
1321
+ const handleHexInputChange = (val) => {
1322
+ setHexInput(val);
1323
+ if (/^#[0-9A-F]{6}$/i.test(val) || /^[0-9A-F]{6}$/i.test(val)) {
1324
+ const hsl = hexToHsl(val.startsWith("#") ? val : `#${val}`);
1325
+ updateColor({
1326
+ hue: hsl.h,
1327
+ saturation: lightnessToSliderValue(hsl.l),
1328
+ lightness: hsl.l,
1329
+ originalSaturation: hsl.s,
1330
+ alpha: currentValue.alpha,
1331
+ layer: currentValue.layer
1332
+ });
1333
+ }
1334
+ };
1335
+ const handleRgbaInputChange = (key, val) => {
1336
+ const nextRgba = {
1337
+ ...rgbaInputs,
1338
+ [key]: val
1339
+ };
1340
+ setRgbaInputs(nextRgba);
1341
+ const r = parseInt(nextRgba.r, 10);
1342
+ const g = parseInt(nextRgba.g, 10);
1343
+ const b = parseInt(nextRgba.b, 10);
1344
+ const a = parseFloat(nextRgba.a);
1345
+ if (!Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b)) {
1346
+ const hsl = rgbToHsl(r, g, b);
1347
+ updateColor({
1348
+ hue: hsl.h,
1349
+ saturation: lightnessToSliderValue(hsl.l),
1350
+ lightness: hsl.l,
1351
+ originalSaturation: hsl.s,
1352
+ alpha: Number.isNaN(a) ? currentValue.alpha : Math.max(0, Math.min(100, a * 100)),
1353
+ layer: currentValue.layer
1354
+ });
1355
+ }
1356
+ };
1357
+ const handleHslaInputChange = (key, val) => {
1358
+ const nextHsla = {
1359
+ ...hslaInputs,
1360
+ [key]: val
1361
+ };
1362
+ setHslaInputs(nextHsla);
1363
+ const h = parseInt(nextHsla.h, 10);
1364
+ const s = parseInt(nextHsla.s, 10);
1365
+ const l = parseInt(nextHsla.l, 10);
1366
+ const a = parseFloat(nextHsla.a);
1367
+ if (!Number.isNaN(h) && !Number.isNaN(s) && !Number.isNaN(l)) updateColor({
1368
+ hue: Math.max(0, Math.min(360, h)),
1369
+ saturation: Math.max(0, Math.min(100, s)),
1370
+ lightness: Math.max(0, Math.min(100, l)),
1371
+ originalSaturation: baseSaturation,
1372
+ alpha: Number.isNaN(a) ? currentValue.alpha : Math.max(0, Math.min(100, a * 100)),
1373
+ layer: currentValue.layer
1374
+ });
1375
+ };
1376
+ return /* @__PURE__ */ jsxs("div", {
1377
+ ref,
1378
+ "data-slot": "color-picker",
1379
+ ...props,
1380
+ className: cn("inline-flex flex-col rounded-2xl border bg-card text-card-foreground shadow-xs/5 overflow-hidden w-[250px] select-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", darkMode && "dark", className),
1381
+ children: [/* @__PURE__ */ jsx("div", {
1382
+ className: "flex justify-center items-center pt-10 pb-[calc(--spacing(10)-1px)] px-4 bg-muted/20 border-b",
1383
+ children: /* @__PURE__ */ jsx(BlossomColorPicker, {
1384
+ value: currentValue,
1385
+ colors,
1386
+ onChange: handleRadialPickerChange,
1387
+ onCollapse,
1388
+ disabled,
1389
+ openOnHover,
1390
+ initialExpanded,
1391
+ animationDuration,
1392
+ showAlphaSlider,
1393
+ showOpacitySlider: false,
1394
+ coreSize,
1395
+ petalSize,
1396
+ showCoreColor,
1397
+ sliderPosition,
1398
+ adaptivePositioning,
1399
+ circularBarWidth,
1400
+ sliderWidth,
1401
+ sliderOffset,
1402
+ collapsible
1403
+ })
1404
+ }), /* @__PURE__ */ jsxs("div", {
1405
+ className: "p-4 flex flex-col gap-4",
1406
+ children: [/* @__PURE__ */ jsxs("div", {
1407
+ className: "flex items-center gap-3",
1408
+ children: [/* @__PURE__ */ jsxs("div", {
1409
+ className: "relative size-9 rounded-full border border-black/5 dark:border-white/10 overflow-hidden shrink-0",
1410
+ children: [/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[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%)] bg-size-[8px_8px] bg-position-[0_0,0_4px,4px_-4px,-4px_0px] bg-white opacity-40" }), /* @__PURE__ */ jsx("div", {
1411
+ className: "absolute inset-0 rounded-full shadow-inner",
1412
+ style: { backgroundColor: parsedOutput.rgba }
1413
+ })]
1414
+ }), /* @__PURE__ */ jsxs("div", {
1415
+ className: "relative flex-1 h-3 flex items-center",
1416
+ children: [
1417
+ /* @__PURE__ */ jsxs("div", {
1418
+ className: "relative w-full h-2.5 rounded-full border border-black/5 overflow-hidden",
1419
+ children: [/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[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%)] bg-size-[8px_8px] bg-position-[0_0,0_4px,4px_-4px,-4px_0px] bg-white opacity-40" }), /* @__PURE__ */ jsx("div", {
1420
+ className: "absolute inset-0",
1421
+ style: { background: `linear-gradient(to right, rgba(${parsedOutput.r}, ${parsedOutput.g}, ${parsedOutput.b}, 0), rgb(${parsedOutput.r}, ${parsedOutput.g}, ${parsedOutput.b}))` }
1422
+ })]
1423
+ }),
1424
+ /* @__PURE__ */ jsx("div", {
1425
+ className: "absolute size-3.5 -ml-1.75 bg-card border border-input shadow-xs/5 rounded-full pointer-events-none top-1/2 -translate-y-1/2",
1426
+ style: { left: `${currentValue.alpha}%` }
1427
+ }),
1428
+ /* @__PURE__ */ jsx("input", {
1429
+ type: "range",
1430
+ "aria-label": "Opacity",
1431
+ min: 0,
1432
+ max: 100,
1433
+ disabled,
1434
+ value: currentValue.alpha,
1435
+ onChange: (e) => handleAlphaChange(Number(e.target.value)),
1436
+ className: "absolute inset-0 opacity-0 cursor-pointer w-full h-full disabled:cursor-not-allowed"
1437
+ })
1438
+ ]
1439
+ })]
1440
+ }), /* @__PURE__ */ jsxs("div", {
1441
+ className: "flex gap-2 items-start",
1442
+ children: [/* @__PURE__ */ jsxs("div", {
1443
+ className: "flex-1 flex gap-1.5 min-w-0",
1444
+ children: [
1445
+ colorMode === "HEX" && /* @__PURE__ */ jsxs("div", {
1446
+ className: "flex-1 flex flex-col items-center gap-1",
1447
+ children: [/* @__PURE__ */ jsx("input", {
1448
+ type: "text",
1449
+ "aria-label": "Hex color",
1450
+ disabled,
1451
+ value: hexInput,
1452
+ onChange: (e) => handleHexInputChange(e.target.value),
1453
+ className: "w-full h-7 rounded-md border border-input bg-background/50 px-[calc(--spacing(2)-1px)] py-[calc(--spacing(1)-1px)] text-center font-mono text-xs uppercase shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1454
+ }), /* @__PURE__ */ jsx("span", {
1455
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1456
+ children: "Hex"
1457
+ })]
1458
+ }),
1459
+ colorMode === "RGBA" && /* @__PURE__ */ jsxs(Fragment, { children: [
1460
+ /* @__PURE__ */ jsxs("div", {
1461
+ className: "flex-1 flex flex-col items-center gap-1",
1462
+ children: [/* @__PURE__ */ jsx("input", {
1463
+ type: "text",
1464
+ "aria-label": "Red",
1465
+ disabled,
1466
+ value: rgbaInputs.r,
1467
+ onChange: (e) => handleRgbaInputChange("r", e.target.value),
1468
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1469
+ }), /* @__PURE__ */ jsx("span", {
1470
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1471
+ children: "R"
1472
+ })]
1473
+ }),
1474
+ /* @__PURE__ */ jsxs("div", {
1475
+ className: "flex-1 flex flex-col items-center gap-1",
1476
+ children: [/* @__PURE__ */ jsx("input", {
1477
+ type: "text",
1478
+ "aria-label": "Green",
1479
+ disabled,
1480
+ value: rgbaInputs.g,
1481
+ onChange: (e) => handleRgbaInputChange("g", e.target.value),
1482
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1483
+ }), /* @__PURE__ */ jsx("span", {
1484
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1485
+ children: "G"
1486
+ })]
1487
+ }),
1488
+ /* @__PURE__ */ jsxs("div", {
1489
+ className: "flex-1 flex flex-col items-center gap-1",
1490
+ children: [/* @__PURE__ */ jsx("input", {
1491
+ type: "text",
1492
+ "aria-label": "Blue",
1493
+ disabled,
1494
+ value: rgbaInputs.b,
1495
+ onChange: (e) => handleRgbaInputChange("b", e.target.value),
1496
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1497
+ }), /* @__PURE__ */ jsx("span", {
1498
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1499
+ children: "B"
1500
+ })]
1501
+ }),
1502
+ /* @__PURE__ */ jsxs("div", {
1503
+ className: "flex-1 flex flex-col items-center gap-1",
1504
+ children: [/* @__PURE__ */ jsx("input", {
1505
+ type: "text",
1506
+ "aria-label": "Alpha",
1507
+ disabled,
1508
+ value: rgbaInputs.a,
1509
+ onChange: (e) => handleRgbaInputChange("a", e.target.value),
1510
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1511
+ }), /* @__PURE__ */ jsx("span", {
1512
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1513
+ children: "A"
1514
+ })]
1515
+ })
1516
+ ] }),
1517
+ colorMode === "HSLA" && /* @__PURE__ */ jsxs(Fragment, { children: [
1518
+ /* @__PURE__ */ jsxs("div", {
1519
+ className: "flex-1 flex flex-col items-center gap-1",
1520
+ children: [/* @__PURE__ */ jsx("input", {
1521
+ type: "text",
1522
+ "aria-label": "Hue",
1523
+ disabled,
1524
+ value: hslaInputs.h,
1525
+ onChange: (e) => handleHslaInputChange("h", e.target.value),
1526
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1527
+ }), /* @__PURE__ */ jsx("span", {
1528
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1529
+ children: "H"
1530
+ })]
1531
+ }),
1532
+ /* @__PURE__ */ jsxs("div", {
1533
+ className: "flex-1 flex flex-col items-center gap-1",
1534
+ children: [/* @__PURE__ */ jsx("input", {
1535
+ type: "text",
1536
+ "aria-label": "Saturation",
1537
+ disabled,
1538
+ value: hslaInputs.s,
1539
+ onChange: (e) => handleHslaInputChange("s", e.target.value),
1540
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1541
+ }), /* @__PURE__ */ jsx("span", {
1542
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1543
+ children: "S"
1544
+ })]
1545
+ }),
1546
+ /* @__PURE__ */ jsxs("div", {
1547
+ className: "flex-1 flex flex-col items-center gap-1",
1548
+ children: [/* @__PURE__ */ jsx("input", {
1549
+ type: "text",
1550
+ "aria-label": "Lightness",
1551
+ disabled,
1552
+ value: hslaInputs.l,
1553
+ onChange: (e) => handleHslaInputChange("l", e.target.value),
1554
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1555
+ }), /* @__PURE__ */ jsx("span", {
1556
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1557
+ children: "L"
1558
+ })]
1559
+ }),
1560
+ /* @__PURE__ */ jsxs("div", {
1561
+ className: "flex-1 flex flex-col items-center gap-1",
1562
+ children: [/* @__PURE__ */ jsx("input", {
1563
+ type: "text",
1564
+ "aria-label": "Alpha",
1565
+ disabled,
1566
+ value: hslaInputs.a,
1567
+ onChange: (e) => handleHslaInputChange("a", e.target.value),
1568
+ className: "w-full h-7 rounded-md border border-input bg-background/50 py-[calc(--spacing(1)-1px)] text-center font-mono text-xs shadow-2xs outline-none focus:border-primary/40 focus:ring-1 focus:ring-primary/20 disabled:opacity-64"
1569
+ }), /* @__PURE__ */ jsx("span", {
1570
+ className: "text-[10px] text-muted-foreground font-medium uppercase tracking-wider",
1571
+ children: "A"
1572
+ })]
1573
+ })
1574
+ ] })
1575
+ ]
1576
+ }), /* @__PURE__ */ jsx("button", {
1577
+ type: "button",
1578
+ disabled,
1579
+ onClick: toggleMode,
1580
+ "aria-label": "Switch color format",
1581
+ className: "relative flex items-center justify-center h-7 px-[calc(--spacing(2)-1px)] rounded-md border border-input bg-background/30 hover:bg-muted/70 active:bg-muted/90 cursor-pointer text-muted-foreground transition-colors disabled:opacity-64 disabled:cursor-not-allowed shadow-2xs focus:outline-none focus-visible:ring-1 focus-visible:ring-primary/40 pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11",
1582
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5" })
1583
+ })]
1584
+ })]
1585
+ })]
1586
+ });
1587
+ }
1588
+ //#endregion
1589
+ export { BlossomColorPicker, ColorPicker, DEFAULT_COLORS, INNER_COLORS, OUTER_COLORS, calculateArcGradientColors, calculateBarRadius, calculateContainerSize, calculateLayerRadii, calculateLayerRotations, calculateSliderValueFromPoint, computeAdaptivePosition, createColorOutput, describeArc, getCenterAngle, getOppositePosition, getPetalZIndex, getVisualSaturation, hexToHsl, hslToHex, hslToRgb, hslToString, hslaToString, lightnessToSliderValue, organizeColorsIntoLayers, parseColor, polarToCartesian, rgbToHsl, rgbaToString, sliderValueToLightness };