import useDeepCompareEffect from 'use-deep-compare-effect' ; import React , { useContext , FC , memo } from 'react' ; import { RoughSVG } from 'roughjs/bin/svg' ; import { Drawable } from 'roughjs/bin/core' ; import { RoughCanvas } from 'roughjs/bin/canvas' ; export { Point } from 'roughjs/bin/geometry' ; import * as Props from './RoughComponentProps' ; import RoughContext from './RoughContext' ; type RoughRenderer = RoughSVG | RoughCanvas ; type RoughOutput = Node | Drawable ; interface RendererProps { render : ( rc : RoughRenderer ) => RoughOutput ; } const Renderer = ( { render } ) => { const { ref , config , width , height , type } = useContext ( RoughContext ) ; const clearCanvas = ( ) : void => { if ( ! ( width && height ) ) { throw new Error ( 'Canvas should have a defined width and height' ) ; } const canvas = ref && ( ref . current as HTMLCanvasElement ) ; const ctx = canvas && canvas . getContext ( '2d' ) ; ctx && ctx . clearRect ( 0 , 0 , width , height ) ; } ; useDeepCompareEffect ( ( ) => { const rendererElement = ref && ref . current ; if ( ! rendererElement ) return ; if ( type === 'svg' ) { const roughSvg = new RoughSVG ( rendererElement as SVGSVGElement , config ) ; const node = render ( roughSvg ) as Node ; rendererElement . appendChild ( node ) ; return ( ) : void => { rendererElement . removeChild ( node ) ; } ; } else { const roughCanvas = new RoughCanvas ( rendererElement as HTMLCanvasElement , config ) ; render ( roughCanvas ) ; } } , [ ref , config , render , type ] ) ; if ( type === 'canvas' ) clearCanvas ( ) ; return null ; } ; export const Line = memo ( ( { x1 , y1 , x2 , y2 , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . line ( x1 , y1 , x2 , y2 , props ) , [ x1 , y1 , x2 , y2 , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Line . displayName = 'Line' ; export const Rectangle = memo ( ( { x , y , width , height , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . rectangle ( x , y , width , height , props ) , [ x , y , width , height , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Rectangle . displayName = 'Rectangle' ; export const Ellipse = memo ( ( { x , y , width , height , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . ellipse ( x , y , width , height , props ) , [ x , y , width , height , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Ellipse . displayName = 'Ellipse' ; export const Circle = memo ( ( { x , y , diameter , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . circle ( x , y , diameter , props ) , [ x , y , diameter , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Circle . displayName = 'Circle' ; export const LinearPath = memo ( ( { points , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . linearPath ( points , props ) , [ points , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; LinearPath . displayName = 'LinearPath' ; export const Polygon = memo ( ( { points , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . polygon ( points , props ) , [ points , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Polygon . displayName = 'Polygon' ; export const Arc = memo ( ( { x , y , width , height , start , stop , closed , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . arc ( x , y , width , height , start , stop , closed , props ) , [ x , y , width , height , start , stop , closed , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Arc . displayName = 'Arc' ; export const Curve = memo ( ( { points , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . curve ( points , props ) , [ points , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Curve . displayName = 'Curve' ; export const Path = memo ( ( { d , ... props } ) => { const renderProps = React . useCallback ( ( rc ) => rc . path ( d , props ) , [ d , props ] ) ; return ( < Renderer render = { ( rc ) : RoughOutput => renderProps ( rc ) } />); } ) ; Path . displayName = 'Path' ;