47 lines
1.5 KiB
JavaScript
47 lines
1.5 KiB
JavaScript
"use client"
|
|
|
|
import React, { useState } from "react"
|
|
import { motion, AnimatePresence } from "motion/react"
|
|
|
|
export default function RippleButton({ children }) {
|
|
const [ripples, setRipples] = useState([])
|
|
|
|
const addRipple = (e) => {
|
|
const rect = e.currentTarget.getBoundingClientRect()
|
|
const x = e.clientX - rect.left
|
|
const y = e.clientY - rect.top
|
|
const id = Date.now()
|
|
|
|
setRipples([...ripples, { x, y, id }])
|
|
|
|
setTimeout(() => {
|
|
setRipples((r) => r.filter((ripple) => ripple.id !== id))
|
|
}, 600) // ripple длится ~600ms
|
|
}
|
|
|
|
return (
|
|
<button
|
|
onClick={addRipple}
|
|
className="relative overflow-hidden rounded-lg bg-blue-600 px-4 py-2 text-white font-medium"
|
|
>
|
|
{children}
|
|
<AnimatePresence>
|
|
{ripples.map((ripple) => (
|
|
<motion.span
|
|
key={ripple.id}
|
|
initial={{ scale: 0, opacity: 0.6 }}
|
|
animate={{ scale: 4, opacity: 0 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.6, ease: "easeOut" }}
|
|
style={{
|
|
left: ripple.x,
|
|
top: ripple.y,
|
|
}}
|
|
className="absolute h-8 w-8 rounded-full bg-white/70 pointer-events-none -translate-x-1/2 -translate-y-1/2"
|
|
/>
|
|
))}
|
|
</AnimatePresence>
|
|
</button>
|
|
)
|
|
}
|