Skip to content

Commit

Permalink
Refactor using hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
bgonp committed Mar 18, 2021
1 parent d10695d commit 7bfbf74
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 113 deletions.
70 changes: 0 additions & 70 deletions src/DrawArea.tsx

This file was deleted.

54 changes: 54 additions & 0 deletions src/components/DrawArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { FC } from 'react'
import * as PropTypes from 'prop-types'

import Drawable from 'components/Drawable'
import Drawed from 'components/Drawed'
import DrawContext from 'contexts/DrawContext'
import useDrawArea from 'hooks/useDrawArea'

type Props = {
className?: string
color?: string
disabled?: boolean
hidden?: boolean
thickness?: number
}

const DrawArea: FC<Props> = ({
className = '',
color = '#000000',
disabled = false,
hidden = false,
thickness = 10,
children,
}) => {
const { isDrawing, lines, addPoint, finishLine, reset, undo } = useDrawArea()

const content = hidden
? null
: (
<div className={className}>
<Drawed color={color} lines={lines} thickness={thickness} />
{disabled || <Drawable addPoint={addPoint} finishLine={finishLine} />}
</div>
)

if (!children) return content

return (
<DrawContext.Provider value={{ isDrawing, lines, reset, undo }}>
{children}
{content}
</DrawContext.Provider>
)
}

DrawArea.propTypes = {
className: PropTypes.string,
color: PropTypes.string,
disabled: PropTypes.bool,
hidden: PropTypes.bool,
thickness: PropTypes.number,
}

export default DrawArea
36 changes: 36 additions & 0 deletions src/components/Drawable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { CSSProperties, FC, useRef } from 'react'

import useDrawable from 'hooks/useDrawable'

import { Point } from 'types'

type Props = {
addPoint: (point: Point) => void
finishLine: () => void
}

const style: CSSProperties = {
position: 'absolute',
inset: 0,
}

const Drawable: FC<Props> = ({ addPoint, finishLine }) => {
const ref = useRef<HTMLDivElement>(null)
const { startDrawing, keepDrawing, endDrawing } = useDrawable({ ref, addPoint, finishLine })

return (
<div
ref={ref}
style={style}
onMouseDown={startDrawing}
onMouseMove={keepDrawing}
onMouseUp={endDrawing}
onMouseLeave={endDrawing}
onTouchStart={startDrawing}
onTouchMove={keepDrawing}
onTouchEnd={endDrawing}
/>
)
}

export default Drawable
4 changes: 2 additions & 2 deletions src/Drawed.tsx → src/components/Drawed.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { CSSProperties, FC } from 'react'

import { Lines, Line } from './types'
import { Lines, Line } from 'types'

type Props = {
color: string
Expand All @@ -26,7 +26,7 @@ const Drawed: FC<Props> = ({ color, lines, thickness }) => (
strokeLinecap="round"
stroke={color}
strokeWidth={thickness}
/>,
/>
)}
</svg>
)
Expand Down
4 changes: 2 additions & 2 deletions src/DrawContext.tsx → src/contexts/DrawContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createContext } from 'react'

import { Lines } from './types'
import { Lines } from 'types'

type DrawContextType = {
lines: Lines
Expand All @@ -9,6 +9,6 @@ type DrawContextType = {
undo: () => void
}

const DrawContext = createContext<DrawContextType>(null)
const DrawContext = createContext<DrawContextType | null>(null)

export default DrawContext
51 changes: 51 additions & 0 deletions src/hooks/useDrawArea.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useCallback, useMemo, useState } from 'react'

import { Line, Lines, Point } from 'types'

type UseDrawAreaType = {
isDrawing: boolean
lines: Lines
addPoint: (point: Point) => void
finishLine: () => void
reset: () => void
undo: () => void
}

