@fab1o978/react-ui 0.1.8 → 0.2.1

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 (35) hide show
  1. package/dist/components/Badge/index.d.cts +3 -3
  2. package/dist/components/Badge/index.d.ts +3 -3
  3. package/dist/components/Button/index.d.cts +3 -3
  4. package/dist/components/Button/index.d.ts +3 -3
  5. package/dist/components/ColorPicker/index.d.cts +2 -2
  6. package/dist/components/ColorPicker/index.d.ts +2 -2
  7. package/dist/components/ColorWheel/index.cjs +673 -0
  8. package/dist/components/ColorWheel/index.cjs.map +1 -0
  9. package/dist/components/ColorWheel/index.css +493 -0
  10. package/dist/components/ColorWheel/index.css.map +1 -0
  11. package/dist/components/ColorWheel/index.d.cts +49 -0
  12. package/dist/components/ColorWheel/index.d.ts +49 -0
  13. package/dist/components/ColorWheel/index.js +671 -0
  14. package/dist/components/ColorWheel/index.js.map +1 -0
  15. package/dist/components/Input/index.d.cts +5 -5
  16. package/dist/components/Input/index.d.ts +5 -5
  17. package/dist/components/RainCanvas/index.d.cts +4 -4
  18. package/dist/components/RainCanvas/index.d.ts +4 -4
  19. package/dist/components/RichTextEditor/index.d.cts +6 -6
  20. package/dist/components/RichTextEditor/index.d.ts +6 -6
  21. package/dist/components/SliderControl/index.d.cts +4 -4
  22. package/dist/components/SliderControl/index.d.ts +4 -4
  23. package/dist/components/SlidingCounter/index.d.cts +2 -2
  24. package/dist/components/SlidingCounter/index.d.ts +2 -2
  25. package/dist/components/Timeline/index.d.cts +3 -3
  26. package/dist/components/Timeline/index.d.ts +3 -3
  27. package/dist/index.cjs +590 -0
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.css +493 -0
  30. package/dist/index.css.map +1 -1
  31. package/dist/index.d.cts +1 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.js +591 -2
  34. package/dist/index.js.map +1 -1
  35. package/package.json +1 -1
