import { useState, useEffect } from 'react'; const MatrixCursor = () => { const [position, setPosition] = useState({ x: 0, y: 0 }); const [isHovering, setIsHovering] = useState(false); const [isVisible, setIsVisible] = useState(false); const [isTouchDevice, setIsTouchDevice] = useState(false); useEffect(() => { // Detect touch device - only consider it a touch device if primary pointer is coarse (touch) const checkTouchDevice = () => { // Check if the device has a fine pointer (mouse) as primary input const hasFinePrimary = window.matchMedia('(pointer: fine)').matches; // Consider it a touch device only if it doesn't have a fine pointer as primary setIsTouchDevice(!hasFinePrimary); }; checkTouchDevice(); // Re-check on orientation change or resize (for hybrid devices) window.addEventListener('resize', checkTouchDevice); return () => { window.removeEventListener('resize', checkTouchDevice); }; }, []); useEffect(() => { // Don't set up mouse listeners on touch devices if (isTouchDevice) { document.body.classList.remove('matrix-cursor'); return; } const handleMouseMove = (e: MouseEvent) => { setPosition({ x: e.clientX, y: e.clientY }); setIsVisible(true); }; const handleMouseEnter = () => setIsVisible(true); const handleMouseLeave = () => setIsVisible(false); const handleHoverCheck = (e: MouseEvent) => { const target = e.target as HTMLElement; const isInteractive = target.tagName === 'A' || target.tagName === 'BUTTON' || !!target.closest('a') || !!target.closest('button') || target.getAttribute('role') === 'button' || window.getComputedStyle(target).cursor === 'pointer'; setIsHovering(isInteractive); }; // Hide cursor on any touch event (for hybrid devices) const handleTouch = () => { setIsVisible(false); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mousemove', handleHoverCheck); document.addEventListener('mouseenter', handleMouseEnter); document.addEventListener('mouseleave', handleMouseLeave); document.addEventListener('touchstart', handleTouch, { passive: true }); // Add cursor class to body document.body.classList.add('matrix-cursor'); return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mousemove', handleHoverCheck); document.removeEventListener('mouseenter', handleMouseEnter); document.removeEventListener('mouseleave', handleMouseLeave); document.removeEventListener('touchstart', handleTouch); document.body.classList.remove('matrix-cursor'); }; }, [isTouchDevice]); // Don't render anything on touch devices or when not visible if (isTouchDevice || !isVisible) return null; return ( <> {/* Crosshair */}
{/* Center dot */} > ); }; export default MatrixCursor;