useBoop


The useBoop hook allows you to apply an animated boop effect to an element in React. The boop effect consists of a combination of movement, rotation, and scaling of the element.

Usage The useBoop hook accepts an object as a parameter that contains various settings for the boop effect:

x (optional, default: 0): The horizontal displacement of the element during the boop effect. y (optional, default: 0): The vertical displacement of the element during the boop effect. rotation (optional, default: 0): The rotation angle of the element during the boop effect. scale (optional, default: 1): The scaling of the element during the boop effect. timing (optional, default: 150): The duration of the boop effect in milliseconds. springConfig (optional, default: { tension: 300, friction: 10 }): The configuration for the spring animation that generates the boop effect. The useBoop hook returns an array that contains the applied style and a function to trigger the boop effect.

Usage

import type { MouseEvent, ReactNode } from 'react'
import { animated } from 'react-spring'

import { useBoop } from 'reactchemy'


interface Props {
   children: ReactNode
   [key: string]: any
}

export default function Component({ children, ...boopConfig }: Props) {
   const [style, trigger] = useBoop(boopConfig) as [any, () => void]

   const handleMouseEvent = (e: MouseEvent<HTMLButtonElement>) => {
      e.preventDefault()
      trigger()
   }

   return (
    <animated.span style={style} onMouseEnter={handleMouseEvent}>
      {children}
    </animated.span>
   )
}

Hook

import React from 'react'
import { useSpring } from 'react-spring'
import { usePrefersReducedMotion } from 'reactchemy'

export function useBoop({
   x = 0,
   y = 0,
   rotation = 0,
   scale = 1,
   timing = 150,
   springConfig = {
      tension: 300,
      friction: 10,
   },
}) {
   const prefersReducedMotion = usePrefersReducedMotion()
   const [isBooped, setIsBooped] = React.useState(false)
   const style = useSpring({
      transform: isBooped
         ? `translate(${x}px, ${y}px)
         rotate(${rotation}deg)
         scale(${scale})`
         : `translate(0px, 0px)
         rotate(0deg)
         scale(1)`,
      config: springConfig,
   })
   React.useEffect(() => {
      if (!isBooped)
         return

      const timeoutId = window.setTimeout(() => {
         setIsBooped(false)
      }, timing)
      return () => {
         window.clearTimeout(timeoutId)
      }
   }, [isBooped])
   const trigger = React.useCallback(() => {
      setIsBooped(true)
   }, [])
   const appliedStyle = prefersReducedMotion ? {} : style
   return [appliedStyle, trigger]
}