import React, { useEffect, useRef, useState } from "react"; import { useOklchCanvas } from "./useOklchCanvas"; import { Handle } from "./Handle"; import type { I18nProvider, LchChannel } from "./Picker"; import { type Oklch } from "culori"; import { round, precision, maxValue } from "./utils"; interface SliderProps { useP3: boolean; channel: LchChannel; color: Oklch; onChange: (value: number) => void; i18nProvider: I18nProvider; } export const Slider = ({ useP3, channel, color, onChange, i18nProvider }: SliderProps) => { const [value, setValue] = useState(color[channel]!.toFixed(precision[channel])); const containerRef = useRef(null); useEffect(() => { setValue(color[channel]!.toFixed(precision[channel])); }, [color.l, color.c, color.h]); const canvasRef = useRef(null); useOklchCanvas({ channel: channel, max: maxValue[channel], canvasRef: canvasRef, color, useP3 }); const getSliderPosition = (value: number, max: number) => { return (value / max) * 100; }; const getValueFromPosition = (clientX: number) => { if (!containerRef.current) return 0; const rect = containerRef.current.getBoundingClientRect(); const x = clientX - rect.left; const percentage = Math.max(0, Math.min(1, x / rect.width)); return round(percentage * maxValue[channel], precision[channel]); }; const onInputChange = (e: React.ChangeEvent) => { const value = parseFloat(e.target.value); if (value > maxValue[channel]) onChange(maxValue[channel]); else if (value < 0 || isNaN(value)) onChange(0); else onChange(value); setValue(e.target.value); }; const onBlur = (e: React.FocusEvent) => { const value = parseFloat(e.target.value); if (value > maxValue[channel]) { onChange(maxValue[channel]); setValue(maxValue[channel].toFixed(precision[channel])); } else if (value < 0 || isNaN(value)) { onChange(0); setValue("0"); } else { onChange(value); setValue(value.toFixed(precision[channel])); } }; const buttonHanlder = (type: "increase" | "decrease") => { const factor = type === "increase" ? 1 : -1; const step = Math.pow(10, -precision[channel] + 2); const delta = factor * step; onChange(round(color[channel]! + delta, precision[channel])); }; const handleOnChange = (value: number) => { onChange(round(value, precision[channel])); }; const handleTouchMove = (e: React.TouchEvent) => { const touch = e.touches[0]; if (touch) { const newValue = getValueFromPosition(touch.clientX); handleOnChange(newValue); } }; const handleTouchStart = (e: React.TouchEvent) => { const touch = e.touches[0]; if (touch) { const newValue = getValueFromPosition(touch.clientX); handleOnChange(newValue); } }; return (
); };