Skip to content

Commit

Permalink
(refactor/types): re-write src/index.js in TypeScript
Browse files Browse the repository at this point in the history
- make heavy use of the multiple iterations on types in others' PRs,
  my own iterations on that, and then @types/react-signature-canvas
  - credit where credit is due!
  - NOTE: the naming of the props type and the class type do not include
    the word "React" unlike @types/react-signature-canvas
    - it is convention in React components to leave it out and you're
      already importing from a package with "react" in its name

- refactor init logic a bit to get around `| null` everywhere
  - kinda hacky but better than ifs or ! (non-nullable) everywhere
- use ! for canvas.getContext('2d') calls for same reason
  - c.f. microsoft/TypeScript#19229

- refactor naming everywhere to src/index.tsx

- configure tsconfig -- no need for allowJs anymore, but jsx needs to
  be set as TS is actually reading it now
- configure jest -- ts-jest needed to read TSX files

(deps): add DT typings for prop-types, react, and signature_pad
(deps): add a declaration file for trim-canvas as it doesn't have
types built-in yet (TODO for me!)
  - use typings/ to hold external declarations
  • Loading branch information
agilgur5 committed Apr 20, 2022
1 parent 962b902 commit ecb0374
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 21 deletions.
2 changes: 1 addition & 1 deletion example/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import ReactDOM from 'react-dom'

import SignaturePad from '../../src/index.js'
import SignaturePad from '../../src/index.tsx'

import styles from './styles.module.css'

Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ module.exports = {
],
transform: {
// support babel-jest. TSDX defaults to just ts-jest. see https://github.com/jaredpalmer/tsdx/pull/486
'\\.js$': 'babel-jest'
'\\.js$': 'babel-jest',
'\\.tsx$': 'ts-jest'
},
// support JS + JSX. TSDX defaults to just TS + TSX. see https://github.com/jaredpalmer/tsdx/pull/486
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
Expand Down
34 changes: 34 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,16 @@
"react-dom": "0.14 - 17"
},
"dependencies": {
"@types/signature_pad": "^2.3.0",
"signature_pad": "^2.3.2",
"trim-canvas": "^0.1.0"
},
"devDependencies": {
"@agilgur5/changelog-maker": "^3.0.0",
"@babel/core": "^7.8.4",
"@babel/preset-react": "^7.8.3",
"@types/prop-types": "^15.7.3",
"@types/react": "^17.0.44",
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.6",
"babel-eslint": "^10.0.2",
"canvas": "^2.9.0",
Expand Down
45 changes: 29 additions & 16 deletions src/index.js → src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import React, { Component } from 'react'
import SignaturePad from 'signature_pad'
import trimCanvas from 'trim-canvas'

export class SignatureCanvas extends Component {
export interface SignatureCanvasProps extends SignaturePad.SignaturePadOptions {
canvasProps?: React.CanvasHTMLAttributes<HTMLCanvasElement>,
clearOnResize?: boolean
}

export class SignatureCanvas extends Component<SignatureCanvasProps> {
static propTypes = {
// signature_pad's props
velocityFilterWeight: PropTypes.number,
Expand All @@ -24,7 +29,15 @@ export class SignatureCanvas extends Component {
clearOnResize: true
}

_sigPad = null
// this is some hack-ish init and casting to avoid `| null` everywhere :/
_sigPad: SignaturePad = {} as SignaturePad
_canvas: HTMLCanvasElement = {} as HTMLCanvasElement

private readonly setRef = (ref: HTMLCanvasElement | null) => {
if (ref) {
this._canvas = ref
}
}

_excludeOurProps = () => {
const { canvasProps, clearOnResize, ...sigPadProps } = this.props
Expand All @@ -47,23 +60,23 @@ export class SignatureCanvas extends Component {
}

// return the canvas ref for operations like toDataURL
getCanvas = () => {
getCanvas = (): HTMLCanvasElement => {
return this._canvas
}

// return a trimmed copy of the canvas
getTrimmedCanvas = () => {
getTrimmedCanvas = (): HTMLCanvasElement => {
// copy the canvas
const copy = document.createElement('canvas')
copy.width = this._canvas.width
copy.height = this._canvas.height
copy.getContext('2d').drawImage(this._canvas, 0, 0)
copy.getContext('2d')!.drawImage(this._canvas, 0, 0)
// then trim it
return trimCanvas(copy)
}

// return the internal SignaturePad reference
getSignaturePad = () => {
getSignaturePad = (): SignaturePad => {
return this._sigPad
}

Expand Down Expand Up @@ -94,48 +107,48 @@ export class SignatureCanvas extends Component {
if (!height) {
canvas.height = canvas.offsetHeight * ratio
}
canvas.getContext('2d').scale(ratio, ratio)
canvas.getContext('2d')!.scale(ratio, ratio)
this.clear()
}

render () {
const { canvasProps } = this.props
return <canvas ref={(ref) => { this._canvas = ref }} {...canvasProps} />
return <canvas ref={this.setRef} {...canvasProps} />
}

// all wrapper functions below render
//
on = () => {
on: SignaturePad['on'] = () => {
window.addEventListener('resize', this._checkClearOnResize)
return this._sigPad.on()
}

off = () => {
off: SignaturePad['off'] = () => {
window.removeEventListener('resize', this._checkClearOnResize)
return this._sigPad.off()
}

clear = () => {
clear: SignaturePad['clear'] = () => {
return this._sigPad.clear()
}

isEmpty = () => {
isEmpty: SignaturePad['isEmpty'] = () => {
return this._sigPad.isEmpty()
}

fromDataURL = (dataURL, options) => {
fromDataURL: SignaturePad['fromDataURL'] = (dataURL, options) => {
return this._sigPad.fromDataURL(dataURL, options)
}

toDataURL = (type, encoderOptions) => {
toDataURL: SignaturePad['toDataURL'] = (type, encoderOptions) => {
return this._sigPad.toDataURL(type, encoderOptions)
}

fromData = (pointGroups) => {
fromData: SignaturePad['fromData'] = (pointGroups) => {
return this._sigPad.fromData(pointGroups)
}

toData = () => {
toData: SignaturePad['toData'] = () => {
return this._sigPad.toData()
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { jest, describe, it, test, expect } from 'jest-without-globals'
import { mount } from 'enzyme'
import React from 'react'

import SignatureCanvas from '../src/index.js'
import SignatureCanvas from '../src/index.tsx'
import { propsF, dotF } from './fixtures.js'

test('mounts canvas and instance properly', () => {
Expand Down
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"include": ["src", "types"],
"include": ["src", "typings"],
"compilerOptions": {
"module": "esnext",
"lib": ["dom", "esnext"],
Expand All @@ -18,6 +18,6 @@
"*": ["src/*", "node_modules/*"]
},
"esModuleInterop": true,
"allowJs": true
"jsx": "react"
}
}
3 changes: 3 additions & 0 deletions typings/trim-canvas.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare module 'trim-canvas' {
export default function trimCanvas (canvas: HTMLCanvasElement): HTMLCanvasElement
}

0 comments on commit ecb0374

Please sign in to comment.