# All files / utils useMousePos.ts

10.52% Statements 4/38
0% Branches 0/1
0% Functions 0/12
12.5% Lines 4/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    771x

    1x

    1x

    1x

     import {useState, useEffect, useMemo, MouseEvent} from 'react'

    export interface MousePosition {
      x: number | null
      y: number | null
    }

    interface UseMousePosProps {
      onMouseEnter: (e: MouseEvent<HTMLDivElement>) => void
      onMouseMove: (e: MouseEvent<HTMLDivElement>) => void
      onMouseLeave: (e: MouseEvent<HTMLDivElement>) => void
    }

    const mousePositionFromEvent = (e: MouseEvent<HTMLDivElement>) => {
      const {top, left} = e.currentTarget.getBoundingClientRect()

      return {x: e.clientX - left, y: e.clientY - top}
    }

    export const useMousePos = (): [MousePosition, UseMousePosProps] => {
      const [state, setState] = useState<MousePosition>({x: null, y: null})

      const eventProps = useMemo(
        () => ({
          onMouseEnter(e) {
            setState(mousePositionFromEvent(e))
          },
          onMouseMove(e) {
            setState(mousePositionFromEvent(e))
          },
          onMouseLeave() {
            setState({x: null, y: null})
          },
        }),
        []
      )

      return [state, eventProps]
    }

    export const useRefMousePos = (el: Element): MousePosition => {
      const [state, setState] = useState({x: null, y: null})

      useEffect(() => {
        Iif (!el) {
          // Force one more render to give the ref a chance to attach
          setState({x: null, y: null})

          return
        }

        const onMouseEnter = e => {
          setState({x: e.x, y: e.y})
        }

        const onMouseMove = e => {
          onMouseEnter(e)
        }

        const onMouseLeave = () => {
          setState({x: null, y: null})
        }

        el.addEventListener('mouseenter', onMouseEnter)
        el.addEventListener('mousemove', onMouseMove)
        el.addEventListener('mouseleave', onMouseLeave)

        return () => {
          el.removeEventListener('mouseenter', onMouseEnter)
          el.removeEventListener('mousemove', onMouseMove)
          el.removeEventListener('mouseleave', onMouseLeave)
        }
      }, [el])

      return state
    }