@hilum/ui 3.8.4 → 3.8.6
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.
- package/dist/index.js +21 -13
- package/dist/index.js.map +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/components/color-picker.tsx +32 -12
package/llms.txt
CHANGED
package/package.json
CHANGED
|
@@ -392,6 +392,21 @@ function parseColor(input: string): { r: number; g: number; b: number; a: number
|
|
|
392
392
|
return null;
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
+
function colorsRepresentSameValue(left: string, right: string): boolean {
|
|
396
|
+
if (left.trim().toLowerCase() === right.trim().toLowerCase()) return true;
|
|
397
|
+
|
|
398
|
+
const leftColor = parseColor(left);
|
|
399
|
+
const rightColor = parseColor(right);
|
|
400
|
+
if (!leftColor || !rightColor) return false;
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
Math.abs(leftColor.r - rightColor.r) < 0.5 &&
|
|
404
|
+
Math.abs(leftColor.g - rightColor.g) < 0.5 &&
|
|
405
|
+
Math.abs(leftColor.b - rightColor.b) < 0.5 &&
|
|
406
|
+
Math.abs(leftColor.a - rightColor.a) < 0.5 / 255
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
395
410
|
function buildParsed(h: number, s: number, v: number, a: number): ParsedColor {
|
|
396
411
|
const { r, g, b } = hsvToRgb(h, s, v);
|
|
397
412
|
const hsl = rgbToHsl(r, g, b);
|
|
@@ -463,7 +478,7 @@ interface SaturationSquareProps {
|
|
|
463
478
|
function SaturationSquare({ h, s, v, onChange }: SaturationSquareProps) {
|
|
464
479
|
const ref = useRef<HTMLDivElement>(null);
|
|
465
480
|
const dragging = useRef(false);
|
|
466
|
-
const
|
|
481
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
467
482
|
const [focused, setFocused] = useState(false);
|
|
468
483
|
const [hovered, setHovered] = useState(false);
|
|
469
484
|
const [cursorPos, setCursorPos] = useState<{ x: number; y: number } | null>(null);
|
|
@@ -494,7 +509,7 @@ function SaturationSquare({ h, s, v, onChange }: SaturationSquareProps) {
|
|
|
494
509
|
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
495
510
|
e.preventDefault();
|
|
496
511
|
dragging.current = true;
|
|
497
|
-
|
|
512
|
+
setIsDragging(true);
|
|
498
513
|
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
499
514
|
updateFromPointer(e.clientX, e.clientY);
|
|
500
515
|
},
|
|
@@ -505,7 +520,6 @@ function SaturationSquare({ h, s, v, onChange }: SaturationSquareProps) {
|
|
|
505
520
|
(e: React.PointerEvent<HTMLDivElement>) => {
|
|
506
521
|
updateCursorPos(e.clientX, e.clientY);
|
|
507
522
|
if (!dragging.current) return;
|
|
508
|
-
hasMoved.current = true;
|
|
509
523
|
updateFromPointer(e.clientX, e.clientY);
|
|
510
524
|
},
|
|
511
525
|
[updateFromPointer, updateCursorPos],
|
|
@@ -513,7 +527,7 @@ function SaturationSquare({ h, s, v, onChange }: SaturationSquareProps) {
|
|
|
513
527
|
|
|
514
528
|
const onPointerUp = useCallback(() => {
|
|
515
529
|
dragging.current = false;
|
|
516
|
-
|
|
530
|
+
setIsDragging(false);
|
|
517
531
|
}, []);
|
|
518
532
|
|
|
519
533
|
const onKeyDown = useCallback(
|
|
@@ -556,6 +570,8 @@ function SaturationSquare({ h, s, v, onChange }: SaturationSquareProps) {
|
|
|
556
570
|
onPointerDown={onPointerDown}
|
|
557
571
|
onPointerMove={onPointerMove}
|
|
558
572
|
onPointerUp={onPointerUp}
|
|
573
|
+
onPointerCancel={onPointerUp}
|
|
574
|
+
onLostPointerCapture={onPointerUp}
|
|
559
575
|
onKeyDown={onKeyDown}
|
|
560
576
|
className={cn("relative w-full select-none touch-none cursor-none outline-none", shape.bg)}
|
|
561
577
|
style={{
|
|
@@ -572,25 +588,25 @@ function SaturationSquare({ h, s, v, onChange }: SaturationSquareProps) {
|
|
|
572
588
|
background: `linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${h}, 100%, 50%))`,
|
|
573
589
|
}}
|
|
574
590
|
/>
|
|
575
|
-
<
|
|
591
|
+
<div
|
|
592
|
+
data-slot="color-picker-thumb"
|
|
593
|
+
aria-hidden="true"
|
|
576
594
|
className="absolute pointer-events-none rounded-full"
|
|
577
|
-
|
|
578
|
-
animate={{
|
|
595
|
+
style={{
|
|
579
596
|
left: `${s * 100}%`,
|
|
580
597
|
top: `${(1 - v) * 100}%`,
|
|
581
598
|
width: 18,
|
|
582
599
|
height: 18,
|
|
583
|
-
}}
|
|
584
|
-
transition={{ duration: 0 }}
|
|
585
|
-
style={{
|
|
586
600
|
transform: "translate(-50%, -50%)",
|
|
587
601
|
border: "1px solid white",
|
|
588
602
|
boxShadow: "0 0 0 1px rgba(0,0,0,1)",
|
|
589
603
|
backgroundColor: thumbColor,
|
|
590
604
|
}}
|
|
591
605
|
/>
|
|
592
|
-
{hovered && !
|
|
606
|
+
{hovered && !isDragging && cursorPos && (
|
|
593
607
|
<div
|
|
608
|
+
data-slot="color-picker-hover"
|
|
609
|
+
aria-hidden="true"
|
|
594
610
|
className="absolute pointer-events-none rounded-full"
|
|
595
611
|
style={{
|
|
596
612
|
left: `${cursorPos.x}%`,
|
|
@@ -1338,7 +1354,11 @@ const ColorPicker = forwardRef<HTMLDivElement, ColorPickerProps>(
|
|
|
1338
1354
|
if (!isControlled) return;
|
|
1339
1355
|
const emitted = lastEmittedRef.current;
|
|
1340
1356
|
const cur = value as string;
|
|
1341
|
-
|
|
1357
|
+
// Controlled consumers commonly normalize emitted hex strings (for
|
|
1358
|
+
// example, Pappery uppercases them). Treat a formatting-only round trip
|
|
1359
|
+
// as an acknowledgement of our last emission so the precise in-flight
|
|
1360
|
+
// HSV position is not replaced with RGB-quantized coordinates mid-drag.
|
|
1361
|
+
if (cur === emitted || colorsRepresentSameValue(cur, emitted)) return;
|
|
1342
1362
|
const p = parseColor(cur);
|
|
1343
1363
|
if (!p) return;
|
|
1344
1364
|
oklchHueRef.current = null;
|