Skip to content

Commit d295e28

Browse files
committed
(refactor/types): re-write src/index.js in TypeScript
- 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! - 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
1 parent fdc0213 commit d295e28

File tree

8 files changed

+68
-21
lines changed

8 files changed

+68
-21
lines changed

example/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Component } from 'react'
22
import ReactDOM from 'react-dom'
33

4-
import SignaturePad from '../../src/index.js'
4+
import SignaturePad from '../../src/index.tsx'
55

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

jest.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ module.exports = {
77
],
88
transform: {
99
// support babel-jest. TSDX defaults to just ts-jest. see https://github.com/jaredpalmer/tsdx/pull/486
10-
'\\.js$': 'babel-jest'
10+
'\\.js$': 'babel-jest',
11+
'\\.tsx$': 'ts-jest'
1112
},
1213
// support JS + JSX. TSDX defaults to just TS + TSX. see https://github.com/jaredpalmer/tsdx/pull/486
1314
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],

package-lock.json

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,16 @@
5252
"react-dom": "0.14 - 16"
5353
},
5454
"dependencies": {
55+
"@types/signature_pad": "^2.3.0",
5556
"signature_pad": "^2.3.2",
5657
"trim-canvas": "^0.1.0"
5758
},
5859
"devDependencies": {
5960
"@agilgur5/changelog-maker": "^3.0.0",
6061
"@babel/core": "^7.8.4",
6162
"@babel/preset-react": "^7.8.3",
63+
"@types/prop-types": "^15.7.3",
64+
"@types/react": "^16.9.19",
6265
"babel-eslint": "^10.0.2",
6366
"canvas-prebuilt": "^1.6.11",
6467
"enzyme": "^3.10.0",

src/index.js renamed to src/index.tsx

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import React, { Component } from 'react'
33
import SignaturePad from 'signature_pad'
44
import trimCanvas from 'trim-canvas'
55

6-
export default class SignatureCanvas extends Component {
6+
export interface ReactSignatureCanvasProps extends SignaturePad.SignaturePadOptions {
7+
canvasProps?: React.CanvasHTMLAttributes<HTMLCanvasElement>,
8+
clearOnResize?: boolean
9+
}
10+
11+
export default class ReactSignatureCanvas extends Component<ReactSignatureCanvasProps> {
712
static propTypes = {
813
// signature_pad's props
914
velocityFilterWeight: PropTypes.number,
@@ -24,7 +29,15 @@ export default class SignatureCanvas extends Component {
2429
clearOnResize: true
2530
}
2631

27-
_sigPad = null
32+
// this is some hack-ish init and casting to avoid `| null` everywhere :/
33+
_sigPad: SignaturePad = {} as SignaturePad
34+
_canvas: HTMLCanvasElement = {} as HTMLCanvasElement
35+
36+
_setRef = (ref: HTMLCanvasElement | null) => {
37+
if (ref) {
38+
this._canvas = ref
39+
}
40+
}
2841

2942
_excludeOurProps = () => {
3043
const { canvasProps, clearOnResize, ...sigPadProps } = this.props
@@ -47,23 +60,23 @@ export default class SignatureCanvas extends Component {
4760
}
4861

4962
// return the canvas ref for operations like toDataURL
50-
getCanvas = () => {
63+
getCanvas = (): HTMLCanvasElement => {
5164
return this._canvas
5265
}
5366

5467
// return a trimmed copy of the canvas
55-
getTrimmedCanvas = () => {
68+
getTrimmedCanvas = (): HTMLCanvasElement => {
5669
// copy the canvas
5770
const copy = document.createElement('canvas')
5871
copy.width = this._canvas.width
5972
copy.height = this._canvas.height
60-
copy.getContext('2d').drawImage(this._canvas, 0, 0)
73+
copy.getContext('2d')!.drawImage(this._canvas, 0, 0)
6174
// then trim it
6275
return trimCanvas(copy)
6376
}
6477

6578
// return the internal SignaturePad reference
66-
getSignaturePad = () => {
79+
getSignaturePad = (): SignaturePad => {
6780
return this._sigPad
6881
}
6982

@@ -94,48 +107,48 @@ export default class SignatureCanvas extends Component {
94107
if (!height) {
95108
canvas.height = canvas.offsetHeight * ratio
96109
}
97-
canvas.getContext('2d').scale(ratio, ratio)
110+
canvas.getContext('2d')!.scale(ratio, ratio)
98111
this.clear()
99112
}
100113

101114
render () {
102115
const { canvasProps } = this.props
103-
return <canvas ref={(ref) => { this._canvas = ref }} {...canvasProps} />
116+
return <canvas ref={this._setRef} {...canvasProps} />
104117
}
105118

106119
// all wrapper functions below render
107120
//
108-
on = () => {
121+
on: SignaturePad['on'] = () => {
109122
window.addEventListener('resize', this._checkClearOnResize)
110123
return this._sigPad.on()
111124
}
112125

113-
off = () => {
126+
off: SignaturePad['off'] = () => {
114127
window.removeEventListener('resize', this._checkClearOnResize)
115128
return this._sigPad.off()
116129
}
117130

118-
clear = () => {
131+
clear: SignaturePad['clear'] = () => {
119132
return this._sigPad.clear()
120133
}
121134

122-
isEmpty = () => {
135+
isEmpty: SignaturePad['isEmpty'] = () => {
123136
return this._sigPad.isEmpty()
124137
}
125138

126-
fromDataURL = (dataURL, options) => {
139+
fromDataURL: SignaturePad['fromDataURL'] = (dataURL, options) => {
127140
return this._sigPad.fromDataURL(dataURL, options)
128141
}
129142

130-
toDataURL = (type, encoderOptions) => {
143+
toDataURL: SignaturePad['toDataURL'] = (type, encoderOptions) => {
131144
return this._sigPad.toDataURL(type, encoderOptions)
132145
}
133146

134-
fromData = (pointGroups) => {
147+
fromData: SignaturePad['fromData'] = (pointGroups) => {
135148
return this._sigPad.fromData(pointGroups)
136149
}
137150

138-
toData = () => {
151+
toData: SignaturePad['toData'] = () => {
139152
return this._sigPad.toData()
140153
}
141154
}

test/index.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { jest, describe, it, test, expect } from 'jest-without-globals'
22
import { mount } from 'enzyme'
33
import React from 'react'
44

5-
import SignatureCanvas from '../src/index.js'
5+
import SignatureCanvas from '../src/index.tsx'
66
import { propsF, dotF } from './fixtures.js'
77

88
test('mounts canvas and instance properly', () => {

tsconfig.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"include": ["src", "types"],
2+
"include": ["src", "typings"],
33
"compilerOptions": {
44
"module": "esnext",
55
"lib": ["dom", "esnext"],
@@ -18,6 +18,6 @@
1818
"*": ["src/*", "node_modules/*"]
1919
},
2020
"esModuleInterop": true,
21-
"allowJs": true
21+
"jsx": "react"
2222
}
2323
}

typings/trim-canvas.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module 'trim-canvas' {
2+
export default function trimCanvas (canvas: HTMLCanvasElement): HTMLCanvasElement
3+
}

0 commit comments

Comments
 (0)