diff --git a/apps/www/public/llms-full.txt b/apps/www/public/llms-full.txt index 05f295e19..c6872aeed 100644 --- a/apps/www/public/llms-full.txt +++ b/apps/www/public/llms-full.txt @@ -16507,7 +16507,13 @@ Description: An animated button with ripple useful for user engagement. --- file: magicui/ripple-button.tsx --- "use client" -import React, { useEffect, useState, type MouseEvent } from "react" +import React, { + useCallback, + useEffect, + useRef, + useState, + type MouseEvent, +} from "react" import { cn } from "@/lib/utils" @@ -16516,6 +16522,55 @@ interface RippleButtonProps extends React.ButtonHTMLAttributes void +}) { + useEffect(() => { + const timeout = setTimeout( + () => { + onDone(ripple.key) + }, + parseInt(duration, 10) + ) + + return () => { + clearTimeout(timeout) + } + }, [duration, onDone, ripple.key]) + + return ( + + ) +} + export const RippleButton = React.forwardRef< HTMLButtonElement, RippleButtonProps @@ -16531,9 +16586,14 @@ export const RippleButton = React.forwardRef< }, ref ) => { - const [buttonRipples, setButtonRipples] = useState< - Array<{ x: number; y: number; size: number; key: number }> - >([]) + const [buttonRipples, setButtonRipples] = useState>([]) + const nextKeyRef = useRef(0) + + const removeRipple = useCallback((key: number) => { + setButtonRipples((prevRipples) => + prevRipples.filter((ripple) => ripple.key !== key) + ) + }, []) const handleClick = (event: MouseEvent) => { createRipple(event) @@ -16547,29 +16607,11 @@ export const RippleButton = React.forwardRef< const x = event.clientX - rect.left - size / 2 const y = event.clientY - rect.top - size / 2 - const newRipple = { x, y, size, key: Date.now() } + nextKeyRef.current += 1 + const newRipple = { x, y, size, key: nextKeyRef.current } setButtonRipples((prevRipples) => [...prevRipples, newRipple]) } - useEffect(() => { - let timeout: ReturnType | null = null - - if (buttonRipples.length > 0) { - const lastRipple = buttonRipples[buttonRipples.length - 1] - timeout = setTimeout(() => { - setButtonRipples((prevRipples) => - prevRipples.filter((ripple) => ripple.key !== lastRipple.key) - ) - }, parseInt(duration)) - } - - return () => { - if (timeout !== null) { - clearTimeout(timeout) - } - } - }, [buttonRipples, duration]) - return ( \n )\n }\n)\n\nRippleButton.displayName = \"RippleButton\"\n", + "content": "\"use client\"\n\nimport React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n type MouseEvent,\n} from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface RippleButtonProps extends React.ButtonHTMLAttributes {\n rippleColor?: string\n duration?: string\n}\n\ntype RippleItem = {\n x: number\n y: number\n size: number\n key: number\n}\n\nfunction ButtonRipple({\n ripple,\n duration,\n rippleColor,\n onDone,\n}: {\n ripple: RippleItem\n duration: string\n rippleColor: string\n onDone: (key: number) => void\n}) {\n useEffect(() => {\n const timeout = setTimeout(\n () => {\n onDone(ripple.key)\n },\n parseInt(duration, 10)\n )\n\n return () => {\n clearTimeout(timeout)\n }\n }, [duration, onDone, ripple.key])\n\n return (\n \n )\n}\n\nexport const RippleButton = React.forwardRef<\n HTMLButtonElement,\n RippleButtonProps\n>(\n (\n {\n className,\n children,\n rippleColor = \"#ffffff\",\n duration = \"600ms\",\n onClick,\n ...props\n },\n ref\n ) => {\n const [buttonRipples, setButtonRipples] = useState>([])\n const nextKeyRef = useRef(0)\n\n const removeRipple = useCallback((key: number) => {\n setButtonRipples((prevRipples) =>\n prevRipples.filter((ripple) => ripple.key !== key)\n )\n }, [])\n\n const handleClick = (event: MouseEvent) => {\n createRipple(event)\n onClick?.(event)\n }\n\n const createRipple = (event: MouseEvent) => {\n const button = event.currentTarget\n const rect = button.getBoundingClientRect()\n const size = Math.max(rect.width, rect.height)\n const x = event.clientX - rect.left - size / 2\n const y = event.clientY - rect.top - size / 2\n\n nextKeyRef.current += 1\n const newRipple = { x, y, size, key: nextKeyRef.current }\n setButtonRipples((prevRipples) => [...prevRipples, newRipple])\n }\n\n return (\n \n
{children}
\n \n {buttonRipples.map((ripple) => (\n \n ))}\n \n \n )\n }\n)\n\nRippleButton.displayName = \"RippleButton\"\n", "type": "registry:ui" } ], diff --git a/apps/www/registry/magicui/ripple-button.tsx b/apps/www/registry/magicui/ripple-button.tsx index 0cc571cb0..efe83c8d8 100644 --- a/apps/www/registry/magicui/ripple-button.tsx +++ b/apps/www/registry/magicui/ripple-button.tsx @@ -1,6 +1,12 @@ "use client" -import React, { useEffect, useState, type MouseEvent } from "react" +import React, { + useCallback, + useEffect, + useRef, + useState, + type MouseEvent, +} from "react" import { cn } from "@/lib/utils" @@ -9,6 +15,55 @@ interface RippleButtonProps extends React.ButtonHTMLAttributes void +}) { + useEffect(() => { + const timeout = setTimeout( + () => { + onDone(ripple.key) + }, + parseInt(duration, 10) + ) + + return () => { + clearTimeout(timeout) + } + }, [duration, onDone, ripple.key]) + + return ( + + ) +} + export const RippleButton = React.forwardRef< HTMLButtonElement, RippleButtonProps @@ -24,9 +79,14 @@ export const RippleButton = React.forwardRef< }, ref ) => { - const [buttonRipples, setButtonRipples] = useState< - Array<{ x: number; y: number; size: number; key: number }> - >([]) + const [buttonRipples, setButtonRipples] = useState>([]) + const nextKeyRef = useRef(0) + + const removeRipple = useCallback((key: number) => { + setButtonRipples((prevRipples) => + prevRipples.filter((ripple) => ripple.key !== key) + ) + }, []) const handleClick = (event: MouseEvent) => { createRipple(event) @@ -40,29 +100,11 @@ export const RippleButton = React.forwardRef< const x = event.clientX - rect.left - size / 2 const y = event.clientY - rect.top - size / 2 - const newRipple = { x, y, size, key: Date.now() } + nextKeyRef.current += 1 + const newRipple = { x, y, size, key: nextKeyRef.current } setButtonRipples((prevRipples) => [...prevRipples, newRipple]) } - useEffect(() => { - let timeout: ReturnType | null = null - - if (buttonRipples.length > 0) { - const lastRipple = buttonRipples[buttonRipples.length - 1] - timeout = setTimeout(() => { - setButtonRipples((prevRipples) => - prevRipples.filter((ripple) => ripple.key !== lastRipple.key) - ) - }, parseInt(duration)) - } - - return () => { - if (timeout !== null) { - clearTimeout(timeout) - } - } - }, [buttonRipples, duration]) - return (