import React, { useEffect, useMemo, useRef } from 'react' import { useInventoryContext } from '../../context/InventoryContext' import { useScale } from '../../context/ScaleContext' import { ItemCanvas } from '../ItemCanvas' import { useMobile } from '../../hooks/useMobile' import { globalMouse } from '../../utils/globalMouse' /** * CursorItem — optimized to bypass React re-renders on mouse move. * Uses direct DOM manipulation via refs to update position every frame. * Only re-renders when heldItem or contentSize changes (for ItemCanvas updates). */ export function CursorItem() { const { heldItem, isDragging, dragSlots, dragRemainder } = useInventoryContext() const { contentSize } = useScale() const isMobile = useMobile() const containerRef = useRef(null) const rafRef = useRef(0) const halfSizeRef = useRef(Math.round(contentSize / 2)) // Determine display item: during spread, show remainder count const displayItem = useMemo(() => { if (isDragging && dragSlots.length > 1 && heldItem && dragRemainder !== null) { return { ...heldItem, count: dragRemainder } } return heldItem }, [isDragging, dragSlots.length, heldItem, dragRemainder]) // Update halfSize when contentSize changes useEffect(() => { halfSizeRef.current = Math.round(contentSize / 2) }, [contentSize]) // Direct DOM position updates — no React state, no re-renders useEffect(() => { if (isMobile || !heldItem || !containerRef.current) { // Cancel RAF if item dropped or mobile if (rafRef.current) { cancelAnimationFrame(rafRef.current) rafRef.current = 0 } return } const container = containerRef.current // Immediately position at current cursor const half = halfSizeRef.current container.style.left = `${globalMouse.x - half}px` container.style.top = `${globalMouse.y - half}px` // RAF loop — direct DOM updates, no React state const update = () => { if (!containerRef.current) return const half = halfSizeRef.current container.style.left = `${globalMouse.x - half}px` container.style.top = `${globalMouse.y - half}px` rafRef.current = requestAnimationFrame(update) } rafRef.current = requestAnimationFrame(update) return () => { if (rafRef.current) { cancelAnimationFrame(rafRef.current) rafRef.current = 0 } } }, [isMobile, heldItem]) // Only re-render when heldItem or contentSize changes (for ItemCanvas) if (!heldItem || isMobile) return null return (
{isDragging && dragSlots.length > 1 && dragRemainder === 0 && ( 0 )}
) }