diff --git a/components/converter/MainConverter.tsx b/components/converter/MainConverter.tsx index be2ea9e..76fd56b 100644 --- a/components/converter/MainConverter.tsx +++ b/components/converter/MainConverter.tsx @@ -32,6 +32,7 @@ export default function MainConverter() { const [favorites, setFavorites] = useState([]); const [copiedUnit, setCopiedUnit] = useState(null); const [showVisualComparison, setShowVisualComparison] = useState(false); + const [isDragging, setIsDragging] = useState(false); const measures = getAllMeasures(); const units = getUnitsForMeasure(selectedMeasure); @@ -92,8 +93,10 @@ export default function MainConverter() { setFavorites(getFavorites()); }, []); - // Save to history when conversion happens + // Save to history when conversion happens (but not during dragging) useEffect(() => { + if (isDragging) return; // Don't save to history while dragging + const numValue = parseNumberInput(inputValue); if (numValue !== null && selectedUnit && conversions.length > 0) { // Save first conversion to history @@ -108,7 +111,7 @@ export default function MainConverter() { window.dispatchEvent(new Event('historyUpdated')); } } - }, [inputValue, selectedUnit, conversions, selectedMeasure]); + }, [inputValue, selectedUnit, conversions, selectedMeasure, isDragging]); // Handle search selection const handleSearchSelect = useCallback((unit: string, measure: Measure) => { @@ -124,8 +127,9 @@ export default function MainConverter() { }, []); // Handle value change from draggable bars - const handleValueChange = useCallback((value: number, unit: string) => { + const handleValueChange = useCallback((value: number, unit: string, dragging: boolean) => { // When dragging a bar, switch to that unit as the source + setIsDragging(dragging); setInputValue(value.toString()); setSelectedUnit(unit); }, []); diff --git a/components/converter/VisualComparison.tsx b/components/converter/VisualComparison.tsx index 6869be9..1d4e65e 100644 --- a/components/converter/VisualComparison.tsx +++ b/components/converter/VisualComparison.tsx @@ -7,7 +7,7 @@ import { formatNumber, cn } from '@/lib/utils'; interface VisualComparisonProps { conversions: ConversionResult[]; color: string; - onValueChange?: (value: number, unit: string) => void; + onValueChange?: (value: number, unit: string, dragging: boolean) => void; } export default function VisualComparison({ @@ -19,6 +19,7 @@ export default function VisualComparison({ const dragStartX = useRef(0); const dragStartWidth = useRef(0); const activeBarRef = useRef(null); + const lastUpdateTime = useRef(0); // Calculate percentages for visual bars using logarithmic scale const withPercentages = useMemo(() => { if (conversions.length === 0) return []; @@ -93,6 +94,11 @@ export default function VisualComparison({ const handleMouseMove = useCallback((e: MouseEvent) => { if (!draggingUnit || !activeBarRef.current || !onValueChange) return; + // Throttle updates to every 16ms (~60fps) + const now = Date.now(); + if (now - lastUpdateTime.current < 16) return; + lastUpdateTime.current = now; + const barWidth = activeBarRef.current.offsetWidth; const deltaX = e.clientX - dragStartX.current; const deltaPercentage = (deltaX / barWidth) * 100; @@ -112,13 +118,20 @@ export default function VisualComparison({ // Calculate new value from percentage const newValue = calculateValueFromPercentage(newPercentage, minValue, maxValue); - onValueChange(newValue, draggingUnit); + onValueChange(newValue, draggingUnit, true); // true = currently dragging }, [draggingUnit, conversions, onValueChange, calculateValueFromPercentage]); const handleMouseUp = useCallback(() => { + if (draggingUnit && onValueChange) { + // Find the current value for the dragged unit + const conversion = conversions.find(c => c.unit === draggingUnit); + if (conversion) { + onValueChange(conversion.value, draggingUnit, false); // false = drag ended + } + } setDraggingUnit(null); activeBarRef.current = null; - }, []); + }, [draggingUnit, conversions, onValueChange]); // Touch drag handlers const handleTouchStart = useCallback((e: React.TouchEvent, unit: string, currentPercentage: number, barElement: HTMLDivElement) => { @@ -134,6 +147,11 @@ export default function VisualComparison({ const handleTouchMove = useCallback((e: TouchEvent) => { if (!draggingUnit || !activeBarRef.current || !onValueChange) return; + // Throttle updates to every 16ms (~60fps) + const now = Date.now(); + if (now - lastUpdateTime.current < 16) return; + lastUpdateTime.current = now; + e.preventDefault(); // Prevent scrolling while dragging const touch = e.touches[0]; const barWidth = activeBarRef.current.offsetWidth; @@ -152,13 +170,20 @@ export default function VisualComparison({ const newValue = calculateValueFromPercentage(newPercentage, minValue, maxValue); - onValueChange(newValue, draggingUnit); + onValueChange(newValue, draggingUnit, true); // true = currently dragging }, [draggingUnit, conversions, onValueChange, calculateValueFromPercentage]); const handleTouchEnd = useCallback(() => { + if (draggingUnit && onValueChange) { + // Find the current value for the dragged unit + const conversion = conversions.find(c => c.unit === draggingUnit); + if (conversion) { + onValueChange(conversion.value, draggingUnit, false); // false = drag ended + } + } setDraggingUnit(null); activeBarRef.current = null; - }, []); + }, [draggingUnit, conversions, onValueChange]); // Add/remove global event listeners for drag useEffect(() => {