22
33import { cn } from "@/lib/utils" ;
44import { motion , stagger , useAnimate , useInView } from "framer-motion" ;
5- import { memo , useEffect } from "react" ;
5+ import { memo , useEffect , useMemo , useCallback } from "react" ;
66
77const TypewriterEffect = ( {
88 words,
@@ -16,16 +16,14 @@ const TypewriterEffect = ({
1616 className ?: string ;
1717 cursorClassName ?: string ;
1818} ) => {
19-
20- const wordsArray = words . map ( ( word ) => {
21- return {
22- ...word ,
23- text : word . text . split ( "" ) ,
24- } ;
25- } ) ;
19+ const wordsArray = useMemo ( ( ) => words . map ( ( word ) => ( {
20+ ...word ,
21+ text : word . text . split ( "" ) ,
22+ } ) ) , [ words ] ) ;
2623
2724 const [ scope , animate ] = useAnimate ( ) ;
28- const isInView = useInView ( scope ) ;
25+ const isInView = useInView ( scope , { once : true } ) ;
26+
2927 useEffect ( ( ) => {
3028 if ( isInView ) {
3129 animate (
@@ -36,53 +34,44 @@ const TypewriterEffect = ({
3634 width : "fit-content" ,
3735 } ,
3836 {
39- delay : stagger ( 0.1 ) ,
40- ease : "easeInOut" ,
37+ duration : 0.2 ,
38+ delay : stagger ( 0.1 , { startDelay : 0.3 } ) ,
39+ ease : "linear" ,
4140 }
4241 ) ;
4342 }
4443 } , [ isInView , animate ] ) ;
4544
46- const renderWords = ( ) => {
47- return (
48- < motion . div ref = { scope } className = "inline" >
49- { wordsArray . map ( ( word , idx ) => {
50- return (
51- < div key = { `word-${ idx } ` } className = "inline-block" >
52- { word . text . map ( ( char , index ) => (
53- < motion . span
54- initial = { { } }
55- key = { `char-${ index } ` }
56- className = { cn (
57- `dark:text-white text-black opacity-0 hidden` ,
58- word . className
59- ) }
60- >
61- { char }
62- </ motion . span >
63- ) ) }
64-
65- </ div >
66- ) ;
67- } ) }
68- </ motion . div >
69- ) ;
70- } ;
45+ const renderWords = useCallback ( ( ) => (
46+ < motion . div ref = { scope } className = "inline" >
47+ { wordsArray . map ( ( word , idx ) => (
48+ < div key = { `word-${ idx } ` } className = "inline-block" >
49+ { word . text . map ( ( char , index ) => (
50+ < motion . span
51+ key = { `char-${ index } ` }
52+ className = { cn (
53+ `dark:text-white text-black opacity-0 hidden` ,
54+ word . className
55+ ) }
56+ >
57+ { char }
58+ </ motion . span >
59+ ) ) }
60+
61+ </ div >
62+ ) ) }
63+ </ motion . div >
64+ ) , [ wordsArray , scope ] ) ;
65+
7166 return (
72- < div
73- className = { cn (
74- "text-base sm:text-xl md:text-1xl lg:text-4xl font-bold text-center" ,
75- className
76- ) }
77- >
67+ < div className = { cn (
68+ "text-base sm:text-xl md:text-1xl lg:text-4xl font-bold text-center" ,
69+ className
70+ ) } >
7871 { renderWords ( ) }
7972 < motion . span
80- initial = { {
81- opacity : 0 ,
82- } }
83- animate = { {
84- opacity : 1 ,
85- } }
73+ initial = { { opacity : 0 } }
74+ animate = { { opacity : 1 } }
8675 transition = { {
8776 duration : 0.8 ,
8877 repeat : Infinity ,
@@ -92,12 +81,12 @@ const TypewriterEffect = ({
9281 "inline-block rounded-sm w-[4px] h-4 md:h-6 lg:h-10 bg-blue-500" ,
9382 cursorClassName
9483 ) }
95- > </ motion . span >
84+ / >
9685 </ div >
9786 ) ;
9887} ;
9988
100- export const TypewriterEffectSmooth = ( {
89+ export const TypewriterEffectSmooth = memo ( ( {
10190 words,
10291 className,
10392 cursorClassName,
@@ -109,45 +98,36 @@ export const TypewriterEffectSmooth = ({
10998 className ?: string ;
11099 cursorClassName ?: string ;
111100} ) => {
112- // split text inside of words into array of characters
113- const wordsArray = words . map ( ( word ) => {
114- return {
115- ...word ,
116- text : word . text . split ( "" ) ,
117- } ;
118- } ) ;
119- const renderWords = ( ) => {
120- return (
121- < div >
122- { wordsArray . map ( ( word , idx ) => {
123- return (
124- < div key = { `word-${ idx } ` } className = "inline-block" >
125- { word . text . map ( ( char , index ) => (
126- < span
127- key = { `char-${ index } ` }
128- className = { cn ( `text-white ` , word . className ) }
129- >
130- { char }
131- </ span >
132- ) ) }
133-
134- </ div >
135- ) ;
136- } ) }
137- </ div >
138- ) ;
139- } ;
101+ const wordsArray = useMemo ( ( ) => words . map ( ( word ) => ( {
102+ ...word ,
103+ text : word . text . split ( "" ) ,
104+ } ) ) , [ words ] ) ;
105+
106+ const renderWords = useCallback ( ( ) => (
107+ < div >
108+ { wordsArray . map ( ( word , idx ) => (
109+ < div key = { `word-${ idx } ` } className = "inline-block" >
110+ { word . text . map ( ( char , index ) => (
111+ < span
112+ key = { `char-${ index } ` }
113+ className = { cn ( `text-white` , word . className ) }
114+ >
115+ { char }
116+ </ span >
117+ ) ) }
118+
119+ </ div >
120+ ) ) }
121+ </ div >
122+ ) , [ wordsArray ] ) ;
140123
141124 return (
142125 < div className = { cn ( "flex space-x-1 my-6" , className ) } >
143126 < motion . div
144127 className = "overflow-hidden pb-2"
145- initial = { {
146- width : "0%" ,
147- } }
148- whileInView = { {
149- width : "fit-content" ,
150- } }
128+ initial = { { width : "0%" } }
129+ whileInView = { { width : "fit-content" } }
130+ viewport = { { once : true } }
151131 transition = { {
152132 duration : 2 ,
153133 ease : "linear" ,
@@ -156,33 +136,26 @@ export const TypewriterEffectSmooth = ({
156136 >
157137 < div
158138 className = "text-xs sm:text-base md:text-xl lg:text:3xl xl:text-5xl font-bold"
159- style = { {
160- whiteSpace : "nowrap" ,
161- } }
139+ style = { { whiteSpace : "nowrap" } }
162140 >
163- { renderWords ( ) } { " " }
164- </ div > { " " }
141+ { renderWords ( ) }
142+ </ div >
165143 </ motion . div >
166144 < motion . span
167- initial = { {
168- opacity : 0 ,
169- } }
170- animate = { {
171- opacity : 1 ,
172- } }
145+ initial = { { opacity : 0 } }
146+ animate = { { opacity : 1 } }
173147 transition = { {
174148 duration : 0.8 ,
175-
176149 repeat : Infinity ,
177150 repeatType : "reverse" ,
178151 } }
179152 className = { cn (
180153 "block rounded-sm w-[4px] h-5 sm:h-6 xl:h-12 bg-blue-500" ,
181154 cursorClassName
182155 ) }
183- > </ motion . span >
156+ / >
184157 </ div >
185158 ) ;
186- } ;
159+ } ) ;
187160
188- export default memo ( TypewriterEffect )
161+ export default memo ( TypewriterEffect ) ;
0 commit comments