+
{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
+
+