11import React , {
22 useState ,
3+ useCallback ,
34 useEffect ,
5+ useLayoutEffect ,
46 useContext ,
5- useMemo ,
67 useRef ,
8+ useMemo ,
79 createContext
810} from 'react'
911
@@ -13,102 +15,113 @@ import { generateRandomNumber } from '../utils/generateRandomNumber'
1315import styles from './index.css'
1416
1517/** ====================================
16- * 🔰Hook
17- Hook for Animation
18- ==================================== **/
18+ * 🔰Hook
19+ Hook for Animation
20+ ==================================== **/
1921
20- const useClapAnimation = ( { duration : tlDuration } ) => {
22+ const useClapAnimation = ( {
23+ duration : tlDuration ,
24+ bounceEl,
25+ fadeEl,
26+ burstEl
27+ } ) => {
2128 const [ animationTimeline , setAnimationTimeline ] = useState (
2229 new mojs . Timeline ( )
2330 )
2431
25- useEffect (
26- ( ) => {
27- const triangleBurst = new mojs . Burst ( {
28- parent : '#clap' ,
29- radius : { 50 : 95 } ,
30- count : 5 ,
31- angle : 30 ,
32- children : {
33- shape : 'polygon' ,
34- radius : { 6 : 0 } ,
35- scale : 1 ,
36- stroke : 'rgba(211,84,0 ,0.5)' ,
37- strokeWidth : 2 ,
38- angle : 210 ,
39- delay : 30 ,
40- speed : 0.2 ,
41- easing : mojs . easing . bezier ( 0.1 , 1 , 0.3 , 1 ) ,
42- duration : tlDuration
43- }
44- } )
45-
46- const circleBurst = new mojs . Burst ( {
47- parent : '#clap' ,
48- radius : { 50 : 75 } ,
49- angle : 25 ,
50- duration : tlDuration ,
51- children : {
52- shape : 'circle' ,
53- fill : 'rgba(149,165,166 ,0.5)' ,
54- delay : 30 ,
55- speed : 0.2 ,
56- radius : { 3 : 0 } ,
57- easing : mojs . easing . bezier ( 0.1 , 1 , 0.3 , 1 )
58- }
59- } )
60-
61- const countAnimation = new mojs . Html ( {
62- el : '#clapCount' ,
63- isShowStart : false ,
64- isShowEnd : true ,
65- y : { 0 : - 30 } ,
66- opacity : { 0 : 1 } ,
32+ useLayoutEffect ( ( ) => {
33+ if ( ! bounceEl || ! fadeEl || ! burstEl ) {
34+ return
35+ }
36+
37+ const triangleBurst = new mojs . Burst ( {
38+ parent : burstEl ,
39+ radius : { 50 : 95 } ,
40+ count : 5 ,
41+ angle : 30 ,
42+ children : {
43+ shape : 'polygon' ,
44+ radius : { 6 : 0 } ,
45+ scale : 1 ,
46+ stroke : 'rgba(211,84,0 ,0.5)' ,
47+ strokeWidth : 2 ,
48+ angle : 210 ,
49+ delay : 30 ,
50+ speed : 0.2 ,
51+ easing : mojs . easing . bezier ( 0.1 , 1 , 0.3 , 1 ) ,
6752 duration : tlDuration
68- } ) . then ( {
69- opacity : { 1 : 0 } ,
70- y : - 80 ,
71- delay : tlDuration / 2
72- } )
73-
74- const countTotalAnimation = new mojs . Html ( {
75- el : '#clapCountTotal' ,
76- isShowStart : false ,
77- isShowEnd : true ,
78- opacity : { 0 : 1 } ,
79- delay : ( 3 * tlDuration ) / 2 ,
80- duration : tlDuration ,
81- y : { 0 : - 3 }
82- } )
83-
84- const scaleButton = new mojs . Html ( {
85- el : '#clap' ,
86- duration : tlDuration ,
87- scale : { 1.3 : 1 } ,
88- easing : mojs . easing . out
89- } )
90-
91- const clap = document . getElementById ( 'clap' )
53+ }
54+ } )
55+
56+ const circleBurst = new mojs . Burst ( {
57+ parent : burstEl ,
58+ radius : { 50 : 75 } ,
59+ angle : 25 ,
60+ duration : tlDuration ,
61+ children : {
62+ shape : 'circle' ,
63+ fill : 'rgba(149,165,166 ,0.5)' ,
64+ delay : 30 ,
65+ speed : 0.2 ,
66+ radius : { 3 : 0 } ,
67+ easing : mojs . easing . bezier ( 0.1 , 1 , 0.3 , 1 )
68+ }
69+ } )
70+
71+ const countAnimation = new mojs . Html ( {
72+ el : bounceEl ,
73+ isShowStart : false ,
74+ isShowEnd : true ,
75+ y : { 0 : - 30 } ,
76+ opacity : { 0 : 1 } ,
77+ duration : tlDuration
78+ } ) . then ( {
79+ opacity : { 1 : 0 } ,
80+ y : - 80 ,
81+ delay : tlDuration / 2
82+ } )
83+
84+ const countTotalAnimation = new mojs . Html ( {
85+ el : fadeEl ,
86+ isShowStart : false ,
87+ isShowEnd : true ,
88+ opacity : { 0 : 1 } ,
89+ delay : ( 3 * tlDuration ) / 2 ,
90+ duration : tlDuration ,
91+ y : { 0 : - 3 }
92+ } )
93+
94+ const scaleButton = new mojs . Html ( {
95+ el : burstEl ,
96+ duration : tlDuration ,
97+ scale : { 1.3 : 1 } ,
98+ easing : mojs . easing . out
99+ } )
100+
101+ if ( typeof burstEl === 'string' ) {
92102 clap . style . transform = 'scale(1, 1)'
103+ const el = document . getElementById ( id )
104+ el . style . transform = 'scale(1, 1)'
105+ } else {
106+ burstEl . style . transform = 'scale(1, 1)'
107+ }
93108
94- const updatedAnimationTimeline = animationTimeline . add ( [
95- countAnimation ,
96- countTotalAnimation ,
97- scaleButton ,
98- circleBurst ,
99- triangleBurst
100- ] )
101-
102- setAnimationTimeline ( updatedAnimationTimeline )
103- } ,
104- [ tlDuration , animationTimeline ]
105- )
109+ const updatedAnimationTimeline = animationTimeline . add ( [
110+ countAnimation ,
111+ countTotalAnimation ,
112+ scaleButton ,
113+ circleBurst ,
114+ triangleBurst
115+ ] )
116+
117+ setAnimationTimeline ( updatedAnimationTimeline )
118+ } , [ tlDuration , animationTimeline , bounceEl , fadeEl , burstEl ] )
106119
107120 return animationTimeline
108121}
109122/** ====================================
110- * 🔰 MediumClap
111- ==================================== **/
123+ * 🔰 MediumClap
124+ ==================================== **/
112125const initialState = {
113126 count : 0 ,
114127 countTotal : generateRandomNumber ( 500 , 10000 ) ,
@@ -123,7 +136,24 @@ const MediumClap = ({ children, onClap }) => {
123136 const [ clapState , setClapState ] = useState ( initialState )
124137 const { count, countTotal, isClicked } = clapState
125138
126- const animationTimeline = useClapAnimation ( { duration : 300 } )
139+ const [ { clapRef, clapCountRef, clapTotalRef } , setRefState ] = useState ( { } )
140+
141+ const setRef = useCallback ( node => {
142+ if ( node !== null ) {
143+ setRefState ( prevRefState => ( {
144+ ...prevRefState ,
145+ [ node . dataset . refkey ] : node
146+ } ) )
147+ }
148+ } , [ ] )
149+
150+ const animationTimeline = useClapAnimation ( {
151+ duration : 300 ,
152+ bounceEl : clapCountRef ,
153+ fadeEl : clapTotalRef ,
154+ burstEl : clapRef
155+ } )
156+
127157 const handleClapClick = ( ) => {
128158 // 👉 prop from HOC
129159 animationTimeline . replay ( )
@@ -137,38 +167,41 @@ const MediumClap = ({ children, onClap }) => {
137167
138168 const componentJustMounted = useRef ( true )
139169
140- useEffect (
141- ( ) => {
142- if ( ! componentJustMounted . current ) {
143- onClap ( clapState )
144- }
145- componentJustMounted . current = false
146- } ,
147- [ count , onClap ]
148- )
170+ useEffect ( ( ) => {
171+ if ( ! componentJustMounted . current ) {
172+ onClap ( clapState )
173+ }
174+ componentJustMounted . current = false
175+ } , [ count , onClap ] )
149176
150177 const memoizedValue = useMemo (
151178 ( ) => ( {
152179 count,
153180 countTotal,
154- isClicked
181+ isClicked,
182+ setRef
155183 } ) ,
156- [ count , countTotal , isClicked ]
184+ [ count , countTotal , isClicked , setRef ]
157185 )
158186
159187 return (
160188 < Provider value = { memoizedValue } >
161- < button id = 'clap' className = { styles . clap } onClick = { handleClapClick } >
189+ < button
190+ ref = { setRef }
191+ data-refkey = 'clapRef'
192+ className = { styles . clap }
193+ onClick = { handleClapClick }
194+ >
162195 { children }
163196 </ button >
164197 </ Provider >
165198 )
166199}
167200
168201/** ====================================
169- * 🔰SubComponents
170- Smaller Component used by <MediumClap />
171- ==================================== **/
202+ * 🔰SubComponents
203+ Smaller Component used by <MediumClap />
204+ ==================================== **/
172205
173206const ClapIcon = ( ) => {
174207 const { isClicked } = useContext ( MediumClapContext )
@@ -187,17 +220,17 @@ const ClapIcon = () => {
187220 )
188221}
189222const ClapCount = ( ) => {
190- const { count } = useContext ( MediumClapContext )
223+ const { count, setRef } = useContext ( MediumClapContext )
191224 return (
192- < span id = 'clapCount ' className = { styles . count } >
225+ < span ref = { setRef } data-refkey = 'clapCountRef ' className = { styles . count } >
193226 +{ count }
194227 </ span >
195228 )
196229}
197230const CountTotal = ( ) => {
198- const { countTotal } = useContext ( MediumClapContext )
231+ const { countTotal, setRef } = useContext ( MediumClapContext )
199232 return (
200- < span id = 'clapCountTotal ' className = { styles . total } >
233+ < span ref = { setRef } data-refkey = 'clapTotalRef ' className = { styles . total } >
201234 { countTotal }
202235 </ span >
203236 )
@@ -218,10 +251,10 @@ MediumClap.Total = CountTotal
218251MediumClap . Info = ClapInfo
219252
220253/** ====================================
221- * 🔰USAGE
222- Below's how a potential user
223- may consume the component API
224- ==================================== **/
254+ * 🔰USAGE
255+ Below's how a potential user
256+ may consume the component API
257+ ==================================== **/
225258
226259const Usage = ( ) => {
227260 const [ total , setTotal ] = useState ( 0 )
0 commit comments