mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
fix: color picker
This commit is contained in:
@@ -37,7 +37,10 @@ const hexToHsv = (hex: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [h * 60, s, v];
|
h = (h * 60 + 360) % 360;
|
||||||
|
if (isNaN(h)) h = 0;
|
||||||
|
|
||||||
|
return [h, s, v];
|
||||||
};
|
};
|
||||||
|
|
||||||
const hsvToHex = (h: number, s: number, v: number) => {
|
const hsvToHex = (h: number, s: number, v: number) => {
|
||||||
@@ -92,12 +95,20 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
});
|
});
|
||||||
|
const [internalHue, setInternalHue] = React.useState(0);
|
||||||
|
const [inputValue, setInputValue] = React.useState(value);
|
||||||
|
|
||||||
const pickerRef = React.useRef<HTMLDivElement>(null);
|
const pickerRef = React.useRef<HTMLDivElement>(null);
|
||||||
const saturationRef = React.useRef<HTMLDivElement>(null);
|
const saturationRef = React.useRef<HTMLDivElement>(null);
|
||||||
const hueRef = React.useRef<HTMLDivElement>(null);
|
const hueRef = React.useRef<HTMLDivElement>(null);
|
||||||
const triggerRef = React.useRef<HTMLDivElement>(null);
|
const triggerRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [h, s, v] = hexToHsv(value);
|
const [h, s, v] = hexToHsv(value);
|
||||||
|
const displayHue = s > 0 ? h : internalHue;
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setInputValue(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
@@ -130,10 +141,9 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
0,
|
0,
|
||||||
Math.min(1, (e.clientY - rect.top) / rect.height)
|
Math.min(1, (e.clientY - rect.top) / rect.height)
|
||||||
);
|
);
|
||||||
|
|
||||||
const newS = x;
|
const newS = x;
|
||||||
const newV = 1 - y;
|
const newV = 1 - y;
|
||||||
const newHex = hsvToHex(h, newS, newV);
|
const newHex = hsvToHex(displayHue, newS, newV);
|
||||||
onChange?.(newHex);
|
onChange?.(newHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +154,11 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
Math.min(1, (e.clientX - rect.left) / rect.width)
|
Math.min(1, (e.clientX - rect.left) / rect.width)
|
||||||
);
|
);
|
||||||
const newH = x * 360;
|
const newH = x * 360;
|
||||||
const newHex = hsvToHex(newH, s, v);
|
setInternalHue(newH);
|
||||||
onChange?.(newHex);
|
if (s > 0) {
|
||||||
|
const newHex = hsvToHex(newH, s, v);
|
||||||
|
onChange?.(newHex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,37 +174,33 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
document.removeEventListener("mouseup", handleMouseUp);
|
document.removeEventListener("mouseup", handleMouseUp);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [isDragging, h, s, v, onChange]);
|
}, [isDragging, displayHue, s, v, onChange]);
|
||||||
|
|
||||||
const handleSaturationMouseDown = (e: React.MouseEvent) => {
|
const handleSaturationMouseDown = (e: React.MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsDragging("saturation");
|
setIsDragging("saturation");
|
||||||
|
|
||||||
const rect = saturationRef.current!.getBoundingClientRect();
|
const rect = saturationRef.current!.getBoundingClientRect();
|
||||||
const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
||||||
const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
|
const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
|
||||||
const newS = x;
|
const newS = x;
|
||||||
const newV = 1 - y;
|
const newV = 1 - y;
|
||||||
const newHex = hsvToHex(h, newS, newV);
|
const newHex = hsvToHex(displayHue, newS, newV);
|
||||||
onChange?.(newHex);
|
onChange?.(newHex);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleHueMouseDown = (e: React.MouseEvent) => {
|
const handleHueMouseDown = (e: React.MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
setIsDragging("hue");
|
setIsDragging("hue");
|
||||||
|
|
||||||
const rect = hueRef.current!.getBoundingClientRect();
|
const rect = hueRef.current!.getBoundingClientRect();
|
||||||
const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
||||||
const newH = x * 360;
|
const newH = x * 360;
|
||||||
const newHex = hsvToHex(newH, s, v);
|
setInternalHue(newH);
|
||||||
onChange?.(newHex);
|
if (s > 0) {
|
||||||
|
const newHex = hsvToHex(newH, s, v);
|
||||||
|
onChange?.(newHex);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [inputValue, setInputValue] = React.useState(value);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
setInputValue(value);
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const hex = e.target.value.replace("#", "");
|
const hex = e.target.value.replace("#", "");
|
||||||
setInputValue(hex);
|
setInputValue(hex);
|
||||||
@@ -209,7 +218,7 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saturationStyle = {
|
const saturationStyle = {
|
||||||
background: `linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${h}, 100%, 50%))`,
|
background: `linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${displayHue}, 100%, 50%))`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const hueStyle = {
|
const hueStyle = {
|
||||||
@@ -235,7 +244,6 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
if (!isOpen && triggerRef.current && containerRef?.current) {
|
if (!isOpen && triggerRef.current && containerRef?.current) {
|
||||||
const containerRect =
|
const containerRect =
|
||||||
containerRef.current.getBoundingClientRect();
|
containerRef.current.getBoundingClientRect();
|
||||||
|
|
||||||
setPickerPosition({
|
setPickerPosition({
|
||||||
right: window.innerWidth - containerRect.left - 8,
|
right: window.innerWidth - containerRect.left - 8,
|
||||||
bottom: window.innerHeight - containerRect.bottom,
|
bottom: window.innerHeight - containerRect.bottom,
|
||||||
@@ -246,7 +254,7 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
/>
|
/>
|
||||||
<div className="flex-1 flex items-center">
|
<div className="flex-1 flex items-center">
|
||||||
<Input
|
<Input
|
||||||
className="bg-transparent p-0 !ring-0 !ring-offset-0 !border-0 "
|
className="bg-transparent p-0 !ring-0 !ring-offset-0 !border-0"
|
||||||
containerClassName="w-full"
|
containerClassName="w-full"
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
@@ -287,7 +295,10 @@ const ColorPicker = React.forwardRef<HTMLDivElement, ColorPickerProps>(
|
|||||||
>
|
>
|
||||||
<ColorCircle
|
<ColorCircle
|
||||||
size="md"
|
size="md"
|
||||||
position={{ left: `${(h / 360) * 100}%`, top: "50%" }}
|
position={{
|
||||||
|
left: `${(displayHue / 360) * 100}%`,
|
||||||
|
top: "50%",
|
||||||
|
}}
|
||||||
color={`#${value}`}
|
color={`#${value}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -310,7 +321,7 @@ const ColorCircle = ({
|
|||||||
color: string;
|
color: string;
|
||||||
}) => (
|
}) => (
|
||||||
<div
|
<div
|
||||||
className={`absolute border-3 border-accent rounded-full shadow-lg pointer-events-none ${
|
className={`absolute border-3 border-white rounded-full shadow-lg pointer-events-none ${
|
||||||
size === "sm" ? "w-3 h-3" : "w-4 h-4"
|
size === "sm" ? "w-3 h-3" : "w-4 h-4"
|
||||||
}`}
|
}`}
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
Reference in New Issue
Block a user