11'use client' ;
22
33import { motion } from 'motion/react' ;
4- import { RefObject , useEffect , useId , useState } from 'react' ;
4+ import { RefObject , useEffect , useId , useMemo , useState } from 'react' ;
55
6- export interface AnimatedBeamProps {
6+ export type AnimatedBeamProps = {
77 className ?: string ;
88 containerRef : RefObject < HTMLElement | null > ; // Container ref
99 fromRef : RefObject < HTMLElement | null > ;
@@ -21,10 +21,9 @@ export interface AnimatedBeamProps {
2121 startYOffset ?: number ;
2222 endXOffset ?: number ;
2323 endYOffset ?: number ;
24- }
24+ } ;
2525
26- export const AnimatedBeam : React . FC < AnimatedBeamProps > = ( {
27- className,
26+ export function AnimatedBeam ( {
2827 containerRef,
2928 fromRef,
3029 toRef,
@@ -41,26 +40,11 @@ export const AnimatedBeam: React.FC<AnimatedBeamProps> = ({
4140 startYOffset = 0 ,
4241 endXOffset = 0 ,
4342 endYOffset = 0 ,
44- } ) => {
43+ } : AnimatedBeamProps ) {
4544 const id = useId ( ) ;
4645 const [ pathD , setPathD ] = useState ( '' ) ;
4746 const [ svgDimensions , setSvgDimensions ] = useState ( { width : 0 , height : 0 } ) ;
4847
49- // Calculate the gradient coordinates based on the reverse prop
50- const gradientCoordinates = reverse
51- ? {
52- x1 : [ '90%' , '-10%' ] ,
53- x2 : [ '100%' , '0%' ] ,
54- y1 : [ '0%' , '0%' ] ,
55- y2 : [ '0%' , '0%' ] ,
56- }
57- : {
58- x1 : [ '10%' , '110%' ] ,
59- x2 : [ '0%' , '100%' ] ,
60- y1 : [ '0%' , '0%' ] ,
61- y2 : [ '0%' , '0%' ] ,
62- } ;
63-
6448 useEffect ( ( ) => {
6549 const updatePath = ( ) => {
6650 if ( containerRef . current && fromRef . current && toRef . current ) {
@@ -86,9 +70,9 @@ export const AnimatedBeam: React.FC<AnimatedBeamProps> = ({
8670 // Initialize ResizeObserver
8771 const resizeObserver = new ResizeObserver ( ( entries ) => {
8872 // For all entries, recalculate the path
89- for ( let entry of entries ) {
73+ entries . forEach ( ( ) => {
9074 updatePath ( ) ;
91- }
75+ } ) ;
9276 } ) ;
9377
9478 // Observe the container element
@@ -105,6 +89,48 @@ export const AnimatedBeam: React.FC<AnimatedBeamProps> = ({
10589 } ;
10690 } , [ containerRef , fromRef , toRef , curvature , startXOffset , startYOffset , endXOffset , endYOffset ] ) ;
10791
92+ const initial = useMemo ( ( ) => {
93+ return {
94+ x1 : '0%' ,
95+ x2 : '0%' ,
96+ y1 : '0%' ,
97+ y2 : '0%' ,
98+ } ;
99+ } , [ ] ) ;
100+
101+ const animate = useMemo ( ( ) => {
102+ // Calculate the gradient coordinates based on the reverse prop
103+ const gradientCoordinates = reverse
104+ ? {
105+ x1 : [ '90%' , '-10%' ] ,
106+ x2 : [ '100%' , '0%' ] ,
107+ y1 : [ '0%' , '0%' ] ,
108+ y2 : [ '0%' , '0%' ] ,
109+ }
110+ : {
111+ x1 : [ '10%' , '110%' ] ,
112+ x2 : [ '0%' , '100%' ] ,
113+ y1 : [ '0%' , '0%' ] ,
114+ y2 : [ '0%' , '0%' ] ,
115+ } ;
116+ return {
117+ x1 : gradientCoordinates . x1 ,
118+ x2 : gradientCoordinates . x2 ,
119+ y1 : gradientCoordinates . y1 ,
120+ y2 : gradientCoordinates . y2 ,
121+ } ;
122+ } , [ reverse ] ) ;
123+
124+ const transition = useMemo ( ( ) => {
125+ return {
126+ delay,
127+ duration,
128+ ease : [ 0.16 , 1 , 0.3 , 1 ] , // https://easings.net/#easeOutExpo
129+ repeat : Infinity ,
130+ repeatDelay : 0 ,
131+ } ;
132+ } , [ delay , duration ] ) ;
133+
108134 return (
109135 < svg
110136 fill = "none"
@@ -132,33 +158,17 @@ export const AnimatedBeam: React.FC<AnimatedBeamProps> = ({
132158 < motion . linearGradient
133159 className = "transform-gpu"
134160 id = { id }
135- gradientUnits = { 'userSpaceOnUse' }
136- initial = { {
137- x1 : '0%' ,
138- x2 : '0%' ,
139- y1 : '0%' ,
140- y2 : '0%' ,
141- } }
142- animate = { {
143- x1 : gradientCoordinates . x1 ,
144- x2 : gradientCoordinates . x2 ,
145- y1 : gradientCoordinates . y1 ,
146- y2 : gradientCoordinates . y2 ,
147- } }
148- transition = { {
149- delay,
150- duration,
151- ease : [ 0.16 , 1 , 0.3 , 1 ] , // https://easings.net/#easeOutExpo
152- repeat : Infinity ,
153- repeatDelay : 0 ,
154- } }
161+ gradientUnits = "userSpaceOnUse"
162+ initial = { initial }
163+ animate = { animate }
164+ transition = { transition }
155165 >
156- < stop stopColor = { gradientStartColor } stopOpacity = "0" > </ stop >
157- < stop stopColor = { gradientStartColor } > </ stop >
158- < stop offset = "32.5%" stopColor = { gradientStopColor } > </ stop >
159- < stop offset = "100%" stopColor = { gradientStopColor } stopOpacity = "0" > </ stop >
166+ < stop stopColor = { gradientStartColor } stopOpacity = "0" / >
167+ < stop stopColor = { gradientStartColor } / >
168+ < stop offset = "32.5%" stopColor = { gradientStopColor } / >
169+ < stop offset = "100%" stopColor = { gradientStopColor } stopOpacity = "0" / >
160170 </ motion . linearGradient >
161171 </ defs >
162172 </ svg >
163173 ) ;
164- } ;
174+ }
0 commit comments