const useDrawArea = (): UseDrawAreaType => {
const [lines, setLines] = useState<Lines>([])
const [newLine, setNewLine] = useState<Line>([])

const allLines: Lines = useMemo(
() => newLine.length === 0 ? lines : [...lines, newLine],
[lines, newLine]
)

const isDrawing: boolean = newLine.length > 0

const addPoint = useCallback(
(newPoint: Point) => setNewLine([...newLine, newPoint]),
[newLine]
)

const finishLine = useCallback(
() => {
if (newLine.length > 1) setLines(allLines)
setNewLine([])
}, [allLines, newLine]
)

const reset = useCallback(() => setLines([]), [])

const undo = useCallback(() => setLines(lines.slice(0, -1)), [lines])

return {
isDrawing,
lines: allLines,
addPoint,
finishLine,
reset,
undo,
}
}

export default useDrawArea
55 changes: 18 additions & 37 deletions src/Drawable.tsx → src/hooks/useDrawable.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,30 @@
import React, {
CSSProperties,
FC,
MouseEvent,
TouchEvent,
useRef,
useState,
} from 'react'
import { RefObject, MouseEvent, TouchEvent, useState } from 'react'

import { Point } from './types'
import { Point } from 'types'

type Props = {
addPoint: (point: Point) => void
finishLine: () => void
type UseDrawableType = {
startDrawing: (event: MouseEvent | TouchEvent) => void
keepDrawing: (event: MouseEvent | TouchEvent) => void
endDrawing: () => void
}

const style: CSSProperties = {
position: 'absolute',
inset: 0,
overscrollBehavior: 'contain',
type UseDrawableProps = {
ref: RefObject<HTMLDivElement>
addPoint: (point: Point) => void
finishLine: () => void
}

const getCoordinates = (event: MouseEvent | TouchEvent): [number, number] | null => {
if (event.button === 0) {
if (event instanceof MouseEvent && event.button === 0) {
return [event.clientX, event.clientY]
} else if (event.touches?.length) {
} else if (event instanceof TouchEvent && event.touches.length > 0) {
return [event.touches[0].clientX, event.touches[0].clientY]
}
return null
}

const Drawable: FC<Props> = ({ addPoint, finishLine }) => {
const useDrawable = ({ ref, addPoint, finishLine }: UseDrawableProps): UseDrawableType => {
const [isDrawing, setIsDrawing] = useState<boolean>(false)
const ref = useRef<HTMLDivElement>(null)

const getPoint = (event: MouseEvent | TouchEvent): Point | null => {
if (!ref.current) return null
Expand All @@ -44,39 +37,27 @@ const Drawable: FC<Props> = ({ addPoint, finishLine }) => {
}
}

const onStartDrawing = (event: MouseEvent | TouchEvent) => {
const startDrawing = (event: MouseEvent | TouchEvent) => {
const firstPoint = getPoint(event)
if (!firstPoint) return
addPoint(firstPoint)
setIsDrawing(true)
}

const onMoveDrawing = (event: MouseEvent | TouchEvent) => {
const keepDrawing = (event: MouseEvent | TouchEvent) => {
if (!isDrawing) return
const nextPoint = getPoint(event)
if (!nextPoint) return
addPoint(nextPoint)
}

const onEndDrawing = () => {
const endDrawing = () => {
if (!isDrawing) return
finishLine()
setIsDrawing(false)
}

return (
<div
ref={ref}
style={style}
onMouseDown={onStartDrawing}
onMouseMove={onMoveDrawing}
onMouseUp={onEndDrawing}
onMouseLeave={onEndDrawing}
onTouchStart={onStartDrawing}
onTouchMove={onMoveDrawing}
onTouchEnd={onEndDrawing}
/>
)
return { startDrawing, keepDrawing, endDrawing }
}

export default Drawable
export default useDrawable
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import DrawArea from './DrawArea'
import DrawContext from './DrawContext'
import DrawArea from 'components/DrawArea'
import DrawContext from 'contexts/DrawContext'

export { DrawArea, DrawContext }

0 comments on commit 7bfbf74

Please sign in to comment.