@@ -4,7 +4,17 @@ import React, { useState, useEffect } from 'react';
44import { motion , Variants } from 'motion/react' ;
55import { CursorType , Position , CursorProps } from './types' ;
66
7- const INTERACTIVE_ELEMENTS : string [ ] = [ 'BUTTON' , 'A' , 'INPUT' , 'LABEL' , 'SELECT' , 'TEXTAREA' , 'DETAILS' , 'SUMMARY' ] ;
7+ const INTERACTIVE_ELEMENTS : string [ ] = [
8+ 'BUTTON' ,
9+ 'A' ,
10+ 'INPUT' ,
11+ 'LABEL' ,
12+ 'SELECT' ,
13+ 'TEXTAREA' ,
14+ 'DETAILS' ,
15+ 'SUMMARY' ,
16+ 'OPTION' ,
17+ ] ;
818
919const TEXT_ELEMENTS : string [ ] = [
1020 'P' ,
@@ -30,8 +40,44 @@ const TEXT_ELEMENTS: string[] = [
3040 'MARK' ,
3141 'Q' ,
3242 'CITE' ,
43+ 'DL' ,
44+ 'DT' ,
45+ 'DD' ,
46+ 'FIGCAPTION' ,
47+ 'ABBR' ,
48+ 'TIME' ,
49+ 'DEL' ,
50+ 'INS' ,
51+ 'VAR' ,
52+ 'SAMP' ,
53+ 'KBD' ,
54+ 'SMALL' ,
3355] ;
3456
57+ const isMobile = ( ) : boolean => {
58+ return / i P h o n e | i P a d | i P o d | A n d r o i d | W e b O S / i. test ( navigator . userAgent ) ;
59+ } ;
60+
61+ const isInteractive = ( target : HTMLElement ) : boolean => {
62+ if ( INTERACTIVE_ELEMENTS . includes ( target . tagName ) ) {
63+ return true ;
64+ }
65+ // Check interactions via a role or an 'onclick' event
66+ if (
67+ target . getAttribute ( 'role' ) === 'button' ||
68+ target . getAttribute ( 'role' ) === 'link' ||
69+ target . hasAttribute ( 'onclick' )
70+ ) {
71+ return true ;
72+ }
73+ // Check if the element belongs to an interactive container
74+ if ( target . closest ( 'A' ) || target . closest ( 'BUTTON' ) ) {
75+ return true ;
76+ }
77+
78+ return false ;
79+ } ;
80+
3581const Cursor : React . FC < CursorProps > = ( { zIndex = 9999 } ) => {
3682 const [ position , setPosition ] = useState < Position > ( { x : 0 , y : 0 } ) ;
3783 const [ cursorType , setCursorType ] = useState < CursorType > ( 'default' ) ;
@@ -77,6 +123,10 @@ const Cursor: React.FC<CursorProps> = ({ zIndex = 9999 }) => {
77123 } ;
78124
79125 useEffect ( ( ) => {
126+ if ( isMobile ( ) ) {
127+ return ;
128+ }
129+
80130 const handleMouseMove = ( e : MouseEvent ) : void => {
81131 setPosition ( { x : e . clientX , y : e . clientY } ) ;
82132 } ;
@@ -86,14 +136,13 @@ const Cursor: React.FC<CursorProps> = ({ zIndex = 9999 }) => {
86136
87137 if ( target . hasAttribute ( 'disabled' ) ) {
88138 setCursorType ( 'disabled' ) ;
89- } else if ( INTERACTIVE_ELEMENTS . includes ( target . tagName ) || ( target . tagName === 'IMG' && target . closest ( 'A' ) ) ) {
139+ }
140+ // Prioritize interactive elements
141+ else if ( isInteractive ( target ) ) {
90142 setCursorType ( 'hover' ) ;
91143 } else if ( TEXT_ELEMENTS . includes ( target . tagName ) ) {
92144 setFontSize ( parseFloat ( getComputedStyle ( target ) . fontSize ) ) ;
93145 setCursorType ( 'text' ) ;
94- } else if ( target . tagName === 'A' && target . querySelector ( 'IMG' ) ) {
95- // fix strange css behavior of images inside links
96- setCursorType ( 'default' ) ;
97146 } else {
98147 setCursorType ( 'default' ) ;
99148 }
@@ -118,6 +167,10 @@ const Cursor: React.FC<CursorProps> = ({ zIndex = 9999 }) => {
118167 } ;
119168 } , [ ] ) ;
120169
170+ if ( isMobile ( ) ) {
171+ return null ;
172+ }
173+
121174 return (
122175 < motion . div
123176 className = "custom-cursor"
0 commit comments