From 37423602bb43843d2b6c213cbc556901adc4dfef Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: 2019年12月18日 06:20:22 +0100 Subject: [PATCH 1/6] cleanups --- showcase/src/constants/displayBoxNotes.js | 5 +- showcase/src/patterns/02.js | 241 ------------ showcase/src/patterns/03.js | 243 ------------ showcase/src/patterns/04.js | 309 ---------------- showcase/src/patterns/05.js | 342 ----------------- showcase/src/patterns/06.js | 409 --------------------- showcase/src/patterns/07.js | 323 ---------------- showcase/src/patterns/08.js | 345 ----------------- showcase/src/patterns/09.js | 400 -------------------- showcase/src/patterns/10.js | 427 ---------------------- 10 files changed, 1 insertion(+), 3043 deletions(-) delete mode 100644 showcase/src/patterns/02.js delete mode 100644 showcase/src/patterns/03.js delete mode 100644 showcase/src/patterns/04.js delete mode 100644 showcase/src/patterns/05.js delete mode 100644 showcase/src/patterns/06.js delete mode 100644 showcase/src/patterns/07.js delete mode 100644 showcase/src/patterns/08.js delete mode 100644 showcase/src/patterns/09.js delete mode 100644 showcase/src/patterns/10.js diff --git a/showcase/src/constants/displayBoxNotes.js b/showcase/src/constants/displayBoxNotes.js index 6553856..61c4eb1 100644 --- a/showcase/src/constants/displayBoxNotes.js +++ b/showcase/src/constants/displayBoxNotes.js @@ -1,4 +1 @@ -export const NOTES = { - '1': 'Animated via an HOC', - '2': 'Animated via a hook 💪' -} +export const NOTES = {} diff --git a/showcase/src/patterns/02.js b/showcase/src/patterns/02.js deleted file mode 100644 index fb18d7d..0000000 --- a/showcase/src/patterns/02.js +++ /dev/null @@ -1,241 +0,0 @@ -import React, { - useState, - useCallback, - useLayoutEffect, - useContext, - useMemo, - createContext -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - 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)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap - ==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ children }) => { - 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 = () => { - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const memoizedValue = useMemo( - () => ({ - count, - countTotal, - isClicked, - setRef - }), - [count, countTotal, isClicked, setRef] - ) - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapIcon = () => { - const { isClicked } = useContext(MediumClapContext) - return ( - - - - - - - ) -} -const ClapCount = () => { - const { count, setRef } = useContext(MediumClapContext) - return ( - - +{count} - - ) -} -const CountTotal = () => { - const { countTotal, setRef } = useContext(MediumClapContext) - return ( - - {countTotal} - - ) -} - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const Usage = () => { - return -} - -export default Usage diff --git a/showcase/src/patterns/03.js b/showcase/src/patterns/03.js deleted file mode 100644 index 2809f8f..0000000 --- a/showcase/src/patterns/03.js +++ /dev/null @@ -1,243 +0,0 @@ -import React, { - useState, - useEffect, - useContext, - useMemo, - useRef, - createContext -} from 'react' - -import mojs from 'mo-js' -import wordConverter from 'number-to-words' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' - -/** ==================================== - * 🔰Hook - Hook for Animation -==================================== **/ - -const useClapAnimation = ({ duration: tlDuration }) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useEffect( - () => { - 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 }, - 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 updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap -==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ children, onClap }) => { - const MAXIMUM_USER_CLAP = 50 - const [clapState, setClapState] = useState(initialState) - const { count, countTotal, isClicked } = clapState - - const animationTimeline = useClapAnimation({ duration: 300 }) - const handleClapClick = () => { - // 👉 prop from HOC - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const componentJustMounted = useRef(true) - - useEffect( - () => { - if (!componentJustMounted.current) { - onClap(clapState) - } - componentJustMounted.current = false - }, - [count, onClap] - ) - - const memoizedValue = useMemo( - () => ({ - count, - countTotal, - isClicked - }), - [count, countTotal, isClicked] - ) - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents -Smaller Component used by -==================================== **/ - -const ClapIcon = () => { - const { isClicked } = useContext(MediumClapContext) - return ( - - - - - - - ) -} -const ClapCount = () => { - const { count } = useContext(MediumClapContext) - return ( - - +{count} - - ) -} -const CountTotal = () => { - const { countTotal } = useContext(MediumClapContext) - return ( - - {countTotal} - - ) -} - -const ClapInfo = ({ info }) => { - const { countTotal } = useContext(MediumClapContext) - return ( -
- {info || wordConverter.toWords(countTotal)} claps! -
- ) -} - -MediumClap.Icon = ClapIcon -MediumClap.Count = ClapCount -MediumClap.Total = CountTotal -MediumClap.Info = ClapInfo - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API -==================================== **/ - -const Usage = () => { - const [total, setTotal] = useState(0) - - const onClap = ({ countTotal }) => { - setTotal(countTotal) - } - - return ( - - - - - - - ) -} - -export default Usage diff --git a/showcase/src/patterns/04.js b/showcase/src/patterns/04.js deleted file mode 100644 index 4dabdcc..0000000 --- a/showcase/src/patterns/04.js +++ /dev/null @@ -1,309 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - useContext, - useMemo, - useRef, - createContext -} from 'react' - -import mojs from 'mo-js' -import wordConverter from 'number-to-words' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation -==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - 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)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap -==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ - children, - onClap, - className = '', - style: userStyles = {} -}) => { - 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 = () => { - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const componentJustMounted = useRef(true) - - useEffect( - () => { - if (!componentJustMounted.current) { - onClap(clapState) - } - componentJustMounted.current = false - }, - [count, onClap] - ) - - const memoizedValue = useMemo( - () => ({ - count, - countTotal, - isClicked, - setRef - }), - [count, countTotal, isClicked, setRef] - ) - - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents -Smaller Component used by -==================================== **/ - -const ClapIcon = ({ className = '', style: userStyles = {} }) => { - const { isClicked } = useContext(MediumClapContext) - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} -const ClapCount = ({ className = '', style: userStyles = {} }) => { - const { count, setRef } = useContext(MediumClapContext) - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) -} -const CountTotal = ({ className = '', style: userStyles = {} }) => { - const { countTotal, setRef } = useContext(MediumClapContext) - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) -} - -const ClapInfo = ({ info }) => { - const { countTotal } = useContext(MediumClapContext) - return ( -
- {info || wordConverter.toWords(countTotal)} claps! -
- ) -} - -MediumClap.Icon = ClapIcon -MediumClap.Count = ClapCount -MediumClap.Total = CountTotal -MediumClap.Info = ClapInfo - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API -==================================== **/ - -const Usage = () => { - const [total, setTotal] = useState(0) - - const onClap = ({ countTotal }) => { - setTotal(countTotal) - } - - return ( - - - - - - - ) -} - -export default Usage diff --git a/showcase/src/patterns/05.js b/showcase/src/patterns/05.js deleted file mode 100644 index 09737b7..0000000 --- a/showcase/src/patterns/05.js +++ /dev/null @@ -1,342 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - useContext, - useMemo, - useRef, - createContext -} from 'react' - -import mojs from 'mo-js' -import wordConverter from 'number-to-words' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap - ==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ - children, - onClap = () => {}, - values = null, - className = '', - style: userStyles = {} -}) => { - 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 - }) - - // Controlled Component ? isControlled = value !== undefined - const isControlled = !!values - - const handleClapClick = () => { - // 👉 prop from HOC - animationTimeline.replay() - isControlled - ? onClap() - : setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const componentJustMounted = useRef(true) - - useEffect( - () => { - if (!componentJustMounted.current && !isControlled) { - onClap(clapState) - } - componentJustMounted.current = false - }, - [count, onClap, isControlled] - ) - - const getState = useCallback(() => (isControlled ? values : clapState), [ - isControlled, - clapState, - values - ]) - - const memoizedValue = useMemo( - () => { - return { - ...getState(), - setRef - } - }, - [getState, setRef] - ) - - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapIcon = ({ className = '', style: userStyles = {} }) => { - const { isClicked } = useContext(MediumClapContext) - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} -const ClapCount = ({ className = '', style: userStyles = {} }) => { - const { count, setRef } = useContext(MediumClapContext) - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) -} -const CountTotal = ({ className = '', style: userStyles = {} }) => { - const { countTotal, setRef } = useContext(MediumClapContext) - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) -} - -const ClapInfo = ({ info }) => { - const { countTotal } = useContext(MediumClapContext) - return ( -
- {info || wordConverter.toWords(countTotal)} claps! -
- ) -} - -MediumClap.Icon = ClapIcon -MediumClap.Count = ClapCount -MediumClap.Total = CountTotal -MediumClap.Info = ClapInfo - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const MAXIMUM_USER_CLAP = 10 -const INITIAL_STATE = { - count: 0, - countTotal: 1206, - isClicked: false -} - -const Usage = () => { - const [clapValues, setClapValues] = useState(INITIAL_STATE) - - const onClap = () => { - setClapValues(({ count, countTotal }) => ({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - })) - } - - return ( -
- - - - - - - - - - - -
- ) -} - -export default Usage diff --git a/showcase/src/patterns/06.js b/showcase/src/patterns/06.js deleted file mode 100644 index 6e745df..0000000 --- a/showcase/src/patterns/06.js +++ /dev/null @@ -1,409 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef - } from 'react' - - import mojs from 'mo-js' - import { generateRandomNumber } from '../utils/generateRandomNumber' - import styles from './index.css' - import userStyles from './usage.css' - - /** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - - const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl - }) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline - } - - /** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ - const MAX_CLAP = 50 - const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false - } - - const useClapState = ({ initialState = INIT_STATE } = {}) => { - const [clapState, setClapState] = useState(initialState) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - return { - clapState, - handleClapClick - } - } - - /** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - - function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) - } - - /** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ - const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] - } - - /** ==================================== - * 🔰 MediumClap - ==================================== **/ - - const MediumClap = () => { - const { clapState, handleClapClick } = useClapState() - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - useEffectAfterMount( - () => { - animationTimeline.replay() - }, - [count] - ) - - return ( - - - - - - ) - } - - /** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - - const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } - ) - - const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) - } - - const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } - ) - - const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } - ) - - /** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - - const CupBowl = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const CupHandle = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const Stream = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const CupBase = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const Usage = () => { - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: '#stream', - fadeEl: '#cupHandle', - burstEl: '#coffee' - }) - - const handleClick = () => { - animationTimeline.replay() - } - - return ( -
-
- -
-
- coffee -
-
- - -
-
- -
-
- -
-
- ) - } - - export default Usage \ No newline at end of file diff --git a/showcase/src/patterns/07.js b/showcase/src/patterns/07.js deleted file mode 100644 index e1ea07e..0000000 --- a/showcase/src/patterns/07.js +++ /dev/null @@ -1,323 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} - -/** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ -const MAX_CLAP = 50 -const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const useClapState = ({ initialState = INIT_STATE } = {}) => { - const [clapState, setClapState] = useState(initialState) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - const togglerProps = { - onClick: handleClapClick, - 'aria-pressed': clapState.isClicked - } - - const counterProps = { - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count - } - - return { - clapState, - togglerProps, - counterProps - } -} - -/** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - -function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) -} - -/** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ -const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } -) - -const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} - -const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } -) - -const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } -) - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const Usage = () => { - const { clapState, togglerProps, counterProps } = useClapState() - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - useEffectAfterMount( - () => { - animationTimeline.replay() - }, - [count] - ) - - return ( - - - - - - ) -} - -export default Usage diff --git a/showcase/src/patterns/08.js b/showcase/src/patterns/08.js deleted file mode 100644 index be75d84..0000000 --- a/showcase/src/patterns/08.js +++ /dev/null @@ -1,345 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} - -/** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ -const MAX_CLAP = 50 -const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const callFnsInSequence = (...fns) => (...args) => - fns.forEach(fn => fn && fn(...args)) - -const useClapState = ({ initialState = INIT_STATE } = {}) => { - const [clapState, setClapState] = useState(initialState) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - const getTogglerProps = ({ onClick, ...otherProps } = {}) => ({ - onClick: callFnsInSequence(handleClapClick, onClick), - 'aria-pressed': clapState.isClicked, - ...otherProps - }) - - const getCounterProps = ({ ...otherProps }) => ({ - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count, - ...otherProps - }) - - return { - clapState, - getTogglerProps, - getCounterProps - } -} - -/** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - -function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) -} - -/** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ -const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } -) - -const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} - -const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } -) - -const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } -) - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const Usage = () => { - const { clapState, getTogglerProps, getCounterProps } = useClapState() - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - const onClick = () => { - animationTimeline.replay() - } - - return ( -
- - - - - -
- {!isClicked ? 'No recommendations :(' : `Recommended ${count} times 🔥`} -
-
- ) -} - -export default Usage diff --git a/showcase/src/patterns/09.js b/showcase/src/patterns/09.js deleted file mode 100644 index b515497..0000000 --- a/showcase/src/patterns/09.js +++ /dev/null @@ -1,400 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Holding Previous Vals - ==================================== **/ -function usePrevious (value) { - const ref = useRef() - useEffect(() => { - ref.current = value - }) - return ref.current === undefined ? null : ref.current -} - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} - -/** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ -const MAX_CLAP = 50 -const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const callFnsInSequence = (...fns) => (...args) => - fns.forEach(fn => fn && fn(...args)) - -const useClapState = ({ initialState = INIT_STATE } = {}) => { - const initialStateRef = useRef(initialState) - const [clapState, setClapState] = useState(initialStateRef.current) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - const resetRef = useRef(0) - // reset only if there's a change. It's possible to check changes to other state values e.g. countTotal & isClicked - const prevCount = usePrevious(count) - const reset = useCallback( - () => { - if (prevCount !== count) { - setClapState(initialStateRef.current) - ++resetRef.current - } - }, - [prevCount, count] - ) - - const getTogglerProps = ({ onClick, ...otherProps } = {}) => ({ - onClick: callFnsInSequence(handleClapClick, onClick), - 'aria-pressed': clapState.isClicked, - ...otherProps - }) - - const getCounterProps = ({ ...otherProps }) => ({ - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count, - ...otherProps - }) - - return { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep: resetRef.current - } -} - -/** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - -function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) -} - -/** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ -const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } -) - -const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} - -const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } -) - -const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } -) - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const initialState = { count: 10, countTotal: 22, isClicked: false } -const Usage = () => { - const { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep - } = useClapState({ initialState }) - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - const onClick = () => { - animationTimeline.replay() - } - - // Side effect after reset has occured. - const [uploadingReset, setUpload] = useState(false) - useEffectAfterMount( - () => { - setUpload(true) - - const id = setTimeout(() => { - setUpload(false) - console.log('RESET COMPLETE!!!') - }, 3000) - - return () => clearTimeout(id) - }, - [resetDep] - ) - - return ( -
- - - - - -
- -
- {JSON.stringify({ count, countTotal, isClicked })}
- 
-
- {uploadingReset ? `uploading reset ${resetDep}...` : ''}
- 
-
-
- ) -} - -export default Usage diff --git a/showcase/src/patterns/10.js b/showcase/src/patterns/10.js deleted file mode 100644 index a2ffb36..0000000 --- a/showcase/src/patterns/10.js +++ /dev/null @@ -1,427 +0,0 @@ -import React, { - useReducer, - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef - } from 'react' - - import mojs from 'mo-js' - import { generateRandomNumber } from '../utils/generateRandomNumber' - import styles from './index.css' - import userStyles from './usage.css' - - /** ==================================== - * 🔰Hook - Hook for Holding Previous Vals - ==================================== **/ - function usePrevious (value) { - const ref = useRef() - useEffect(() => { - ref.current = value - }) - return ref.current === undefined ? null : ref.current - } - - /** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - - const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl - }) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline - } - - /** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ - const MAX_CLAP = 50 - const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false - } - - const callFnsInSequence = (...fns) => (...args) => - fns.forEach(fn => fn && fn(...args)) - - const clapReducer = (state, { type, payload }) => { - const { count, countTotal } = state - - switch (type) { - case useClapState.types.clap: - return { - count: count + 1, - countTotal: countTotal + 1, - isClicked: true - } - case useClapState.types.reset: - return payload - default: - return state - } - } - - const useClapState = ({ - initialState = INIT_STATE, - reducer = clapReducer - } = {}) => { - const initialStateRef = useRef(initialState) - const [clapState, dispatch] = useReducer(reducer, initialStateRef.current) - const { count } = clapState - - const handleClapClick = () => dispatch({ type: 'clap' }) - - const resetRef = useRef(0) - // reset only if there's a change. It's possible to check changes to other state values e.g. countTotal & isClicked - const reset = useCallback(() => { - dispatch({ type: 'reset', payload: initialStateRef.current }) - ++resetRef.current - }, []) - - const getTogglerProps = ({ onClick, ...otherProps } = {}) => ({ - onClick: callFnsInSequence(handleClapClick, onClick), - 'aria-pressed': clapState.isClicked, - ...otherProps - }) - - const getCounterProps = ({ ...otherProps }) => ({ - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count, - ...otherProps - }) - - return { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep: resetRef.current - } - } - - useClapState.reducer = clapReducer - useClapState.types = { - clap: 'clap', - reset: 'reset' - } - - /** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - - function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) - } - - /** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ - const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] - } - - /** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - - const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } - ) - - const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) - } - - const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } - ) - - const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } - ) - - /** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - - const initialState = { count: 10, countTotal: 22, isClicked: false } - const Usage = () => { - const [timesClapped, setTimeClapped] = useState(0) - const clappedTooMuch = timesClapped>= 7 - - const reducer = (state, action) => { - if (action.type === useClapState.types.clap && clappedTooMuch) { - return state - } - return useClapState.reducer(state, action) - } - - const { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep - } = useClapState({ initialState, reducer }) - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - const onClick = () => { - setTimeClapped(t => t + 1) - !clappedTooMuch && animationTimeline.replay() - } - - // Side effect after reset has occured. - const [uploadingReset, setUpload] = useState(false) - useEffectAfterMount( - () => { - setTimeClapped(0) - setUpload(true) - - const id = setTimeout(() => { - setUpload(false) - console.log('RESET COMPLETE!!!') - }, 3000) - - return () => clearTimeout(id) - }, - [resetDep] - ) - - return ( -
- - - - - -
- -
- {JSON.stringify({ timesClapped, count, countTotal })}
- 
-
- {uploadingReset ? `uploading reset ${resetDep}...` : ''}
- 
-
-
- {clappedTooMuch ? `You clapped too much. Don't be so generous!` : ''}
- 
-
- ) - } - - export default Usage \ No newline at end of file From 425ab0415557da06b2fd305a48d1fd00dba09efa Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: 2019年12月18日 06:20:22 +0100 Subject: [PATCH 2/6] cleanups --- showcase/src/constants/displayBoxNotes.js | 5 +- showcase/src/patterns/02.js | 241 ------------ showcase/src/patterns/03.js | 243 ------------ showcase/src/patterns/04.js | 309 ---------------- showcase/src/patterns/05.js | 342 ----------------- showcase/src/patterns/06.js | 409 --------------------- showcase/src/patterns/07.js | 323 ---------------- showcase/src/patterns/08.js | 345 ----------------- showcase/src/patterns/09.js | 400 -------------------- showcase/src/patterns/10.js | 427 ---------------------- 10 files changed, 1 insertion(+), 3043 deletions(-) delete mode 100644 showcase/src/patterns/02.js delete mode 100644 showcase/src/patterns/03.js delete mode 100644 showcase/src/patterns/04.js delete mode 100644 showcase/src/patterns/05.js delete mode 100644 showcase/src/patterns/06.js delete mode 100644 showcase/src/patterns/07.js delete mode 100644 showcase/src/patterns/08.js delete mode 100644 showcase/src/patterns/09.js delete mode 100644 showcase/src/patterns/10.js diff --git a/showcase/src/constants/displayBoxNotes.js b/showcase/src/constants/displayBoxNotes.js index 6553856..61c4eb1 100644 --- a/showcase/src/constants/displayBoxNotes.js +++ b/showcase/src/constants/displayBoxNotes.js @@ -1,4 +1 @@ -export const NOTES = { - '1': 'Animated via an HOC', - '2': 'Animated via a hook 💪' -} +export const NOTES = {} diff --git a/showcase/src/patterns/02.js b/showcase/src/patterns/02.js deleted file mode 100644 index fb18d7d..0000000 --- a/showcase/src/patterns/02.js +++ /dev/null @@ -1,241 +0,0 @@ -import React, { - useState, - useCallback, - useLayoutEffect, - useContext, - useMemo, - createContext -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - 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)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap - ==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ children }) => { - 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 = () => { - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const memoizedValue = useMemo( - () => ({ - count, - countTotal, - isClicked, - setRef - }), - [count, countTotal, isClicked, setRef] - ) - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapIcon = () => { - const { isClicked } = useContext(MediumClapContext) - return ( - - - - - - - ) -} -const ClapCount = () => { - const { count, setRef } = useContext(MediumClapContext) - return ( - - +{count} - - ) -} -const CountTotal = () => { - const { countTotal, setRef } = useContext(MediumClapContext) - return ( - - {countTotal} - - ) -} - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const Usage = () => { - return -} - -export default Usage diff --git a/showcase/src/patterns/03.js b/showcase/src/patterns/03.js deleted file mode 100644 index 2809f8f..0000000 --- a/showcase/src/patterns/03.js +++ /dev/null @@ -1,243 +0,0 @@ -import React, { - useState, - useEffect, - useContext, - useMemo, - useRef, - createContext -} from 'react' - -import mojs from 'mo-js' -import wordConverter from 'number-to-words' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' - -/** ==================================== - * 🔰Hook - Hook for Animation -==================================== **/ - -const useClapAnimation = ({ duration: tlDuration }) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useEffect( - () => { - 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 }, - 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 updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap -==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ children, onClap }) => { - const MAXIMUM_USER_CLAP = 50 - const [clapState, setClapState] = useState(initialState) - const { count, countTotal, isClicked } = clapState - - const animationTimeline = useClapAnimation({ duration: 300 }) - const handleClapClick = () => { - // 👉 prop from HOC - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const componentJustMounted = useRef(true) - - useEffect( - () => { - if (!componentJustMounted.current) { - onClap(clapState) - } - componentJustMounted.current = false - }, - [count, onClap] - ) - - const memoizedValue = useMemo( - () => ({ - count, - countTotal, - isClicked - }), - [count, countTotal, isClicked] - ) - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents -Smaller Component used by -==================================== **/ - -const ClapIcon = () => { - const { isClicked } = useContext(MediumClapContext) - return ( - - - - - - - ) -} -const ClapCount = () => { - const { count } = useContext(MediumClapContext) - return ( - - +{count} - - ) -} -const CountTotal = () => { - const { countTotal } = useContext(MediumClapContext) - return ( - - {countTotal} - - ) -} - -const ClapInfo = ({ info }) => { - const { countTotal } = useContext(MediumClapContext) - return ( -
- {info || wordConverter.toWords(countTotal)} claps! -
- ) -} - -MediumClap.Icon = ClapIcon -MediumClap.Count = ClapCount -MediumClap.Total = CountTotal -MediumClap.Info = ClapInfo - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API -==================================== **/ - -const Usage = () => { - const [total, setTotal] = useState(0) - - const onClap = ({ countTotal }) => { - setTotal(countTotal) - } - - return ( - - - - - - - ) -} - -export default Usage diff --git a/showcase/src/patterns/04.js b/showcase/src/patterns/04.js deleted file mode 100644 index 4dabdcc..0000000 --- a/showcase/src/patterns/04.js +++ /dev/null @@ -1,309 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - useContext, - useMemo, - useRef, - createContext -} from 'react' - -import mojs from 'mo-js' -import wordConverter from 'number-to-words' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation -==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - 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)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap -==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ - children, - onClap, - className = '', - style: userStyles = {} -}) => { - 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 = () => { - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const componentJustMounted = useRef(true) - - useEffect( - () => { - if (!componentJustMounted.current) { - onClap(clapState) - } - componentJustMounted.current = false - }, - [count, onClap] - ) - - const memoizedValue = useMemo( - () => ({ - count, - countTotal, - isClicked, - setRef - }), - [count, countTotal, isClicked, setRef] - ) - - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents -Smaller Component used by -==================================== **/ - -const ClapIcon = ({ className = '', style: userStyles = {} }) => { - const { isClicked } = useContext(MediumClapContext) - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} -const ClapCount = ({ className = '', style: userStyles = {} }) => { - const { count, setRef } = useContext(MediumClapContext) - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) -} -const CountTotal = ({ className = '', style: userStyles = {} }) => { - const { countTotal, setRef } = useContext(MediumClapContext) - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) -} - -const ClapInfo = ({ info }) => { - const { countTotal } = useContext(MediumClapContext) - return ( -
- {info || wordConverter.toWords(countTotal)} claps! -
- ) -} - -MediumClap.Icon = ClapIcon -MediumClap.Count = ClapCount -MediumClap.Total = CountTotal -MediumClap.Info = ClapInfo - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API -==================================== **/ - -const Usage = () => { - const [total, setTotal] = useState(0) - - const onClap = ({ countTotal }) => { - setTotal(countTotal) - } - - return ( - - - - - - - ) -} - -export default Usage diff --git a/showcase/src/patterns/05.js b/showcase/src/patterns/05.js deleted file mode 100644 index 09737b7..0000000 --- a/showcase/src/patterns/05.js +++ /dev/null @@ -1,342 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - useContext, - useMemo, - useRef, - createContext -} from 'react' - -import mojs from 'mo-js' -import wordConverter from 'number-to-words' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} -/** ==================================== - * 🔰 MediumClap - ==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClapContext = createContext() -const { Provider } = MediumClapContext - -const MediumClap = ({ - children, - onClap = () => {}, - values = null, - className = '', - style: userStyles = {} -}) => { - 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 - }) - - // Controlled Component ? isControlled = value !== undefined - const isControlled = !!values - - const handleClapClick = () => { - // 👉 prop from HOC - animationTimeline.replay() - isControlled - ? onClap() - : setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - const componentJustMounted = useRef(true) - - useEffect( - () => { - if (!componentJustMounted.current && !isControlled) { - onClap(clapState) - } - componentJustMounted.current = false - }, - [count, onClap, isControlled] - ) - - const getState = useCallback(() => (isControlled ? values : clapState), [ - isControlled, - clapState, - values - ]) - - const memoizedValue = useMemo( - () => { - return { - ...getState(), - setRef - } - }, - [getState, setRef] - ) - - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - - - ) -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapIcon = ({ className = '', style: userStyles = {} }) => { - const { isClicked } = useContext(MediumClapContext) - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} -const ClapCount = ({ className = '', style: userStyles = {} }) => { - const { count, setRef } = useContext(MediumClapContext) - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) -} -const CountTotal = ({ className = '', style: userStyles = {} }) => { - const { countTotal, setRef } = useContext(MediumClapContext) - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) -} - -const ClapInfo = ({ info }) => { - const { countTotal } = useContext(MediumClapContext) - return ( -
- {info || wordConverter.toWords(countTotal)} claps! -
- ) -} - -MediumClap.Icon = ClapIcon -MediumClap.Count = ClapCount -MediumClap.Total = CountTotal -MediumClap.Info = ClapInfo - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const MAXIMUM_USER_CLAP = 10 -const INITIAL_STATE = { - count: 0, - countTotal: 1206, - isClicked: false -} - -const Usage = () => { - const [clapValues, setClapValues] = useState(INITIAL_STATE) - - const onClap = () => { - setClapValues(({ count, countTotal }) => ({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - })) - } - - return ( -
- - - - - - - - - - - -
- ) -} - -export default Usage diff --git a/showcase/src/patterns/06.js b/showcase/src/patterns/06.js deleted file mode 100644 index 6e745df..0000000 --- a/showcase/src/patterns/06.js +++ /dev/null @@ -1,409 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef - } from 'react' - - import mojs from 'mo-js' - import { generateRandomNumber } from '../utils/generateRandomNumber' - import styles from './index.css' - import userStyles from './usage.css' - - /** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - - const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl - }) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline - } - - /** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ - const MAX_CLAP = 50 - const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false - } - - const useClapState = ({ initialState = INIT_STATE } = {}) => { - const [clapState, setClapState] = useState(initialState) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - return { - clapState, - handleClapClick - } - } - - /** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - - function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) - } - - /** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ - const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] - } - - /** ==================================== - * 🔰 MediumClap - ==================================== **/ - - const MediumClap = () => { - const { clapState, handleClapClick } = useClapState() - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - useEffectAfterMount( - () => { - animationTimeline.replay() - }, - [count] - ) - - return ( - - - - - - ) - } - - /** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - - const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } - ) - - const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) - } - - const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } - ) - - const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } - ) - - /** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - - const CupBowl = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const CupHandle = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const Stream = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const CupBase = () => { - // Credit: Created by Kieu Thi Kim Cuong from the Noun Project - return ( - - - - - - ) - } - - const Usage = () => { - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: '#stream', - fadeEl: '#cupHandle', - burstEl: '#coffee' - }) - - const handleClick = () => { - animationTimeline.replay() - } - - return ( -
-
- -
-
- coffee -
-
- - -
-
- -
-
- -
-
- ) - } - - export default Usage \ No newline at end of file diff --git a/showcase/src/patterns/07.js b/showcase/src/patterns/07.js deleted file mode 100644 index e1ea07e..0000000 --- a/showcase/src/patterns/07.js +++ /dev/null @@ -1,323 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} - -/** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ -const MAX_CLAP = 50 -const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const useClapState = ({ initialState = INIT_STATE } = {}) => { - const [clapState, setClapState] = useState(initialState) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - const togglerProps = { - onClick: handleClapClick, - 'aria-pressed': clapState.isClicked - } - - const counterProps = { - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count - } - - return { - clapState, - togglerProps, - counterProps - } -} - -/** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - -function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) -} - -/** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ -const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } -) - -const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} - -const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } -) - -const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } -) - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const Usage = () => { - const { clapState, togglerProps, counterProps } = useClapState() - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - useEffectAfterMount( - () => { - animationTimeline.replay() - }, - [count] - ) - - return ( - - - - - - ) -} - -export default Usage diff --git a/showcase/src/patterns/08.js b/showcase/src/patterns/08.js deleted file mode 100644 index be75d84..0000000 --- a/showcase/src/patterns/08.js +++ /dev/null @@ -1,345 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} - -/** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ -const MAX_CLAP = 50 -const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const callFnsInSequence = (...fns) => (...args) => - fns.forEach(fn => fn && fn(...args)) - -const useClapState = ({ initialState = INIT_STATE } = {}) => { - const [clapState, setClapState] = useState(initialState) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - const getTogglerProps = ({ onClick, ...otherProps } = {}) => ({ - onClick: callFnsInSequence(handleClapClick, onClick), - 'aria-pressed': clapState.isClicked, - ...otherProps - }) - - const getCounterProps = ({ ...otherProps }) => ({ - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count, - ...otherProps - }) - - return { - clapState, - getTogglerProps, - getCounterProps - } -} - -/** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - -function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) -} - -/** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ -const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } -) - -const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} - -const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } -) - -const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } -) - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const Usage = () => { - const { clapState, getTogglerProps, getCounterProps } = useClapState() - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - const onClick = () => { - animationTimeline.replay() - } - - return ( -
- - - - - -
- {!isClicked ? 'No recommendations :(' : `Recommended ${count} times 🔥`} -
-
- ) -} - -export default Usage diff --git a/showcase/src/patterns/09.js b/showcase/src/patterns/09.js deleted file mode 100644 index b515497..0000000 --- a/showcase/src/patterns/09.js +++ /dev/null @@ -1,400 +0,0 @@ -import React, { - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef -} from 'react' - -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' -import userStyles from './usage.css' - -/** ==================================== - * 🔰Hook - Hook for Holding Previous Vals - ==================================== **/ -function usePrevious (value) { - const ref = useRef() - useEffect(() => { - ref.current = value - }) - return ref.current === undefined ? null : ref.current -} - -/** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - -const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl -}) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline -} - -/** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ -const MAX_CLAP = 50 -const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const callFnsInSequence = (...fns) => (...args) => - fns.forEach(fn => fn && fn(...args)) - -const useClapState = ({ initialState = INIT_STATE } = {}) => { - const initialStateRef = useRef(initialState) - const [clapState, setClapState] = useState(initialStateRef.current) - const { count, countTotal } = clapState - - const handleClapClick = useCallback( - () => { - setClapState({ - count: Math.min(count + 1, MAX_CLAP), - countTotal: count < MAX_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - }, - [count, countTotal] - ) - - const resetRef = useRef(0) - // reset only if there's a change. It's possible to check changes to other state values e.g. countTotal & isClicked - const prevCount = usePrevious(count) - const reset = useCallback( - () => { - if (prevCount !== count) { - setClapState(initialStateRef.current) - ++resetRef.current - } - }, - [prevCount, count] - ) - - const getTogglerProps = ({ onClick, ...otherProps } = {}) => ({ - onClick: callFnsInSequence(handleClapClick, onClick), - 'aria-pressed': clapState.isClicked, - ...otherProps - }) - - const getCounterProps = ({ ...otherProps }) => ({ - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count, - ...otherProps - }) - - return { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep: resetRef.current - } -} - -/** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - -function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) -} - -/** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ -const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] -} - -/** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - -const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } -) - -const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) -} - -const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } -) - -const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } -) - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - -const initialState = { count: 10, countTotal: 22, isClicked: false } -const Usage = () => { - const { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep - } = useClapState({ initialState }) - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - const onClick = () => { - animationTimeline.replay() - } - - // Side effect after reset has occured. - const [uploadingReset, setUpload] = useState(false) - useEffectAfterMount( - () => { - setUpload(true) - - const id = setTimeout(() => { - setUpload(false) - console.log('RESET COMPLETE!!!') - }, 3000) - - return () => clearTimeout(id) - }, - [resetDep] - ) - - return ( -
- - - - - -
- -
- {JSON.stringify({ count, countTotal, isClicked })}
- 
-
- {uploadingReset ? `uploading reset ${resetDep}...` : ''}
- 
-
-
- ) -} - -export default Usage diff --git a/showcase/src/patterns/10.js b/showcase/src/patterns/10.js deleted file mode 100644 index a2ffb36..0000000 --- a/showcase/src/patterns/10.js +++ /dev/null @@ -1,427 +0,0 @@ -import React, { - useReducer, - useState, - useEffect, - useCallback, - useLayoutEffect, - forwardRef, - useRef - } from 'react' - - import mojs from 'mo-js' - import { generateRandomNumber } from '../utils/generateRandomNumber' - import styles from './index.css' - import userStyles from './usage.css' - - /** ==================================== - * 🔰Hook - Hook for Holding Previous Vals - ==================================== **/ - function usePrevious (value) { - const ref = useRef() - useEffect(() => { - ref.current = value - }) - return ref.current === undefined ? null : ref.current - } - - /** ==================================== - * 🔰Hook - Hook for Animation - ==================================== **/ - - const useClapAnimation = ({ - duration: tlDuration, - bounceEl, - fadeEl, - burstEl - }) => { - const [animationTimeline, setAnimationTimeline] = useState( - new mojs.Timeline() - ) - - useLayoutEffect( - () => { - if (!bounceEl || !fadeEl || !burstEl) { - return - } - - 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 - } - }) - - 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 } - }) - - const scaleButton = new mojs.Html({ - el: burstEl, - duration: tlDuration, - scale: { 1.3: 1 }, - easing: mojs.easing.out - }) - - if (typeof burstEl === 'string') { - const id = burstEl.slice(1, burstEl.length) - const el = document.getElementById(id) - el.style.transform = 'scale(1, 1)' - } else { - burstEl.style.transform = 'scale(1, 1)' - } - - const updatedAnimationTimeline = animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - - setAnimationTimeline(updatedAnimationTimeline) - }, - [tlDuration, animationTimeline, bounceEl, fadeEl, burstEl] - ) - - return animationTimeline - } - - /** ==================================== - * 🔰Hook - Hook for Clap State - ==================================== **/ - const MAX_CLAP = 50 - const INIT_STATE = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false - } - - const callFnsInSequence = (...fns) => (...args) => - fns.forEach(fn => fn && fn(...args)) - - const clapReducer = (state, { type, payload }) => { - const { count, countTotal } = state - - switch (type) { - case useClapState.types.clap: - return { - count: count + 1, - countTotal: countTotal + 1, - isClicked: true - } - case useClapState.types.reset: - return payload - default: - return state - } - } - - const useClapState = ({ - initialState = INIT_STATE, - reducer = clapReducer - } = {}) => { - const initialStateRef = useRef(initialState) - const [clapState, dispatch] = useReducer(reducer, initialStateRef.current) - const { count } = clapState - - const handleClapClick = () => dispatch({ type: 'clap' }) - - const resetRef = useRef(0) - // reset only if there's a change. It's possible to check changes to other state values e.g. countTotal & isClicked - const reset = useCallback(() => { - dispatch({ type: 'reset', payload: initialStateRef.current }) - ++resetRef.current - }, []) - - const getTogglerProps = ({ onClick, ...otherProps } = {}) => ({ - onClick: callFnsInSequence(handleClapClick, onClick), - 'aria-pressed': clapState.isClicked, - ...otherProps - }) - - const getCounterProps = ({ ...otherProps }) => ({ - count, - 'aria-valuemax': MAX_CLAP, - 'aria-valuemin': 0, - 'aria-valuenow': count, - ...otherProps - }) - - return { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep: resetRef.current - } - } - - useClapState.reducer = clapReducer - useClapState.types = { - clap: 'clap', - reset: 'reset' - } - - /** ==================================== - * 🔰Hook - useEffectAfterMount - ==================================== **/ - - function useEffectAfterMount (cb, deps) { - const componentJustMounted = useRef(true) - useEffect(() => { - if (!componentJustMounted.current) { - return cb() - } - componentJustMounted.current = false - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps) - } - - /** ==================================== - * 🔰Hook - useDOMRef - ==================================== **/ - const useDOMRef = () => { - const [DOMRef, setDOMRef] = useState({}) - const setRef = useCallback(node => { - if (node !== null) { - setDOMRef(prevDOMRefs => ({ - ...prevDOMRefs, - [node.dataset.refkey]: node - })) - } - }, []) - - return [DOMRef, setRef] - } - - /** ==================================== - * 🔰SubComponents - Smaller Component used by - ==================================== **/ - - const ClapContainer = forwardRef( - ( - { children, handleClick, className, style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.clap, className].join(' ').trim() - - return ( - - ) - } - ) - - const ClapIcon = ({ className = '', style: userStyles = {}, isClicked }) => { - const classNames = [styles.icon, isClicked ? styles.checked : '', className] - .join(' ') - .trim() - - return ( - - - - - - - ) - } - - const ClapCount = forwardRef( - ({ count, className = '', style: userStyles = {}, ...restProps }, ref) => { - const classNames = [styles.count, className].join(' ').trim() - - return ( - - +{count} - - ) - } - ) - - const CountTotal = forwardRef( - ( - { countTotal, className = '', style: userStyles = {}, ...restProps }, - ref - ) => { - const classNames = [styles.total, className].join(' ').trim() - - return ( - - {countTotal} - - ) - } - ) - - /** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API - ==================================== **/ - - const initialState = { count: 10, countTotal: 22, isClicked: false } - const Usage = () => { - const [timesClapped, setTimeClapped] = useState(0) - const clappedTooMuch = timesClapped>= 7 - - const reducer = (state, action) => { - if (action.type === useClapState.types.clap && clappedTooMuch) { - return state - } - return useClapState.reducer(state, action) - } - - const { - clapState, - getTogglerProps, - getCounterProps, - reset, - resetDep - } = useClapState({ initialState, reducer }) - const { count, countTotal, isClicked } = clapState - - const [ - { clapContainerRef, clapCountRef, countTotalRef }, - setRef - ] = useDOMRef() - - const animationTimeline = useClapAnimation({ - duration: 300, - bounceEl: clapCountRef, - fadeEl: countTotalRef, - burstEl: clapContainerRef - }) - - const onClick = () => { - setTimeClapped(t => t + 1) - !clappedTooMuch && animationTimeline.replay() - } - - // Side effect after reset has occured. - const [uploadingReset, setUpload] = useState(false) - useEffectAfterMount( - () => { - setTimeClapped(0) - setUpload(true) - - const id = setTimeout(() => { - setUpload(false) - console.log('RESET COMPLETE!!!') - }, 3000) - - return () => clearTimeout(id) - }, - [resetDep] - ) - - return ( -
- - - - - -
- -
- {JSON.stringify({ timesClapped, count, countTotal })}
- 
-
- {uploadingReset ? `uploading reset ${resetDep}...` : ''}
- 
-
-
- {clappedTooMuch ? `You clapped too much. Don't be so generous!` : ''}
- 
-
- ) - } - - export default Usage \ No newline at end of file From f16d7f029fbbb4341122a82c0b9b3b81b75dca9f Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: 2019年12月29日 11:12:54 +0000 Subject: [PATCH 3/6] initial commit --- showcase/src/patterns/01.js | 196 +----------------------------------- showcase/src/patterns/02.js | 7 ++ 2 files changed, 11 insertions(+), 192 deletions(-) create mode 100644 showcase/src/patterns/02.js diff --git a/showcase/src/patterns/01.js b/showcase/src/patterns/01.js index a4a5ae5..5787660 100644 --- a/showcase/src/patterns/01.js +++ b/showcase/src/patterns/01.js @@ -1,195 +1,7 @@ -import React, { Component, useState } from 'react' -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' +import React from 'react' -/** ==================================== - * 🔰HOC -Higher Order Component for Animation -==================================== **/ -const withClapAnimation = WrappedComponent => { - class WithClapAnimation extends Component { - state = { - animationTimeline: new mojs.Timeline() - } - - 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 }, - 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)' - this.state.animationTimeline.add([ - countAnimation, - countTotalAnimation, - scaleButton, - circleBurst, - triangleBurst - ]) - } - - render () { - return ( - - ) - } - } - - WithClapAnimation.displayName = `WithClapAnimation(${getDisplayName( - WrappedComponent - )})` - - return WithClapAnimation -} - -function getDisplayName (WrappedComponent) { - return WrappedComponent.displayName || WrappedComponent.name || 'Component' -} - -/** ==================================== - * 🔰 MediumClap -==================================== **/ -const initialState = { - count: 0, - countTotal: generateRandomNumber(500, 10000), - isClicked: false -} - -const MediumClap = ({ animationTimeline }) => { - const MAXIMUM_USER_CLAP = 50 - const [clapState, setClapState] = useState(initialState) - const { count, countTotal, isClicked } = clapState - - const handleClapClick = () => { - // 👉 prop from HOC - animationTimeline.replay() - - setClapState({ - count: Math.min(count + 1, MAXIMUM_USER_CLAP), - countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } - - return ( - - ) -} - -/** ==================================== - * 🔰SubComponents -Smaller Component used by -==================================== **/ - -const ClapIcon = ({ isClicked }) => { - return ( - - - - - - - ) -} -const ClapCount = ({ count }) => { - return ( - - +{count} - - ) -} -const CountTotal = ({ countTotal }) => { - return ( - - {countTotal} - - ) -} - -/** ==================================== - * 🔰USAGE - Below's how a potential user - may consume the component API -==================================== **/ - -const Usage = () => { - const AnimatedMediumClap = withClapAnimation(MediumClap) - return +const Clap = () => { + return

Hello 01 Component

} -export default Usage +export default Clap diff --git a/showcase/src/patterns/02.js b/showcase/src/patterns/02.js new file mode 100644 index 0000000..225836d --- /dev/null +++ b/showcase/src/patterns/02.js @@ -0,0 +1,7 @@ +import React from 'react' + +const Clap = () => { + return

Hello 02 Component

+} + +export default Clap From bbf217166a8ba563cadf352f10acfd05249314a9 Mon Sep 17 00:00:00 2001 From: ohansemmanuel Date: 2020年2月19日 15:58:06 +0100 Subject: [PATCH 4/6] handle platform agnostic browser platform --- showcase/webpack.config.dev.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/showcase/webpack.config.dev.js b/showcase/webpack.config.dev.js index cc41701..14ae9a7 100644 --- a/showcase/webpack.config.dev.js +++ b/showcase/webpack.config.dev.js @@ -1,16 +1,16 @@ -const merge = require('webpack-merge') -const baseConfig = require('./webpack.config.base') +const merge = require("webpack-merge"); +const baseConfig = require("./webpack.config.base"); module.exports = merge(baseConfig, { - mode: 'development', + mode: "development", devServer: { port: 4646, - open: 'Google Chrome', + open: true, overlay: { warnings: true, errors: true }, hot: true }, - devtool: 'source-map' -}) + devtool: "source-map" +}); From 11e02f8449ccee15f6c8ae7dca4fa2b6690fa6d4 Mon Sep 17 00:00:00 2001 From: Ohans Emmanuel Date: 2020年2月26日 05:37:01 +0100 Subject: [PATCH 5/6] fix reload --- showcase/webpack.config.base.js | 3 ++- showcase/webpack.config.dev.js | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/showcase/webpack.config.base.js b/showcase/webpack.config.base.js index 085c1a0..f375cdb 100644 --- a/showcase/webpack.config.base.js +++ b/showcase/webpack.config.base.js @@ -5,7 +5,8 @@ module.exports = { entry: './src/index.js', output: { filename: 'app.bundle.js', - path: path.join(__dirname, 'dist') + path: path.join(__dirname, 'dist'), + publicPath: '/' }, module: { rules: [ diff --git a/showcase/webpack.config.dev.js b/showcase/webpack.config.dev.js index 14ae9a7..c8f056e 100644 --- a/showcase/webpack.config.dev.js +++ b/showcase/webpack.config.dev.js @@ -1,8 +1,8 @@ -const merge = require("webpack-merge"); -const baseConfig = require("./webpack.config.base"); +const merge = require('webpack-merge') +const baseConfig = require('./webpack.config.base') module.exports = merge(baseConfig, { - mode: "development", + mode: 'development', devServer: { port: 4646, open: true, @@ -10,7 +10,8 @@ module.exports = merge(baseConfig, { warnings: true, errors: true }, + historyApiFallback: true, hot: true }, - devtool: "source-map" -}); + devtool: 'source-map' +}) From 32f95a2bdf1e9a78dd191845422fbe9cfa81afb7 Mon Sep 17 00:00:00 2001 From: ohansemmanuel Date: 2020年7月16日 15:42:23 +0200 Subject: [PATCH 6/6] show clap example in clean-slate --- node_modules/.yarn-integrity | 10 ++ showcase/src/patterns/01.js | 199 +++++++++++++++++++++++++++++++- showcase/src/patterns/02.js | 7 -- showcase/src/patterns/index.css | 8 +- yarn.lock | 4 + 5 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 node_modules/.yarn-integrity delete mode 100644 showcase/src/patterns/02.js create mode 100644 yarn.lock diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity new file mode 100644 index 0000000..5e070b6 --- /dev/null +++ b/node_modules/.yarn-integrity @@ -0,0 +1,10 @@ +{ + "systemParams": "darwin-x64-72", + "modulesFolders": [], + "flags": [], + "linkedModules": [], + "topLevelPatterns": [], + "lockfileEntries": {}, + "files": [], + "artifacts": {} +} \ No newline at end of file diff --git a/showcase/src/patterns/01.js b/showcase/src/patterns/01.js index 5787660..664f7b2 100644 --- a/showcase/src/patterns/01.js +++ b/showcase/src/patterns/01.js @@ -1,7 +1,198 @@ -import React from 'react' +import React, { Component, useState } from "react"; +import mojs from "mo-js"; +import { generateRandomNumber } from "../utils/generateRandomNumber"; +import styles from "./index.css"; -const Clap = () => { - return

Hello 01 Component

+/** ==================================== + * 🔰HOC +Higher Order Component for Animation +==================================== **/ +const withClapAnimation = (WrappedComponent) => { + class WithClapAnimation extends Component { + animationTimeline = new mojs.Timeline(); + state = { + animationTimeline: this.animationTimeline, + }; + + 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 }, + 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 }); + } + + render() { + return ( + + ); + } + } + + WithClapAnimation.displayName = `WithClapAnimation(${getDisplayName( + WrappedComponent + )})`; + + return WithClapAnimation; +}; + +function getDisplayName(WrappedComponent) { + return WrappedComponent.displayName || WrappedComponent.name || "Component"; } -export default Clap +/** ==================================== + * 🔰 MediumClap +==================================== **/ +const initialState = { + count: 0, + countTotal: generateRandomNumber(500, 10000), + isClicked: false, +}; + +const MediumClap = ({ animationTimeline }) => { + const MAXIMUM_USER_CLAP = 50; + const [clapState, setClapState] = useState(initialState); + const { count, countTotal, isClicked } = clapState; + + const handleClapClick = () => { + // 👉 prop from HOC + animationTimeline.replay(); + + setClapState({ + count: Math.min(count + 1, MAXIMUM_USER_CLAP), + countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, + isClicked: true, + }); + }; + + return ( + + ); +}; + +/** ==================================== + * 🔰SubComponents +Smaller Component used by +==================================== **/ + +const ClapIcon = ({ isClicked }) => { + return ( + + + + + + + ); +}; +const ClapCount = ({ count }) => { + return ( + + +{count} + + ); +}; +const CountTotal = ({ countTotal }) => { + return ( + + {countTotal} + + ); +}; + +/** ==================================== + * 🔰USAGE + Below's how a potential user + may consume the component API +==================================== **/ + +const Usage = () => { + const AnimatedMediumClap = withClapAnimation(MediumClap); + return ; +}; + +export default Usage; diff --git a/showcase/src/patterns/02.js b/showcase/src/patterns/02.js deleted file mode 100644 index 225836d..0000000 --- a/showcase/src/patterns/02.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react' - -const Clap = () => { - return

Hello 02 Component

-} - -export default Clap diff --git a/showcase/src/patterns/index.css b/showcase/src/patterns/index.css index baa6240..47bda4e 100644 --- a/showcase/src/patterns/index.css +++ b/showcase/src/patterns/index.css @@ -82,8 +82,6 @@ /* Clap Info */ .info { -position: absolute; -left: -20px; -right: -20px; -bottom: -50px; -} \ No newline at end of file + position: relative; + top: 47px; +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..fb57ccd --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +

AltStyle によって変換されたページ (->オリジナル) /