Skip to content

Commit

Permalink
feat: refactor state and hook output
Browse files Browse the repository at this point in the history
  • Loading branch information
awran5 committed Nov 19, 2022
1 parent 270ca16 commit 64c63e7
Showing 1 changed file with 74 additions and 21 deletions.
95 changes: 74 additions & 21 deletions src/hooks/useTypewriter.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useCallback, useEffect, useRef, useReducer } from 'react'
import { reducer } from '../reducer'

export interface TypewriterProps {
/** Callback Function that is triggered when loops are completed. available if loop is > 0 */
export type TypewriterProps = {
/** Callback Function that is triggered when loops are completed. available if loop is > `0` */
onLoopDone?: () => void
/** Callback Function that is runs while typing */
onType?: (counter: number) => void
/** Callback Function that is triggered while typing with `typed` words count passed */
onType?: (count: number) => void
/** Callback Function that is triggered while deleting */
onDelete?: () => void
/** Callback Function that is triggered on typing delay */
onDelay?: () => void
/** Array of strings holding the words */
words: string[]
/** Control how many times to run. `0 | false` to run infinitely */
Expand All @@ -18,17 +22,29 @@ export interface TypewriterProps {
delaySpeed?: number
}

export type TypewriterHelper = {
/** `true` if currently typing */
isType: boolean
/** `true` if on delay */
isDelay: boolean
/** `true` if currently deleting */
isDelete: boolean
/** `true` if all loops are done */
isDone: boolean
}

export const useTypewriter = ({
words = ['Hello World!', 'This is', 'a simple Typewriter'],
loop = 1,
typeSpeed = 80,
deleteSpeed = 50,
delaySpeed = 1500,
onLoopDone,
onType
}: TypewriterProps): (string | number)[] => {
const [{ isDeleting, speed, text, count }, dispatch] = useReducer(reducer, {
isDeleting: false,
onType,
onDelete,
onDelay
}: TypewriterProps): [string, TypewriterHelper] => {
const [{ speed, text, count }, dispatch] = useReducer(reducer, {
speed: typeSpeed,
text: '',
count: 0
Expand All @@ -37,18 +53,27 @@ export const useTypewriter = ({
// Refs
const loops = useRef(0)
const isDone = useRef(false)
const isDelete = useRef(false)
const isType = useRef(false)
const isDelay = useRef(false)

const handleTyping = useCallback(() => {
const index = count % words.length
const fullWord = words[index]

if (!isDeleting) {
if (!isDelete.current) {
dispatch({ type: 'TYPE', payload: fullWord, speed: typeSpeed })

if (onType) onType(count)
isType.current = true

if (text === fullWord) {
dispatch({ type: 'SPEED', payload: delaySpeed })
dispatch({ type: 'DELAY', payload: delaySpeed })
isType.current = false
isDelay.current = true

setTimeout(() => {
isDelay.current = false
isDelete.current = true
}, delaySpeed)

if (loop > 0) {
loops.current += 1
Expand All @@ -57,31 +82,59 @@ export const useTypewriter = ({
}
} else {
dispatch({ type: 'DELETE', payload: fullWord, speed: deleteSpeed })
if (text === '') {
isDelete.current = false
dispatch({ type: 'COUNT' })
}
}

if (isType.current) {
if (onType) onType(loops.current)
}

if (isDelete.current) {
if (onDelete) onDelete()
}

if (text === '') dispatch({ type: 'COUNT' })
if (isDelay.current) {
if (onDelay) onDelay()
}
}, [
isDeleting,
count,
delaySpeed,
deleteSpeed,
loop,
typeSpeed,
words,
text,
onType
onType,
onDelete,
onDelay
])

useEffect(() => {
const typing = setTimeout(handleTyping, speed)

if (isDone.current) {
clearTimeout(typing)
if (onLoopDone) onLoopDone()
}
if (isDone.current) clearTimeout(typing)

return () => clearTimeout(typing)
}, [handleTyping, speed, onLoopDone])
}, [handleTyping, speed])

return [text, count + 1]
useEffect(() => {
if (!onLoopDone) return

if (isDone.current) {
onLoopDone()
}
}, [onLoopDone])

return [
text,
{
isType: isType.current,
isDelay: isDelay.current,
isDelete: isDelete.current,
isDone: isDone.current
}
]
}

0 comments on commit 64c63e7

Please sign in to comment.