Ripple Effect 03
Ripple Effect 03 é um componente de efeito para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Bund UI
MIT
effects
O que é
Ripple Effect 03 é um componente de efeito para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Como usar
Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.
Cinco cópias grátis por mês. Sem cartão.
Precisa de
npm i motion
Licença
Este componente vem de Bund UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.
Ripple Effect 03
import { RippleEffect } from "./ripple-effect";
export default function RippleEffectButton() {
const cardClass =
"flex aspect-square size-36 w-full select-none items-center justify-center text-xs font-medium tracking-widest uppercase text-muted-foreground";
return (
<div className="grid grid-cols-3 gap-4">
<RippleEffect className="bg-muted" color="var(--color-blue-300)">
<div className={cardClass}>blue</div>
</RippleEffect>
<RippleEffect className="bg-muted" color="var(--color-green-300)">
<div className={cardClass}>green</div>
</RippleEffect>
<RippleEffect className="bg-muted" color="var(--color-purple-300)">
<div className={cardClass}>purple</div>
</RippleEffect>
</div>
);
}
"use client";
import React from "react";
import { motion, AnimatePresence } from "motion/react";
interface RippleProps {
children: React.ReactNode;
color?: string;
duration?: number;
className?: string;
}
interface RipplePosition {
x: number;
y: number;
size: number;
id: number;
}
export const RippleEffect = ({
children,
color = "rgba(255, 255, 255, 0.7)",
duration = 0.8,
className
}: RippleProps) => {
const [ripples, setRipples] = React.useState<RipplePosition[]>([]);
const containerRef = React.useRef<HTMLDivElement>(null);
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const size = Math.max(rect.width, rect.height);
const newRipple: RipplePosition = {
x,
y,
size: size * 2,
id: Date.now()
};
setRipples((prevRipples) => [...prevRipples, newRipple]);
setTimeout(() => {
setRipples((prevRipples) => prevRipples.filter((ripple) => ripple.id !== newRipple.id));
}, duration * 1000);
};
return (
<div
ref={containerRef}
className={`relative inline-flex overflow-hidden rounded-lg ${className}`}
onMouseDown={handleClick}>
{children}
<AnimatePresence>
{ripples.map((ripple) => (
<motion.div
key={ripple.id}
initial={{
width: 0,
height: 0,
x: ripple.x,
y: ripple.y,
opacity: 0.5,
borderRadius: "100%"
}}
animate={{
width: ripple.size,
height: ripple.size,
x: ripple.x - ripple.size / 2,
y: ripple.y - ripple.size / 2,
opacity: 0,
borderRadius: "100%"
}}
exit={{ opacity: 0 }}
transition={{ duration, ease: "easeOut" }}
style={{
position: "absolute",
backgroundColor: color,
pointerEvents: "none"
}}
/>
))}
</AnimatePresence>
</div>
);
};