diff --git a/showcase/src/patterns/index.js b/showcase/src/patterns/index.js
index 34fb644..4217c63 100644
--- a/showcase/src/patterns/index.js
+++ b/showcase/src/patterns/index.js
@@ -1,136 +1,147 @@
-import React, { Component, useState } from 'react'
+import React, { useState, useCallback, useLayoutEffect } from 'react'
+
import mojs from 'mo-js'
import { generateRandomNumber } from '../utils/generateRandomNumber'
import styles from './index.css'
/** ====================================
- * 🔰HOC
-Higher Order Component for Animation
-==================================== **/
-const withClapAnimation = WrappedComponent => {
- class WithClapAnimation extends Component {
- animationTimeline = new mojs.Timeline()
- state = {
- animationTimeline: this.animationTimeline
+ * 🔰Hook
+ Hook for Animation
+ ==================================== **/
+
+const useClapAnimation = ({
+ duration: tlDuration,
+ bounceEl,
+ fadeEl,
+ burstEl
+}) => {
+ const [animationTimeline, setAnimationTimeline] = useState(
+ new mojs.Timeline()
+ )
+
+ useLayoutEffect(() => {
+ if (!bounceEl || !fadeEl || !burstEl) {
+ return
}
- componentDidMount () {
- const tlDuration = 300
-
- const triangleBurst = new mojs.Burst({
- parent: '#clap',
- radius: { 50: 95 },
- count: 5,
- angle: 30,
- children: {
- shape: 'polygon',
- radius: { 6: 0 },
- scale: 1,
- stroke: 'rgba(211,84,0 ,0.5)',
- strokeWidth: 2,
- angle: 210,
- delay: 30,
- speed: 0.2,
- easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
- duration: tlDuration
- }
- })
-
- const circleBurst = new mojs.Burst({
- parent: '#clap',
- radius: { 50: 75 },
- angle: 25,
- duration: tlDuration,
- children: {
- shape: 'circle',
- fill: 'rgba(149,165,166 ,0.5)',
- delay: 30,
- speed: 0.2,
- radius: { 3: 0 },
- easing: mojs.easing.bezier(0.1, 1, 0.3, 1)
- }
- })
-
- const countAnimation = new mojs.Html({
- el: '#clapCount',
- isShowStart: false,
- isShowEnd: true,
- y: { 0: -30 },
- opacity: { 0: 1 },
+ const triangleBurst = new mojs.Burst({
+ parent: burstEl,
+ radius: { 50: 95 },
+ count: 5,
+ angle: 30,
+ children: {
+ shape: 'polygon',
+ radius: { 6: 0 },
+ scale: 1,
+ stroke: 'rgba(211,84,0 ,0.5)',
+ strokeWidth: 2,
+ angle: 210,
+ delay: 30,
+ speed: 0.2,
+ easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
duration: tlDuration
- }).then({
- opacity: { 1: 0 },
- y: -80,
- delay: tlDuration / 2
- })
-
- const countTotalAnimation = new mojs.Html({
- el: '#clapCountTotal',
- isShowStart: false,
- isShowEnd: true,
- opacity: { 0: 1 },
- delay: (3 * tlDuration) / 2,
- duration: tlDuration,
- y: { 0: -3 }
- })
-
- const scaleButton = new mojs.Html({
- el: '#clap',
- duration: tlDuration,
- scale: { 1.3: 1 },
- easing: mojs.easing.out
- })
-
- const clap = document.getElementById('clap')
- clap.style.transform = 'scale(1, 1)'
+ }
+ })
- const newAnimationTimeline = this.animationTimeline.add([
- countAnimation,
- countTotalAnimation,
- scaleButton,
- circleBurst,
- triangleBurst
- ])
- this.setState({ animationTimeline: newAnimationTimeline })
- }
+ const circleBurst = new mojs.Burst({
+ parent: burstEl,
+ radius: { 50: 75 },
+ angle: 25,
+ duration: tlDuration,
+ children: {
+ shape: 'circle',
+ fill: 'rgba(149,165,166 ,0.5)',
+ delay: 30,
+ speed: 0.2,
+ radius: { 3: 0 },
+ easing: mojs.easing.bezier(0.1, 1, 0.3, 1)
+ }
+ })
+
+ const countAnimation = new mojs.Html({
+ el: bounceEl,
+ isShowStart: false,
+ isShowEnd: true,
+ y: { 0: -30 },
+ opacity: { 0: 1 },
+ duration: tlDuration
+ }).then({
+ opacity: { 1: 0 },
+ y: -80,
+ delay: tlDuration / 2
+ })
+
+ const countTotalAnimation = new mojs.Html({
+ el: fadeEl,
+ isShowStart: false,
+ isShowEnd: true,
+ opacity: { 0: 1 },
+ delay: (3 * tlDuration) / 2,
+ duration: tlDuration,
+ y: { 0: -3 }
+ })
- render () {
- return (
-
- )
+ const scaleButton = new mojs.Html({
+ el: burstEl,
+ duration: tlDuration,
+ scale: { 1.3: 1 },
+ easing: mojs.easing.out
+ })
+
+ if (typeof burstEl === 'string') {
+ clap.style.transform = 'scale(1, 1)'
+ const el = document.getElementById(id)
+ el.style.transform = 'scale(1, 1)'
+ } else {
+ burstEl.style.transform = 'scale(1, 1)'
}
- }
- WithClapAnimation.displayName = `WithClapAnimation(${getDisplayName(
- WrappedComponent
- )})`
+ const updatedAnimationTimeline = animationTimeline.add([
+ countAnimation,
+ countTotalAnimation,
+ scaleButton,
+ circleBurst,
+ triangleBurst
+ ])
- return WithClapAnimation
-}
+ setAnimationTimeline(updatedAnimationTimeline)
+ }, [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl])
-function getDisplayName (WrappedComponent) {
- return WrappedComponent.displayName || WrappedComponent.name || 'Component'
+ return animationTimeline
}
-
/** ====================================
- * 🔰 MediumClap
-==================================== **/
+ * 🔰 MediumClap
+ ==================================== **/
const initialState = {
count: 0,
countTotal: generateRandomNumber(500, 10000),
isClicked: false
}
-const MediumClap = ({ animationTimeline }) => {
+const MediumClap = () => {
const MAXIMUM_USER_CLAP = 50
const [clapState, setClapState] = useState(initialState)
const { count, countTotal, isClicked } = clapState
+ const [{ clapRef, clapCountRef, clapTotalRef }, setRefState] = useState({})
+
+ const setRef = useCallback(node => {
+ if (node !== null) {
+ setRefState(prevRefState => ({
+ ...prevRefState,
+ [node.dataset.refkey]: node
+ }))
+ }
+ }, [])
+
+ const animationTimeline = useClapAnimation({
+ duration: 300,
+ bounceEl: clapCountRef,
+ fadeEl: clapTotalRef,
+ burstEl: clapRef
+ })
+
const handleClapClick = () => {
- // 👉 prop from HOC
animationTimeline.replay()
setClapState({
@@ -141,18 +152,23 @@ const MediumClap = ({ animationTimeline }) => {
}
return (
-