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/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/01.js b/showcase/src/patterns/01.js index a4a5ae5..664f7b2 100644 --- a/showcase/src/patterns/01.js +++ b/showcase/src/patterns/01.js @@ -1,115 +1,118 @@ -import React, { Component, useState } from 'react' -import mojs from 'mo-js' -import { generateRandomNumber } from '../utils/generateRandomNumber' -import styles from './index.css' +import React, { Component, useState } from "react"; +import mojs from "mo-js"; +import { generateRandomNumber } from "../utils/generateRandomNumber"; +import styles from "./index.css"; /** ==================================== * 🔰HOC Higher Order Component for Animation ==================================== **/ -const withClapAnimation = WrappedComponent => { +const withClapAnimation = (WrappedComponent) => { class WithClapAnimation extends Component { + animationTimeline = new mojs.Timeline(); state = { - animationTimeline: new mojs.Timeline() - } + animationTimeline: this.animationTimeline, + }; - componentDidMount () { - const tlDuration = 300 + componentDidMount() { + const tlDuration = 300; const triangleBurst = new mojs.Burst({ - parent: '#clap', + parent: "#clap", radius: { 50: 95 }, count: 5, angle: 30, children: { - shape: 'polygon', + shape: "polygon", radius: { 6: 0 }, scale: 1, - stroke: 'rgba(211,84,0 ,0.5)', + 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 - } - }) + duration: tlDuration, + }, + }); const circleBurst = new mojs.Burst({ - parent: '#clap', + parent: "#clap", radius: { 50: 75 }, angle: 25, duration: tlDuration, children: { - shape: 'circle', - fill: 'rgba(149,165,166 ,0.5)', + 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) - } - }) + easing: mojs.easing.bezier(0.1, 1, 0.3, 1), + }, + }); const countAnimation = new mojs.Html({ - el: '#clapCount', + el: "#clapCount", isShowStart: false, isShowEnd: true, y: { 0: -30 }, opacity: { 0: 1 }, - duration: tlDuration + duration: tlDuration, }).then({ opacity: { 1: 0 }, y: -80, - delay: tlDuration / 2 - }) + delay: tlDuration / 2, + }); const countTotalAnimation = new mojs.Html({ - el: '#clapCountTotal', + el: "#clapCountTotal", isShowStart: false, isShowEnd: true, opacity: { 0: 1 }, delay: (3 * tlDuration) / 2, duration: tlDuration, - y: { 0: -3 } - }) + y: { 0: -3 }, + }); const scaleButton = new mojs.Html({ - el: '#clap', + el: "#clap", duration: tlDuration, scale: { 1.3: 1 }, - easing: mojs.easing.out - }) + easing: mojs.easing.out, + }); - const clap = document.getElementById('clap') - clap.style.transform = 'scale(1, 1)' - this.state.animationTimeline.add([ + const clap = document.getElementById("clap"); + clap.style.transform = "scale(1, 1)"; + + const newAnimationTimeline = this.animationTimeline.add([ countAnimation, countTotalAnimation, scaleButton, circleBurst, - triangleBurst - ]) + triangleBurst, + ]); + this.setState({ animationTimeline: newAnimationTimeline }); } - render () { + render() { return ( - ) + ); } } WithClapAnimation.displayName = `WithClapAnimation(${getDisplayName( WrappedComponent - )})` + )})`; - return WithClapAnimation -} + return WithClapAnimation; +}; -function getDisplayName (WrappedComponent) { - return WrappedComponent.displayName || WrappedComponent.name || 'Component' +function getDisplayName(WrappedComponent) { + return WrappedComponent.displayName || WrappedComponent.name || "Component"; } /** ==================================== @@ -118,33 +121,33 @@ function getDisplayName (WrappedComponent) { const initialState = { count: 0, countTotal: generateRandomNumber(500, 10000), - isClicked: false -} + isClicked: false, +}; const MediumClap = ({ animationTimeline }) => { - const MAXIMUM_USER_CLAP = 50 - const [clapState, setClapState] = useState(initialState) - const { count, countTotal, isClicked } = clapState + const MAXIMUM_USER_CLAP = 50; + const [clapState, setClapState] = useState(initialState); + const { count, countTotal, isClicked } = clapState; const handleClapClick = () => { // 👉 prop from HOC - animationTimeline.replay() + animationTimeline.replay(); setClapState({ count: Math.min(count + 1, MAXIMUM_USER_CLAP), countTotal: count < MAXIMUM_USER_CLAP ? countTotal + 1 : countTotal, - isClicked: true - }) - } + isClicked: true, + }); + }; return ( - - ) -} + ); +}; /** ==================================== * 🔰SubComponents @@ -155,31 +158,31 @@ const ClapIcon = ({ isClicked }) => { return ( - - + + - ) -} + ); +}; const ClapCount = ({ count }) => { return ( - + +{count} - ) -} + ); +}; const CountTotal = ({ countTotal }) => { return ( - + {countTotal} - ) -} + ); +}; /** ==================================== * 🔰USAGE @@ -188,8 +191,8 @@ const CountTotal = ({ countTotal }) => { ==================================== **/ const Usage = () => { - const AnimatedMediumClap = withClapAnimation(MediumClap) - return -} + const AnimatedMediumClap = withClapAnimation(MediumClap); + return ; +}; -export default Usage +export default Usage; 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 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/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 cc41701..c8f056e 100644 --- a/showcase/webpack.config.dev.js +++ b/showcase/webpack.config.dev.js @@ -5,11 +5,12 @@ module.exports = merge(baseConfig, { mode: 'development', devServer: { port: 4646, - open: 'Google Chrome', + open: true, overlay: { warnings: true, errors: true }, + historyApiFallback: true, hot: true }, devtool: 'source-map' 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 によって変換されたページ (->オリジナル) /