@@ -0,0 +1,671 @@
1
+ import { useMemo, useState, useRef, useEffect } from 'react';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+
4
+ // src/components/ColorWheel/ColorWheel.tsx
5
+
6
+ // src/components/ColorWheel/ColorWheel.module.scss
7
+ var ColorWheel_module_default = {
8
+ root: "ColorWheel_module_root2",
9
+ recents: "ColorWheel_module_recents2",
10
+ chipWrap: "ColorWheel_module_chipWrap2",
11
+ chip: "ColorWheel_module_chip2",
12
+ chipRemove: "ColorWheel_module_chipRemove2",
13
+ picker: "ColorWheel_module_picker2",
14
+ glow: "ColorWheel_module_glow2",
15
+ modeToggle: "ColorWheel_module_modeToggle2",
16
+ modePill: "ColorWheel_module_modePill2",
17
+ modeButton: "ColorWheel_module_modeButton2",
18
+ active: "ColorWheel_module_active2",
19
+ stage: "ColorWheel_module_stage2",
20
+ stageShadow: "ColorWheel_module_stageShadow2",
21
+ ring: "ColorWheel_module_ring2",
22
+ hueHandlePivot: "ColorWheel_module_hueHandlePivot2",
23
+ hueHandle: "ColorWheel_module_hueHandle2",
24
+ alphaArcShadowWrap: "ColorWheel_module_alphaArcShadowWrap2",
25
+ alphaArcShadow: "ColorWheel_module_alphaArcShadow2",
26
+ alphaArc: "ColorWheel_module_alphaArc2",
27
+ alphaArcFill: "ColorWheel_module_alphaArcFill2",
28
+ alphaArcCap: "ColorWheel_module_alphaArcCap2",
29
+ alphaArcCapStart: "ColorWheel_module_alphaArcCapStart2",
30
+ alphaArcCapEnd: "ColorWheel_module_alphaArcCapEnd2",
31
+ alphaArcHandle: "ColorWheel_module_alphaArcHandle2",
32
+ currentDisc: "ColorWheel_module_currentDisc2",
33
+ discFill: "ColorWheel_module_discFill2",
34
+ currentHex: "ColorWheel_module_currentHex2",
35
+ currentHexInput: "ColorWheel_module_currentHexInput2",
36
+ copied: "ColorWheel_module_copied2",
37
+ discBadge: "ColorWheel_module_discBadge2",
38
+ discBadgeTop: "ColorWheel_module_discBadgeTop2",
39
+ pulse: "ColorWheel_module_pulse2",
40
+ discBadgeBottom: "ColorWheel_module_discBadgeBottom2"
41
+ };
42
+ function usePointerDrag(ref, onMove, onEnd, onDraggingChange) {
43
+ const onMoveRef = useRef(onMove);
44
+ onMoveRef.current = onMove;
45
+ const onEndRef = useRef(onEnd);
46
+ onEndRef.current = onEnd;
47
+ const onDraggingChangeRef = useRef(onDraggingChange);
48
+ onDraggingChangeRef.current = onDraggingChange;
49
+ useEffect(() => {
50
+ const el = ref.current;
51
+ if (!el) return;
52
+ function pointerPos(e) {
53
+ return { x: e.clientX, y: e.clientY };
54
+ }
55
+ function move(e) {
56
+ onMoveRef.current(pointerPos(e));
57
+ }
58
+ function up() {
59
+ onDraggingChangeRef.current?.(false);
60
+ window.removeEventListener("pointermove", move);
61
+ window.removeEventListener("pointerup", up);
62
+ onEndRef.current?.();
63
+ }
64
+ function down(e) {
65
+ const pe = e;
66
+ pe.preventDefault();
67
+ pe.stopPropagation();
68
+ onDraggingChangeRef.current?.(true);
69
+ onMoveRef.current(pointerPos(pe));
70
+ window.addEventListener("pointermove", move);
71
+ window.addEventListener("pointerup", up);
72
+ }
73
+ el.addEventListener("pointerdown", down);
74
+ return () => {
75
+ el.removeEventListener("pointerdown", down);
76
+ window.removeEventListener("pointermove", move);
77
+ window.removeEventListener("pointerup", up);
78
+ };
79
+ }, [ref]);
80
+ }
81
+ function useUnwrappedAngle(targetDeg) {
82
+ const continuousRef = useRef(targetDeg);
83
+ const targetMod = (targetDeg % 360 + 360) % 360;
84
+ const currentMod = (continuousRef.current % 360 + 360) % 360;
85
+ let delta = targetMod - currentMod;
86
+ if (delta > 180) delta -= 360;
87
+ else if (delta < -180) delta += 360;
88
+ continuousRef.current += delta;
89
+ return continuousRef.current;
90
+ }
91
+
92
+ // src/utils/color.ts
93
+ function hexToHsl(hex) {
94
+ const r = parseInt(hex.slice(1, 3), 16) / 255;
95
+ const g = parseInt(hex.slice(3, 5), 16) / 255;
96
+ const b = parseInt(hex.slice(5, 7), 16) / 255;
97
+ const max = Math.max(r, g, b);
98
+ const min = Math.min(r, g, b);
99
+ const l = (max + min) / 2;
100
+ let h = 0;
101
+ let s = 0;
102
+ if (max !== min) {
103
+ const d = max - min;
104
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
105
+ switch (max) {
106
+ case r:
107
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
108
+ break;
109
+ case g:
110
+ h = ((b - r) / d + 2) / 6;
111
+ break;
112
+ case b:
113
+ h = ((r - g) / d + 4) / 6;
114
+ break;
115
+ }
116
+ }
117
+ return [h * 360, s * 100, l * 100];
118
+ }
119
+ function hslToHex(h, s, l) {
120
+ const sl = s / 100;
121
+ const ll = l / 100;
122
+ const a = sl * Math.min(ll, 1 - ll);
123
+ const f = (n) => {
124
+ const k = (n + h / 30) % 12;
125
+ const color = ll - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
126
+ return Math.round(255 * color).toString(16).padStart(2, "0");
127
+ };
128
+ return `#${f(0)}${f(8)}${f(4)}`;
129
+ }
130
+ function hslToRgb(h, s, l) {
131
+ const sl = s / 100;
132
+ const ll = l / 100;
133
+ const a = sl * Math.min(ll, 1 - ll);
134
+ const f = (n) => {
135
+ const k = (n + h / 30) % 12;
136
+ return Math.round(255 * (ll - a * Math.max(Math.min(k - 3, 9 - k, 1), -1)));
137
+ };
138
+ return { r: f(0), g: f(8), b: f(4) };
139
+ }
140
+ function hslToRgba(h, s, l, alpha) {
141
+ const { r, g, b } = hslToRgb(h, s, l);
142
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
143
+ }
144
+ function deriveAccent(hex) {
145
+ const [h, s, l] = hexToHsl(hex);
146
+ return {
147
+ base: hex,
148
+ dot: hslToHex(h, s, Math.min(l + 12, 95)),
149
+ track: hex,
150
+ ring: hex,
151
+ glow: hslToRgba(h, s, l, 0.3),
152
+ light: hslToHex(h, Math.max(s - 20, 0), Math.min(l + 45, 96))
153
+ };
154
+ }
155
+ function accentToCssVars(tokens, prefix) {
156
+ return {
157
+ [`--${prefix}-accent`]: tokens.base,
158
+ [`--${prefix}-accent-dot`]: tokens.dot,
159
+ [`--${prefix}-accent-track`]: tokens.track,
160
+ [`--${prefix}-accent-ring`]: tokens.ring,
161
+ [`--${prefix}-accent-glow`]: tokens.glow,
162
+ [`--${prefix}-accent-light`]: tokens.light
163
+ };
164
+ }
165
+
166
+ // src/components/ColorWheel/colorMath.ts
167
+ function hsvToRgb(h, s, v) {
168
+ s /= 100;
169
+ v /= 100;
170
+ const c = v * s;
171
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
172
+ const m = v - c;
173
+ let r, g, b;
174
+ if (h < 60) {
175
+ r = c;
176
+ g = x;
177
+ b = 0;
178
+ } else if (h < 120) {
179
+ r = x;
180
+ g = c;
181
+ b = 0;
182
+ } else if (h < 180) {
183
+ r = 0;
184
+ g = c;
185
+ b = x;
186
+ } else if (h < 240) {
187
+ r = 0;
188
+ g = x;
189
+ b = c;
190
+ } else if (h < 300) {
191
+ r = x;
192
+ g = 0;
193
+ b = c;
194
+ } else {
195
+ r = c;
196
+ g = 0;
197
+ b = x;
198
+ }
199
+ return {
200
+ r: Math.round((r + m) * 255),
201
+ g: Math.round((g + m) * 255),
202
+ b: Math.round((b + m) * 255)
203
+ };
204
+ }
205
+ function rgbToHsv(r, g, b) {
206
+ r /= 255;
207
+ g /= 255;
208
+ b /= 255;
209
+ const max = Math.max(r, g, b);
210
+ const min = Math.min(r, g, b);
211
+ const d = max - min;
212
+ let h = 0;
213
+ if (d !== 0) {
214
+ if (max === r) h = (g - b) / d % 6;
215
+ else if (max === g) h = (b - r) / d + 2;
216
+ else h = (r - g) / d + 4;
217
+ h *= 60;
218
+ if (h < 0) h += 360;
219
+ }
220
+ const s = max === 0 ? 0 : d / max;
221
+ return { h, s: s * 100, v: max * 100 };
222
+ }
223
+ function toHexByte(n) {
224
+ const h = Math.max(0, Math.min(255, Math.round(n))).toString(16);
225
+ return h.length === 1 ? "0" + h : h;
226
+ }
227
+ function rgbToHex(c) {
228
+ return ("#" + toHexByte(c.r) + toHexByte(c.g) + toHexByte(c.b)).toUpperCase();
229
+ }
230
+ function hsvaToHex(hsv, a) {
231
+ const rgb = hsvToRgb(hsv.h, hsv.s, hsv.v);
232
+ let hex = rgbToHex(rgb);
233
+ if (a < 1) hex += toHexByte(Math.round(a * 255));
234
+ return hex;
235
+ }
236
+ function hexToHsva(input) {
237
+ let clean = input.trim().replace(/^#/, "");
238
+ if (/^[0-9a-fA-F]{3}$/.test(clean)) {
239
+ clean = clean.split("").map((ch) => ch + ch).join("");
240
+ }
241
+ if (!/^[0-9a-fA-F]{6}$/.test(clean) && !/^[0-9a-fA-F]{8}$/.test(clean)) return null;
242
+ const r = parseInt(clean.slice(0, 2), 16);
243
+ const g = parseInt(clean.slice(2, 4), 16);
244
+ const b = parseInt(clean.slice(4, 6), 16);
245
+ const a = clean.length === 8 ? parseInt(clean.slice(6, 8), 16) / 255 : 1;
246
+ return { hsv: rgbToHsv(r, g, b), a };
247
+ }
248
+ function clamp(v, min, max) {
249
+ return Math.min(max, Math.max(min, v));
250
+ }
251
+ function round2(n) {
252
+ return Math.round(n * 100) / 100;
253
+ }
254
+ function angleDistance(a, b) {
255
+ const d = Math.abs(a - b) % 360;
256
+ return d > 180 ? 360 - d : d;
257
+ }
258
+ function relativeLuminance(c) {
259
+ return (0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) / 255;
260
+ }
261
+ var RING_SPECTRUM = "conic-gradient(from 180deg, hsl(0 100% 50%) 0%, hsl(60 100% 50%) 16.667%, hsl(120 100% 50%) 33.333%, hsl(180 100% 50%) 50%, hsl(240 100% 50%) 66.667%, hsl(300 100% 50%) 83.333%, hsl(360 100% 50%) 100%)";
262
+ var RING_INNER_FRAC = 0.3382;
263
+ var RING_OUTER_FRAC = 0.5;
264
+ var ARC_A0 = 30;
265
+ var ARC_A1 = 150;
266
+ var ARC_HANDLE_R_FRAC = 152 / 380;
267
+ var PICKER_HEIGHT_WITH_ARC = 265;
268
+ var PICKER_HEIGHT_NO_ARC = 224;
269
+ var MODES_HSV = ["h", "s", "v"];
270
+ var MODES_HSVA = ["h", "s", "v", "a"];
271
+ function ringGradient(mode, hsv) {
272
+ if (mode === "s") {
273
+ const grey = rgbToHex(hsvToRgb(hsv.h, 0, hsv.v));
274
+ const full = rgbToHex(hsvToRgb(hsv.h, 100, hsv.v));
275
+ return `conic-gradient(from 180deg, ${grey} 0deg, ${full} 360deg)`;
276
+ }
277
+ if (mode === "v") {
278
+ const bright = rgbToHex(hsvToRgb(hsv.h, hsv.s, 100));
279
+ return `conic-gradient(from 180deg, #000000 0deg, ${bright} 360deg)`;
280
+ }
281
+ if (mode === "a") {
282
+ const full = rgbToHex(hsvToRgb(hsv.h, hsv.s, hsv.v));
283
+ return `conic-gradient(from 180deg, transparent 0deg, ${full} 360deg)`;
284
+ }
285
+ return RING_SPECTRUM;
286
+ }
287
+ var EMPTY_FAVORITES = [];
288
+ function ColorWheel({
289
+ value,
290
+ onChange,
291
+ favorites = EMPTY_FAVORITES,
292
+ onFavoritesChange,
293
+ maxFavorites = 5,
294
+ showAlphaControl = true,
295
+ alphaMode = "arc",
296
+ theme = "system",
297
+ size = 1,
298
+ accent,
299
+ className
300
+ }) {
301
+ const ringIsFourWay = showAlphaControl && alphaMode === "ring";
302
+ const arcVisible = showAlphaControl && alphaMode === "arc";
303
+ const modes = ringIsFourWay ? MODES_HSVA : MODES_HSV;
304
+ const parsed = useMemo(() => hexToHsva(value), [value]);
305
+ const [hsv, setHsv] = useState(() => parsed?.hsv ?? { h: 0, s: 0, v: 100 });
306
+ const [alpha, setAlpha] = useState(() => parsed?.a ?? 1);
307
+ const [mode, setMode] = useState("h");
308
+ const [dragging, setDragging] = useState(false);
309
+ const [copied, setCopied] = useState(false);
310
+ const [pulseFavorite, setPulseFavorite] = useState(false);
311
+ const [editing, setEditing] = useState(false);
312
+ const [editValue, setEditValue] = useState("");
313
+ const [eyedropperSupported, setEyedropperSupported] = useState(false);
314
+ const accentVars = accent ? accentToCssVars(deriveAccent(accent), "colorwheel") : {};
315
+ const lastEmitted = useRef(value);
316
+ useEffect(() => {
317
+ if (value === lastEmitted.current) return;
318
+ const next = hexToHsva(value);
319
+ if (next) {
320
+ setHsv(next.hsv);
321
+ setAlpha(next.a);
322
+ }
323
+ lastEmitted.current = value;
324
+ }, [value]);
325
+ useEffect(() => {
326
+ setEyedropperSupported(typeof window !== "undefined" && "EyeDropper" in window);
327
+ }, []);
328
+ useEffect(() => {
329
+ if (!ringIsFourWay && mode === "a") setMode("h");
330
+ }, [ringIsFourWay, mode]);
331
+ const stageRef = useRef(null);
332
+ const alphaArcRef = useRef(null);
333
+ const modeToggleRef = useRef(null);
334
+ const hexInputRef = useRef(null);
335
+ function commit(nextHsv, nextAlpha) {
336
+ setHsv(nextHsv);
337
+ setAlpha(nextAlpha);
338
+ const hex = hsvaToHex(nextHsv, nextAlpha);
339
+ lastEmitted.current = hex;
340
+ onChange(hex);
341
+ }
342
+ const rgb = hsvToRgb(hsv.h, hsv.s, hsv.v);
343
+ const solidHex = rgbToHex(rgb);
344
+ const hexString = hsvaToHex(hsv, alpha);
345
+ const luminance = relativeLuminance(rgb);
346
+ const isLight = luminance > 0.58;
347
+ const discText = isLight ? "#1A1913" : "#FFFFFF";
348
+ const badgeBg = isLight ? "rgba(0,0,0,0.02)" : "rgba(255,255,255,0.03)";
349
+ const badgeGrooveDark = isLight ? "rgba(0,0,0,0.2)" : "rgba(0,0,0,0.32)";
350
+ const badgeGrooveLight = isLight ? "rgba(255,255,255,0.35)" : "rgba(255,255,255,0.12)";
351
+ const badgeIcon = isLight ? "rgba(0,0,0,0.72)" : "rgba(255,255,255,0.88)";
352
+ const badgeShadow = {
353
+ background: badgeBg,
354
+ color: badgeIcon,
355
+ boxShadow: `inset 0 1px 1px ${badgeGrooveDark}, inset 0 -1px 1px ${badgeGrooveLight}`
356
+ };
357
+ const ringLogicalAngle = mode === "h" ? hsv.h : mode === "a" ? alpha * 360 : (mode === "s" ? hsv.s : hsv.v) / 100 * 360;
358
+ const ringAngleFromTopDeg = useUnwrappedAngle(180 + ringLogicalAngle);
359
+ const arcLogicalAngle = ARC_A1 - alpha * (ARC_A1 - ARC_A0);
360
+ const arcAngleFromTop = (90 + arcLogicalAngle) * (Math.PI / 180);
361
+ const arcHandleR = ARC_HANDLE_R_FRAC * 380;
362
+ const arcHandleDx = arcHandleR * Math.sin(arcAngleFromTop);
363
+ const arcHandleDy = -arcHandleR * Math.cos(arcAngleFromTop);
364
+ function applyRingAngle(angle) {
365
+ if (mode === "h") commit({ ...hsv, h: angle }, alpha);
366
+ else if (mode === "s") commit({ ...hsv, s: angle / 360 * 100 }, alpha);
367
+ else if (mode === "a") commit(hsv, angle / 360);
368
+ else commit({ ...hsv, v: angle / 360 * 100 }, alpha);
369
+ }
370
+ const dragPrevAngleRef = useRef(null);
371
+ const dragAccumRef = useRef(0);
372
+ usePointerDrag(
373
+ stageRef,
374
+ (pos) => {
375
+ const rect = stageRef.current.getBoundingClientRect();
376
+ const cx = rect.left + rect.width / 2;
377
+ const cy = rect.top + rect.height / 2;
378
+ const dx = pos.x - cx;
379
+ const dy = pos.y - cy;
380
+ const dist = Math.hypot(dx, dy);
381
+ if (dist < rect.width * RING_INNER_FRAC || dist > rect.width * RING_OUTER_FRAC) return;
382
+ let angle = Math.atan2(dy, dx) * (180 / Math.PI) - 90;
383
+ angle = (angle % 360 + 360) % 360;
384
+ if (mode === "h") {
385
+ applyRingAngle(angle);
386
+ return;
387
+ }
388
+ if (dragPrevAngleRef.current === null) {
389
+ dragAccumRef.current = angle;
390
+ } else {
391
+ let delta = angle - dragPrevAngleRef.current;
392
+ if (delta > 180) delta -= 360;
393
+ else if (delta < -180) delta += 360;
394
+ dragAccumRef.current = clamp(dragAccumRef.current + delta, 0, 360);
395
+ }
396
+ dragPrevAngleRef.current = angle;
397
+ applyRingAngle(dragAccumRef.current);
398
+ },
399
+ void 0,
400
+ (dragging2) => {
401
+ if (!dragging2) dragPrevAngleRef.current = null;
402
+ setDragging(dragging2);
403
+ }
404
+ );
405
+ useEffect(() => {
406
+ const el = stageRef.current;
407
+ if (!el) return;
408
+ function onWheel(e) {
409
+ const rect = el.getBoundingClientRect();
410
+ const cx = rect.left + rect.width / 2;
411
+ const cy = rect.top + rect.height / 2;
412
+ const dist = Math.hypot(e.clientX - cx, e.clientY - cy);
413
+ if (dist < rect.width * RING_INNER_FRAC || dist > rect.width * RING_OUTER_FRAC) return;
414
+ e.preventDefault();
415
+ const dir = e.deltaY > 0 ? -1 : 1;
416
+ if (mode === "h") commit({ ...hsv, h: (hsv.h + dir * 4 + 360) % 360 }, alpha);
417
+ else if (mode === "s") commit({ ...hsv, s: clamp(hsv.s + dir * 3, 0, 100) }, alpha);
418
+ else if (mode === "a") commit(hsv, clamp(round2(alpha + dir * 0.03), 0, 1));
419
+ else commit({ ...hsv, v: clamp(hsv.v + dir * 3, 0, 100) }, alpha);
420
+ }
421
+ el.addEventListener("wheel", onWheel, { passive: false });
422
+ return () => el.removeEventListener("wheel", onWheel);
423
+ }, [mode, hsv, alpha]);
424
+ usePointerDrag(
425
+ alphaArcRef,
426
+ (pos) => {
427
+ const rect = alphaArcRef.current.getBoundingClientRect();
428
+ const cx = rect.left + rect.width / 2;
429
+ const cy = rect.top + rect.height / 2;
430
+ let angle = Math.atan2(pos.y - cy, pos.x - cx) * (180 / Math.PI);
431
+ if (angle < 0) angle += 360;
432
+ if (angle < ARC_A0 || angle > ARC_A1) {
433
+ angle = angleDistance(angle, ARC_A0) < angleDistance(angle, ARC_A1) ? ARC_A0 : ARC_A1;
434
+ }
435
+ commit(hsv, round2((ARC_A1 - angle) / (ARC_A1 - ARC_A0)));
436
+ },
437
+ void 0,
438
+ setDragging
439
+ );
440
+ useEffect(() => {
441
+ const el = alphaArcRef.current;
442
+ if (!el) return;
443
+ function onWheel(e) {
444
+ e.preventDefault();
445
+ const dir = e.deltaY > 0 ? -1 : 1;
446
+ commit(hsv, clamp(round2(alpha + dir * 0.05), 0, 1));
447
+ }
448
+ el.addEventListener("wheel", onWheel, { passive: false });
449
+ return () => el.removeEventListener("wheel", onWheel);
450
+ }, [hsv, alpha]);
451
+ useEffect(() => {
452
+ const el = modeToggleRef.current;
453
+ if (!el) return;
454
+ function onWheel(e) {
455
+ e.preventDefault();
456
+ const idx = modes.indexOf(mode);
457
+ const dir = e.deltaY > 0 ? -1 : 1;
458
+ setMode(modes[clamp(idx + dir, 0, modes.length - 1)]);
459
+ }
460
+ el.addEventListener("wheel", onWheel, { passive: false });
461
+ return () => el.removeEventListener("wheel", onWheel);
462
+ }, [mode, modes]);
463
+ function handleDiscClick() {
464
+ const done = () => {
465
+ setCopied(true);
466
+ setTimeout(() => setCopied(false), 900);
467
+ };
468
+ if (navigator.clipboard?.writeText) {
469
+ navigator.clipboard.writeText(hexString).then(done, done);
470
+ } else {
471
+ done();
472
+ }
473
+ }
474
+ function beginEdit(e) {
475
+ e.stopPropagation();
476
+ setEditValue(hexString);
477
+ setEditing(true);
478
+ requestAnimationFrame(() => {
479
+ hexInputRef.current?.focus();
480
+ hexInputRef.current?.setSelectionRange(1, hexString.length);
481
+ });
482
+ }
483
+ function commitEdit(cancelled) {
484
+ if (!cancelled) {
485
+ const next = hexToHsva(editValue);
486
+ if (next) commit(next.hsv, next.a);
487
+ }
488
+ setEditing(false);
489
+ }
490
+ function pickFromScreen() {
491
+ const dropper = new window.EyeDropper();
492
+ dropper.open().then((result) => {
493
+ const next = hexToHsva(result.sRGBHex);
494
+ if (next) commit(next.hsv, next.a);
495
+ }).catch(() => {
496
+ });
497
+ }
498
+ function saveFavorite() {
499
+ const next = [hexString, ...favorites.filter((h) => h !== hexString)].slice(0, maxFavorites);
500
+ onFavoritesChange?.(next);
501
+ setPulseFavorite(false);
502
+ requestAnimationFrame(() => setPulseFavorite(true));
503
+ }
504
+ function applyFavorite(hex) {
505
+ const next = hexToHsva(hex);
506
+ if (next) commit(next.hsv, next.a);
507
+ }
508
+ function removeFavorite(hex) {
509
+ onFavoritesChange?.(favorites.filter((h) => h !== hex));
510
+ }
511
+ return /* @__PURE__ */ jsxs(
512
+ "div",
513
+ {
514
+ className: [ColorWheel_module_default.root, className].filter(Boolean).join(" "),
515
+ "data-theme": theme === "system" ? void 0 : theme,
516
+ "data-dragging": dragging ? "true" : void 0,
517
+ style: {
518
+ ...accentVars,
519
+ ...size !== 1 ? { transform: `scale(${size})`, transformOrigin: "top center" } : void 0
520
+ },
521
+ children: [
522
+ favorites.length > 0 && /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.recents, children: favorites.map((hex, i) => /* @__PURE__ */ jsxs("div", { className: ColorWheel_module_default.chipWrap, style: { animationDelay: `${i * 0.02}s` }, children: [
523
+ /* @__PURE__ */ jsx(
524
+ "button",
525
+ {
526
+ type: "button",
527
+ className: ColorWheel_module_default.chip,
528
+ style: { background: hex.length > 7 ? hex.slice(0, 7) : hex },
529
+ title: hex,
530
+ "aria-label": `Apply color ${hex}`,
531
+ onClick: () => applyFavorite(hex)
532
+ }
533
+ ),
534
+ /* @__PURE__ */ jsx(
535
+ "button",
536
+ {
537
+ type: "button",
538
+ className: ColorWheel_module_default.chipRemove,
539
+ "aria-label": `Remove ${hex} from favorites`,
540
+ onClick: (e) => {
541
+ e.stopPropagation();
542
+ removeFavorite(hex);
543
+ },
544
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 3, strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M18 6L6 18" }) })
545
+ }
546
+ )
547
+ ] }, hex + i)) }),
548
+ /* @__PURE__ */ jsxs("div", { className: ColorWheel_module_default.picker, style: { height: arcVisible ? PICKER_HEIGHT_WITH_ARC : PICKER_HEIGHT_NO_ARC }, children: [
549
+ /* @__PURE__ */ jsx(
550
+ "div",
551
+ {
552
+ className: ColorWheel_module_default.glow,
553
+ style: { background: `radial-gradient(closest-side, ${solidHex}, transparent 72%)` }
554
+ }
555
+ ),
556
+ /* @__PURE__ */ jsxs(
557
+ "div",
558
+ {
559
+ className: ColorWheel_module_default.modeToggle,
560
+ ref: modeToggleRef,
561
+ style: { width: modes.length * 28, gridTemplateColumns: `repeat(${modes.length}, 1fr)` },
562
+ children: [
563
+ /* @__PURE__ */ jsx(
564
+ "div",
565
+ {
566
+ className: ColorWheel_module_default.modePill,
567
+ style: {
568
+ width: `calc(${100 / modes.length}% - 2px)`,
569
+ transform: `translateX(calc(${modes.indexOf(mode)} * (100% + 1px)))`
570
+ }
571
+ }
572
+ ),
573
+ modes.map((m) => /* @__PURE__ */ jsx(
574
+ "button",
575
+ {
576
+ type: "button",
577
+ className: [ColorWheel_module_default.modeButton, mode === m ? ColorWheel_module_default.active : ""].join(" "),
578
+ onClick: () => setMode(m),
579
+ children: m.toUpperCase()
580
+ },
581
+ m
582
+ ))
583
+ ]
584
+ }
585
+ ),
586
+ /* @__PURE__ */ jsxs("div", { className: ColorWheel_module_default.stage, ref: stageRef, children: [
587
+ /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.stageShadow }),
588
+ /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.ring, style: { background: ringGradient(mode, hsv) } }),
589
+ /* @__PURE__ */ jsxs("div", { className: ColorWheel_module_default.currentDisc, onClick: handleDiscClick, children: [
590
+ /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.discFill, style: { background: `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})` } }),
591
+ !editing && /* @__PURE__ */ jsx("span", { className: [ColorWheel_module_default.currentHex, copied ? ColorWheel_module_default.copied : ""].join(" "), style: { color: discText }, onClick: beginEdit, children: copied ? "Copied" : hexString }),
592
+ editing && /* @__PURE__ */ jsx(
593
+ "input",
594
+ {
595
+ ref: hexInputRef,
596
+ className: ColorWheel_module_default.currentHexInput,
597
+ style: { color: discText },
598
+ type: "text",
599
+ inputMode: "text",
600
+ autoComplete: "off",
601
+ spellCheck: false,
602
+ maxLength: 9,
603
+ value: editValue,
604
+ onClick: (e) => e.stopPropagation(),
605
+ onChange: (e) => setEditValue(e.target.value),
606
+ onKeyDown: (e) => {
607
+ if (e.key === "Enter") hexInputRef.current?.blur();
608
+ else if (e.key === "Escape") {
609
+ commitEdit(true);
610
+ }
611
+ },
612
+ onBlur: () => commitEdit(false)
613
+ }
614
+ )
615
+ ] }),
616
+ eyedropperSupported && /* @__PURE__ */ jsx(
617
+ "button",
618
+ {
619
+ type: "button",
620
+ className: [ColorWheel_module_default.discBadge, ColorWheel_module_default.discBadgeBottom].join(" "),
621
+ style: badgeShadow,
622
+ "aria-label": "Pick color from screen",
623
+ onClick: pickFromScreen,
624
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 32 32", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M27.7,3.3c-1.5-1.5-3.9-1.5-5.4,0L17,8.6l-1.3-1.3c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l1.3,1.3L5,20.6c-0.6,0.6-1,1.4-1.1,2.3C3.3,23.4,3,24.2,3,25c0,1.7,1.3,3,3,3c0.8,0,1.6-0.3,2.2-0.9C9,27,9.8,26.6,10.4,26L21,15.4l1.3,1.3c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L22.4,14l5.3-5.3C29.2,7.2,29.2,4.8,27.7,3.3z M9,24.6c-0.4,0.4-0.8,0.6-1.3,0.5c-0.4,0-0.7,0.2-0.9,0.5C6.7,25.8,6.3,26,6,26c-0.6,0-1-0.4-1-1c0-0.3,0.2-0.7,0.5-0.8c0.3-0.2,0.5-0.5,0.5-0.9c0-0.5,0.2-1,0.5-1.3L17,11.4l2.6,2.6L9,24.6z" }) })
625
+ }
626
+ ),
627
+ /* @__PURE__ */ jsx(
628
+ "button",
629
+ {
630
+ type: "button",
631
+ className: [ColorWheel_module_default.discBadge, ColorWheel_module_default.discBadgeTop, pulseFavorite ? ColorWheel_module_default.pulse : ""].join(" "),
632
+ style: badgeShadow,
633
+ "aria-label": "Save current color to favorites",
634
+ onClick: saveFavorite,
635
+ onAnimationEnd: () => setPulseFavorite(false),
636
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M12 5v14M5 12h14" }) })
637
+ }
638
+ ),
639
+ /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.hueHandlePivot, style: { transform: `translate(-50%, -50%) rotate(${ringAngleFromTopDeg}deg)` }, children: /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.hueHandle, style: { background: solidHex } }) })
640
+ ] }),
641
+ /* @__PURE__ */ jsxs("div", { style: { display: arcVisible ? "contents" : "none" }, children: [
642
+ /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.alphaArcShadowWrap, children: /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.alphaArcShadow }) }),
643
+ /* @__PURE__ */ jsx("div", { className: ColorWheel_module_default.alphaArc, ref: alphaArcRef, children: /* @__PURE__ */ jsx(
644
+ "div",
645
+ {
646
+ className: ColorWheel_module_default.alphaArcFill,
647
+ style: { background: `conic-gradient(from 90deg, ${solidHex} 30deg, transparent 150deg)` }
648
+ }
649
+ ) }),
650
+ /* @__PURE__ */ jsx("div", { className: [ColorWheel_module_default.alphaArcCap, ColorWheel_module_default.alphaArcCapStart].join(" "), style: { background: solidHex } }),
651
+ /* @__PURE__ */ jsx("div", { className: [ColorWheel_module_default.alphaArcCap, ColorWheel_module_default.alphaArcCapEnd].join(" ") }),
652
+ /* @__PURE__ */ jsx(
653
+ "div",
654
+ {
655
+ className: ColorWheel_module_default.alphaArcHandle,
656
+ style: {
657
+ transform: `translate(calc(-50% + ${arcHandleDx}px), calc(-50% + ${arcHandleDy}px))`,
658
+ background: solidHex
659
+ }
660
+ }
661
+ )
662
+ ] })
663
+ ] })
664
+ ]
665
+ }
666
+ );
667
+ }
668
+
669
+ export { ColorWheel };
670
+ //# sourceMappingURL=index.js.map
671
+ //# sourceMappingURL=index.js.map