├── .github └── workflows │ └── npm-publish.yml ├── .gitignore ├── .npmignore ├── README.md ├── index.ts ├── lib ├── signaturePad.scss ├── signaturePad.tsx └── utils │ ├── bezier.js │ ├── point.js │ ├── signature_pad.js │ ├── throttle.js │ └── util.js ├── package.json ├── tsconfig.json ├── types └── index.d.ts └── yarn.lock /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: Node.js Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: 12 18 | - run: npm install 19 | - run: npm install -g typescript 20 | - run: tsc 21 | 22 | publish-npm: 23 | needs: build 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v2 27 | - uses: actions/setup-node@v1 28 | with: 29 | node-version: 12 30 | registry-url: https://registry.npmjs.org/ 31 | - run: npm publish 32 | env: 33 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | *.js.map 4 | *.js 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.[aod] 2 | *.DS_Store 3 | .DS_Store 4 | *Thumbs.db 5 | *.iml 6 | .gradle 7 | .idea 8 | node_modules 9 | screenshots 10 | npm-debug.log 11 | lib/img/ 12 | lib/*.js.map -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # taro-signature-pad 2 | [![npm version](http://img.shields.io/npm/v/@yz1311/taro-signature-pad.svg?style=flat-square)](https://npmjs.org/package/@yz1311/taro-signature-pad "View this project on npm") 3 | [![npm version](http://img.shields.io/npm/dm/@yz1311/taro-signature-pad.svg?style=flat-square)](https://npmjs.org/package/@yz1311/taro-signature-pad "View this project on npm") 4 | 5 | taro的手写签名库 6 | 7 | 只支持taro3小程序,h5没有做兼容处理,只支持Canvas type="2d" 8 | 9 | ### 安装 10 | ``` 11 | npm install @yz1311/taro-signature-pad --save 12 | ``` 13 | 14 | 15 | ### 使用 16 | ``` 17 | import {SignaturePad} from "@yz1311/taro-signature-pad"; 18 | 19 | ... 20 | //组件默认是100%高宽 21 | 22 | 26 | ``` 27 | 28 | 29 | ### 方法 30 | 31 | #### isEmpty(): boolean 32 | 33 | 判断是否签名是空白的 34 | 35 | #### fromDataURL(dataUrl, options, callback): void 36 | 37 | 还原签名数据 38 | 39 | * `dataUrl`: 图片的base64数据 40 | * `options`: 选项 41 | * `callback`: 回调方法 42 | 43 | #### toDataURL(type, encoderOptions): string 44 | 45 | 获取签名数据 46 | 47 | 默认为png图片,实际调用的canvas的toDataURL函数,参考: 48 | 49 | https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL 50 | 51 | #### clear(): void 52 | 53 | 清空签名数据 54 | 55 | #### save(): void 56 | 57 | 将签名数据转换为png图片并且保存到系统相册 58 | 59 | 60 | ### 截图 61 | ![](https://tva1.sinaimg.cn/large/0081Kckwgy1gliuxzjhmsg309s0hsn1i.gif) 62 | 63 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import SignaturePad from "./lib/signaturePad"; 2 | 3 | export { 4 | SignaturePad, 5 | } 6 | -------------------------------------------------------------------------------- /lib/signaturePad.scss: -------------------------------------------------------------------------------- 1 | .sp-canvas { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /lib/signaturePad.tsx: -------------------------------------------------------------------------------- 1 | import React, {FC, useCallback, useEffect, useImperativeHandle, useRef} from "react"; 2 | import Taro from '@tarojs/taro'; 3 | import {Canvas, View} from "@tarojs/components"; 4 | import SignaturePadOrign from './utils/signature_pad.js' 5 | import './signaturePad.scss'; 6 | 7 | interface IProps { 8 | className?: string; 9 | style?: string; 10 | } 11 | 12 | const SignaturePad = React.forwardRef(({className, style}, ref)=>{ 13 | const canvasRef = useRef(); 14 | const signaturePadRef = useRef(new SignaturePadOrign()); 15 | 16 | const handleTouchStart = useCallback((e)=>{ 17 | signaturePadRef.current && signaturePadRef.current.handleTouchStart(e); 18 | },[]); 19 | 20 | const handleTouchMove = useCallback((e)=>{ 21 | signaturePadRef.current && signaturePadRef.current.handleTouchMove(e); 22 | },[]); 23 | 24 | const handleTouchEnd = useCallback((e)=>{ 25 | signaturePadRef.current && signaturePadRef.current.handleTouchEnd(e); 26 | },[]); 27 | 28 | const handleSaveCanvas = useCallback(() =>{ 29 | if(!canvasRef.current) { 30 | return; 31 | } 32 | //@ts-ignore 33 | Taro.canvasToTempFilePath({ 34 | canvas: canvasRef.current, 35 | }).then(res => { 36 | Taro.saveImageToPhotosAlbum({ 37 | filePath: `${res.tempFilePath}`, 38 | success(res) { 39 | Taro.showToast({ 40 | title: '保存成功' 41 | }); 42 | }, 43 | fail(err) { 44 | Taro.showToast({ 45 | title: '保存失败' 46 | }); 47 | } 48 | }) 49 | }).catch(e => { 50 | 51 | }); 52 | },[]); 53 | 54 | 55 | const handleClearCanvas = useCallback((e)=>{ 56 | signaturePadRef.current.clear(); 57 | }, []); 58 | 59 | const toDataURL = useCallback((type, encoderOptions)=>{ 60 | return signaturePadRef.current.toDataURL(type, encoderOptions); 61 | }, []); 62 | 63 | const isEmpty = useCallback(()=>{ 64 | return signaturePadRef.current.isEmpty(); 65 | }, []); 66 | 67 | const fromDataURL = useCallback((dataUrl, options = {}, callback)=>{ 68 | signaturePadRef.current.fromDataURL(dataUrl, options, callback);; 69 | }, []); 70 | 71 | useImperativeHandle(ref, ()=>({ 72 | save: handleSaveCanvas, 73 | clear: handleClearCanvas, 74 | toDataURL: toDataURL, 75 | isEmpty: isEmpty, 76 | fromDataURL: fromDataURL, 77 | })); 78 | 79 | useEffect(()=>{ 80 | Taro.nextTick(()=>{ 81 | //需要设置为type=2d才会不报错 82 | const query = Taro.createSelectorQuery().in(Taro.getCurrentInstance().page); 83 | query.select('.sp-canvas') 84 | .fields({ node: true, size: true }) 85 | .exec((res) => { 86 | const canvas = res[0].node 87 | const ctx = canvas.getContext('2d') 88 | 89 | const dpr = Taro.getSystemInfoSync().pixelRatio 90 | canvas.width = res[0].width * dpr 91 | canvas.height = res[0].height * dpr 92 | ctx.scale(dpr, dpr) 93 | 94 | signaturePadRef.current.init(canvas); 95 | canvasRef.current = canvas; 96 | }) 97 | }); 98 | }, []); 99 | 100 | return ( 101 | 112 | ); 113 | }); 114 | 115 | 116 | export default React.memo(SignaturePad); 117 | -------------------------------------------------------------------------------- /lib/utils/bezier.js: -------------------------------------------------------------------------------- 1 | import Point from './point'; 2 | 3 | export default class Bezier { 4 | constructor(startPoint, control2, control1, endPoint, startWidth, endWidth) { 5 | this.startPoint = startPoint; 6 | this.control2 = control2; 7 | this.control1 = control1; 8 | this.endPoint = endPoint; 9 | this.startWidth = startWidth; 10 | this.endWidth = endWidth; 11 | } 12 | static fromPoints(points, widths) { 13 | const c2 = this.calculateControlPoints(points[0], points[1], points[2]).c2; 14 | const c3 = this.calculateControlPoints(points[1], points[2], points[3]).c1; 15 | return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end); 16 | } 17 | static calculateControlPoints(s1, s2, s3) { 18 | const dx1 = s1.x - s2.x; 19 | const dy1 = s1.y - s2.y; 20 | const dx2 = s2.x - s3.x; 21 | const dy2 = s2.y - s3.y; 22 | const m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 }; 23 | const m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 }; 24 | const l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1)); 25 | const l2 = Math.sqrt((dx2 * dx2) + (dy2 * dy2)); 26 | const dxm = (m1.x - m2.x); 27 | const dym = (m1.y - m2.y); 28 | const k = l2 / (l1 + l2); 29 | const cm = { x: m2.x + (dxm * k), y: m2.y + (dym * k) }; 30 | const tx = s2.x - cm.x; 31 | const ty = s2.y - cm.y; 32 | return { 33 | c1: new Point(m1.x + tx, m1.y + ty), 34 | c2: new Point(m2.x + tx, m2.y + ty), 35 | }; 36 | } 37 | length() { 38 | const steps = 10; 39 | let length = 0; 40 | let px; 41 | let py; 42 | for (let i = 0; i <= steps; i += 1) { 43 | const t = i / steps; 44 | const cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x); 45 | const cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y); 46 | if (i > 0) { 47 | const xdiff = cx - px; 48 | const ydiff = cy - py; 49 | length += Math.sqrt((xdiff * xdiff) + (ydiff * ydiff)); 50 | } 51 | px = cx; 52 | py = cy; 53 | } 54 | return length; 55 | } 56 | point(t, start, c1, c2, end) { 57 | return (start * (1.0 - t) * (1.0 - t) * (1.0 - t)) 58 | + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t) 59 | + (3.0 * c2 * (1.0 - t) * t * t) 60 | + (end * t * t * t); 61 | } 62 | } -------------------------------------------------------------------------------- /lib/utils/point.js: -------------------------------------------------------------------------------- 1 | export default class Point { 2 | constructor(x, y, time) { 3 | this.x = x; 4 | this.y = y; 5 | this.time = time || Date.now(); 6 | } 7 | distanceTo(start) { 8 | return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2)); 9 | } 10 | equals(other) { 11 | return this.x === other.x && this.y === other.y && this.time === other.time; 12 | } 13 | velocityFrom(start) { 14 | return (this.time !== start.time) ? this.distanceTo(start) / (this.time - start.time) : 0; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/signature_pad.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The main idea and some parts of the code (e.g. drawing variable width Bézier curve) are taken from: 3 | * http://corner.squareup.com/2012/07/smoother-signatures.html 4 | * 5 | * Implementation of interpolation using cubic Bézier curves is taken from: 6 | * http://www.benknowscode.com/2012/09/path-interpolation-using-cubic-bezier_9742.html 7 | * 8 | * Algorithm for approximated length of a Bézier curve is taken from: 9 | * http://www.lemoda.net/maths/bezier-length/index.html 10 | */ 11 | 12 | import Bezier from './bezier'; 13 | import Point from './point'; 14 | import throttle from './throttle'; 15 | 16 | 17 | export default class SignaturePad { 18 | constructor(options = {}) { 19 | // this.canvas = canvas; 20 | this.options = options; 21 | 22 | this.velocityFilterWeight = options.velocityFilterWeight || 0.7; 23 | this.minWidth = options.minWidth || 0.5; 24 | this.maxWidth = options.maxWidth || 2.5; 25 | this.throttle = ('throttle' in options ? options.throttle : 16); 26 | this.minDistance = ('minDistance' in options ? options.minDistance : 5); 27 | if (this.throttle) { 28 | this._strokeMoveUpdate = throttle(SignaturePad.prototype._strokeUpdate, this.throttle); 29 | } 30 | else { 31 | this._strokeMoveUpdate = SignaturePad.prototype._strokeUpdate; 32 | } 33 | this.dotSize = options.dotSize || function () { 34 | return (this.minWidth + this.maxWidth) / 2; 35 | }; 36 | this.penColor = options.penColor || 'black'; 37 | this.backgroundColor = options.backgroundColor || 'rgba(0,0,0,0)'; 38 | this.onBegin = options.onBegin; 39 | this.onEnd = options.onEnd; 40 | // this._ctx = canvas.getContext('2d'); 41 | // this.clear(); 42 | // this.on(); 43 | } 44 | 45 | init = (canvas) => { 46 | this.canvas = canvas; 47 | this._ctx = canvas.getContext('2d'); 48 | this.clear(); 49 | } 50 | clear = () => { 51 | const ctx = this._ctx; 52 | const canvas = this.canvas; 53 | ctx.fillStyle = this.backgroundColor; 54 | ctx.clearRect(0, 0, canvas.width, canvas.height); 55 | ctx.fillRect(0, 0, canvas.width, canvas.height); 56 | this._data = []; 57 | this._reset(); 58 | this._isEmpty = true; 59 | } 60 | handleTouchStart = (event) => { 61 | // event.preventDefault(); 62 | if (event.touches.length === 1) { 63 | const touch = event.changedTouches[0]; 64 | this._strokeBegin(touch); 65 | } 66 | } 67 | handleTouchMove = (event) => { 68 | // event.preventDefault(); 69 | const touch = event.touches[0]; 70 | this._strokeMoveUpdate(touch); 71 | } 72 | handleTouchEnd = (event) => { 73 | const wasCanvasTouched = event.target === this.canvas; 74 | if (wasCanvasTouched) { 75 | // event.preventDefault(); 76 | const touch = event.changedTouches[0]; 77 | this._strokeEnd(touch); 78 | } 79 | } 80 | fromDataURL = (dataUrl, options = {}, callback) => { 81 | //下面的代码在小程序下面不兼容,所以还原前面暂未实现 82 | const image = new Image(); 83 | const ratio = options.ratio || 1; 84 | const width = options.width || (this.canvas.width / ratio); 85 | const height = options.height || (this.canvas.height / ratio); 86 | this._reset(); 87 | image.onload = () => { 88 | this._ctx.drawImage(image, 0, 0, width, height); 89 | if (callback) { 90 | callback(); 91 | } 92 | }; 93 | image.onerror = (error) => { 94 | if (callback) { 95 | callback(error); 96 | } 97 | }; 98 | image.src = dataUrl; 99 | this._isEmpty = false; 100 | } 101 | // 微信小程序canvas对象没有toDataURL函数,需要使用小程序canvas对象的canvasGetImageData 102 | toDataURL = (type = 'image/png', encoderOptions) => { 103 | switch (type) { 104 | default: 105 | return this.canvas.toDataURL(type, encoderOptions); 106 | } 107 | } 108 | isEmpty = () => { 109 | return this._isEmpty; 110 | } 111 | fromData(pointGroups) { 112 | this.clear(); 113 | this._fromData(pointGroups, ({ color, curve }) => this._drawCurve({ color, curve }), ({ color, point }) => this._drawDot({ color, point })); 114 | this._data = pointGroups; 115 | } 116 | toData() { 117 | return this._data; 118 | } 119 | _strokeBegin(event) { 120 | const newPointGroup = { 121 | color: this.penColor, 122 | points: [], 123 | }; 124 | this._data.push(newPointGroup); 125 | this._reset(); 126 | this._strokeUpdate(event); 127 | if (typeof this.onBegin === 'function') { 128 | this.onBegin(event); 129 | } 130 | } 131 | _strokeUpdate(event) { 132 | const x = event.x; 133 | const y = event.y; 134 | const point = this._createPoint(x, y); 135 | const lastPointGroup = this._data[this._data.length - 1]; 136 | const lastPoints = lastPointGroup.points; 137 | const lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1]; 138 | const isLastPointTooClose = lastPoint ? point.distanceTo(lastPoint) <= this.minDistance : false; 139 | const color = lastPointGroup.color; 140 | if (!lastPoint || !(lastPoint && isLastPointTooClose)) { 141 | const curve = this._addPoint(point); 142 | if (!lastPoint) { 143 | this._drawDot({ color, point }); 144 | } 145 | else if (curve) { 146 | this._drawCurve({ color, curve }); 147 | } 148 | lastPoints.push({ 149 | time: point.time, 150 | x: point.x, 151 | y: point.y, 152 | }); 153 | } 154 | } 155 | _strokeEnd(event) { 156 | this._strokeUpdate(event); 157 | if (typeof this.onEnd === 'function') { 158 | this.onEnd(event); 159 | } 160 | } 161 | _reset() { 162 | this._lastPoints = []; 163 | this._lastVelocity = 0; 164 | this._lastWidth = (this.minWidth + this.maxWidth) / 2; 165 | this._ctx.fillStyle = this.penColor; 166 | } 167 | _createPoint(x, y) { 168 | // const rect = this._ctx.canvas.getBoundingClientRect(); 169 | const rect = { 170 | left: 0, 171 | top: 0, 172 | } 173 | return new Point(x - rect.left, y - rect.top, new Date().getTime()); 174 | } 175 | _addPoint(point) { 176 | const { _lastPoints } = this; 177 | _lastPoints.push(point); 178 | if (_lastPoints.length > 2) { 179 | if (_lastPoints.length === 3) { 180 | _lastPoints.unshift(_lastPoints[0]); 181 | } 182 | const widths = this._calculateCurveWidths(_lastPoints[1], _lastPoints[2]); 183 | const curve = Bezier.fromPoints(_lastPoints, widths); 184 | _lastPoints.shift(); 185 | return curve; 186 | } 187 | return null; 188 | } 189 | _calculateCurveWidths(startPoint, endPoint) { 190 | const velocity = (this.velocityFilterWeight * endPoint.velocityFrom(startPoint)) 191 | + ((1 - this.velocityFilterWeight) * this._lastVelocity); 192 | const newWidth = this._strokeWidth(velocity); 193 | const widths = { 194 | end: newWidth, 195 | start: this._lastWidth, 196 | }; 197 | this._lastVelocity = velocity; 198 | this._lastWidth = newWidth; 199 | return widths; 200 | } 201 | _strokeWidth(velocity) { 202 | return Math.max(this.maxWidth / (velocity + 1), this.minWidth); 203 | } 204 | _drawCurveSegment(x, y, width) { 205 | const ctx = this._ctx; 206 | ctx.moveTo(x, y); 207 | ctx.arc(x, y, width, 0, 2 * Math.PI, false); 208 | this._isEmpty = false; 209 | } 210 | _drawCurve({ color, curve }) { 211 | const ctx = this._ctx; 212 | const widthDelta = curve.endWidth - curve.startWidth; 213 | const drawSteps = Math.floor(curve.length()) * 2; 214 | ctx.beginPath(); 215 | ctx.fillStyle = color; 216 | for (let i = 0; i < drawSteps; i += 1) { 217 | const t = i / drawSteps; 218 | const tt = t * t; 219 | const ttt = tt * t; 220 | const u = 1 - t; 221 | const uu = u * u; 222 | const uuu = uu * u; 223 | let x = uuu * curve.startPoint.x; 224 | x += 3 * uu * t * curve.control1.x; 225 | x += 3 * u * tt * curve.control2.x; 226 | x += ttt * curve.endPoint.x; 227 | let y = uuu * curve.startPoint.y; 228 | y += 3 * uu * t * curve.control1.y; 229 | y += 3 * u * tt * curve.control2.y; 230 | y += ttt * curve.endPoint.y; 231 | const width = curve.startWidth + (ttt * widthDelta); 232 | this._drawCurveSegment(x, y, width); 233 | } 234 | ctx.closePath(); 235 | ctx.fill(); 236 | } 237 | _drawDot({ color, point }) { 238 | const ctx = this._ctx; 239 | const width = typeof this.dotSize === 'function' ? this.dotSize() : this.dotSize; 240 | ctx.beginPath(); 241 | this._drawCurveSegment(point.x, point.y, width); 242 | ctx.closePath(); 243 | ctx.fillStyle = color; 244 | ctx.fill(); 245 | } 246 | _fromData(pointGroups, drawCurve, drawDot) { 247 | for (const group of pointGroups) { 248 | const { color, points } = group; 249 | if (points.length > 1) { 250 | for (let j = 0; j < points.length; j += 1) { 251 | const basicPoint = points[j]; 252 | const point = new Point(basicPoint.x, basicPoint.y, basicPoint.time); 253 | this.penColor = color; 254 | if (j === 0) { 255 | this._reset(); 256 | } 257 | const curve = this._addPoint(point); 258 | if (curve) { 259 | drawCurve({ color, curve }); 260 | } 261 | } 262 | } 263 | else { 264 | this._reset(); 265 | drawDot({ 266 | color, 267 | point: points[0], 268 | }); 269 | } 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /lib/utils/throttle.js: -------------------------------------------------------------------------------- 1 | export default function throttle(fn, wait = 250) { 2 | let previous = 0; 3 | let timeout = null; 4 | let result; 5 | let storedContext; 6 | let storedArgs; 7 | const later = () => { 8 | previous = Date.now(); 9 | timeout = null; 10 | result = fn.apply(storedContext, storedArgs); 11 | if (!timeout) { 12 | storedContext = null; 13 | storedArgs = []; 14 | } 15 | }; 16 | return function (...args) { 17 | const now = Date.now(); 18 | const remaining = wait - (now - previous); 19 | storedContext = this; 20 | storedArgs = args; 21 | if (remaining <= 0 || remaining > wait) { 22 | if (timeout) { 23 | clearTimeout(timeout); 24 | timeout = null; 25 | } 26 | previous = now; 27 | result = fn.apply(storedContext, storedArgs); 28 | if (!timeout) { 29 | storedContext = null; 30 | storedArgs = []; 31 | } 32 | } 33 | else if (!timeout) { 34 | timeout = setTimeout(later, remaining); 35 | } 36 | return result; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /lib/utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yz1311/taro-signature-pad", 3 | "version": "0.0.1", 4 | "description": "taro3手写签名库", 5 | "main": "index.js", 6 | "types": "types/index.d.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/yz1311/taro-signature-pad.git" 13 | }, 14 | "publishConfig": { 15 | "access": "public" 16 | }, 17 | "keywords": [ 18 | "taro", 19 | "taro3", 20 | "signature", 21 | "signature-pad", 22 | "signature pad" 23 | ], 24 | "author": "yz1311", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/yz1311/taro-signature-pad/issues" 28 | }, 29 | "homepage": "https://github.com/yz1311/taro-signature-pad#readme", 30 | "dependencies": { 31 | 32 | }, 33 | "devDependencies": { 34 | "@types/react": "^16.9.17", 35 | "@types/node": "^14.14.10", 36 | "@tarojs/components": "^3.0.11", 37 | "@tarojs/taro": "^3.0.11", 38 | "react": "^16.10.0", 39 | "typescript": "^3.5.2", 40 | "classnames": "^2.2.6" 41 | }, 42 | "peerDependencies": { 43 | "@tarojs/taro": "^3.0.0", 44 | "react": "^16.10.0", 45 | "classnames": "^2.2.6" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2015", 4 | "target": "es2015", 5 | "moduleResolution": "node", 6 | "jsx": "react", 7 | "jsxFactory": "React.createElement", 8 | "noImplicitAny": false, 9 | "experimentalDecorators": true, 10 | "preserveConstEnums": true, 11 | "sourceMap": true, 12 | "watch": false, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "allowSyntheticDefaultImports": true, 16 | "lib": [ 17 | "es2015.promise", 18 | "es2015", 19 | "es2016", 20 | "dom" 21 | ] 22 | }, 23 | "filesGlob": [ 24 | "components/**/*.ts", 25 | "themes/**/*.tsx" 26 | ], 27 | "exclude": [ 28 | "build", 29 | "node_modules" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import SignaturePad from "../lib/signaturePad"; 2 | 3 | export { 4 | SignaturePad, 5 | } 6 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/runtime@^7.1.2": 6 | version "7.12.5" 7 | resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" 8 | integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== 9 | dependencies: 10 | regenerator-runtime "^0.13.4" 11 | 12 | "@stencil/core@~1.8.1": 13 | version "1.8.12" 14 | resolved "https://registry.npmjs.org/@stencil/core/-/core-1.8.12.tgz#03d54cda940d2ca3a0eff5e839435815db6c3848" 15 | integrity sha512-/YCfLrtsHKYmFtI46e26eTW80TnODs6ugjWPbajc9Iclia4Leo3gZs9nZTW81iZGKs2MUOuab8r2r5UM8qTvnw== 16 | dependencies: 17 | typescript "3.8.2" 18 | 19 | "@tarojs/api@3.0.16": 20 | version "3.0.16" 21 | resolved "https://registry.npmjs.org/@tarojs/api/-/api-3.0.16.tgz#98f0ce04748967959a2ab72684317cbe764ce407" 22 | integrity sha512-sktI7C10M2E/wK3VZTbIM0sSMMR63sZhv651sYiJ8Ti7ZngxJYI/WoUM/ZVJPALGYGO/j87prmFMBjcEl5kcMg== 23 | dependencies: 24 | "@tarojs/runtime" "3.0.16" 25 | 26 | "@tarojs/components@^3.0.11": 27 | version "3.0.16" 28 | resolved "https://registry.npmjs.org/@tarojs/components/-/components-3.0.16.tgz#70e84c7ddafe5e0a25db48ceef21195bce336249" 29 | integrity sha512-CX9cU59sCb9La2c9gTHVLKnBJomcx41vCbv+1FmmLsEVUtZrqsYQYBaB81X6rqJeaBX8N/dkhFHNUXfZDZJo2Q== 30 | dependencies: 31 | "@stencil/core" "~1.8.1" 32 | "@tarojs/taro" "3.0.16" 33 | better-scroll "^1.14.1" 34 | classnames "^2.2.5" 35 | intersection-observer "^0.7.0" 36 | omit.js "^1.0.0" 37 | resolve-pathname "^3.0.0" 38 | swiper "4.4.2" 39 | weui "^1.1.2" 40 | 41 | "@tarojs/router@3.0.16": 42 | version "3.0.16" 43 | resolved "https://registry.npmjs.org/@tarojs/router/-/router-3.0.16.tgz#76b48bb4c3c919f382ddc433f8ba183a95620475" 44 | integrity sha512-Gbrirv06a5bJTr5pV6lOXyUd3bk2gde3EJXC1KF1DGC95L+rx6hCtwzzorFNH02227z2Y19I4SQY2Wl9GhKafg== 45 | dependencies: 46 | "@tarojs/runtime" "3.0.16" 47 | history "^4.10.1" 48 | universal-router "^8.3.0" 49 | url-parse "^1.4.7" 50 | 51 | "@tarojs/runtime@3.0.16": 52 | version "3.0.16" 53 | resolved "https://registry.npmjs.org/@tarojs/runtime/-/runtime-3.0.16.tgz#3bb31fe4317ebc0e920c1aa48759fc35715e93ae" 54 | integrity sha512-iksPOzFwctdQC/BvOAlS6APUpNFY4iUbZ98ZC6rhl91QIWjJKX21tzBQ5mP09V3qo7HpkdSwtpsGPkehUcHqSw== 55 | 56 | "@tarojs/taro-h5@3.0.16": 57 | version "3.0.16" 58 | resolved "https://registry.npmjs.org/@tarojs/taro-h5/-/taro-h5-3.0.16.tgz#97834f64be0ca9e53033d0f145f140b9116bc9fd" 59 | integrity sha512-H4JvFQ2V/APzQakex+QpQnYgHyvBu/GphxmL88W9CRr1Z9IaLoycGJEnGlYQ6ah2r5iyAeV1ZqYd6lQ3AiqeNQ== 60 | dependencies: 61 | "@tarojs/api" "3.0.16" 62 | "@tarojs/router" "3.0.16" 63 | "@tarojs/runtime" "3.0.16" 64 | base64-js "^1.3.0" 65 | jsonp-retry "^1.0.3" 66 | mobile-detect "^1.4.2" 67 | raf "^3.4.1" 68 | whatwg-fetch "^3.4.0" 69 | 70 | "@tarojs/taro@3.0.16", "@tarojs/taro@^3.0.11": 71 | version "3.0.16" 72 | resolved "https://registry.npmjs.org/@tarojs/taro/-/taro-3.0.16.tgz#1c88cdb87c093db652e5008d6532da17b4e9b776" 73 | integrity sha512-DRoQ7d1RsMMw1+Bp35BFMcFbyunNFoodyVROcztXRYDfllapEUV6K/pJz/ucGAHWgZeEtzZXoJRP5k6susqNWA== 74 | dependencies: 75 | "@tarojs/api" "3.0.16" 76 | "@tarojs/taro-h5" "3.0.16" 77 | 78 | "@types/node@^14.14.10": 79 | version "14.14.11" 80 | resolved "https://registry.npmjs.org/@types/node/-/node-14.14.11.tgz#fc25a4248a5e8d0837019b1d170146d07334abe0" 81 | integrity sha512-BJ97wAUuU3NUiUCp44xzUFquQEvnk1wu7q4CMEUYKJWjdkr0YWYDsm4RFtAvxYsNjLsKcrFt6RvK8r+mnzMbEQ== 82 | 83 | "@types/prop-types@*": 84 | version "15.7.3" 85 | resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" 86 | integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== 87 | 88 | "@types/react@^16.9.17": 89 | version "16.9.56" 90 | resolved "https://registry.npmjs.org/@types/react/-/react-16.9.56.tgz#ea25847b53c5bec064933095fc366b1462e2adf0" 91 | integrity sha512-gIkl4J44G/qxbuC6r2Xh+D3CGZpJ+NdWTItAPmZbR5mUS+JQ8Zvzpl0ea5qT/ZT3ZNTUcDKUVqV3xBE8wv/DyQ== 92 | dependencies: 93 | "@types/prop-types" "*" 94 | csstype "^3.0.2" 95 | 96 | babel-runtime@^6.0.0, babel-runtime@^6.23.0: 97 | version "6.26.0" 98 | resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" 99 | integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= 100 | dependencies: 101 | core-js "^2.4.0" 102 | regenerator-runtime "^0.11.0" 103 | 104 | base64-js@^1.3.0: 105 | version "1.3.1" 106 | resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" 107 | integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== 108 | 109 | better-scroll@^1.14.1: 110 | version "1.15.2" 111 | resolved "https://registry.npmjs.org/better-scroll/-/better-scroll-1.15.2.tgz#65ffc6058b8b4ff337b8dfad4bcb334d7699ceb6" 112 | integrity sha512-sSY2N8I9/B+YX/9JpIz6pMQYnmBuvspBqZG4UxYaQEfz/ZWrnxwdyKLL4t6IKpFmxqtZadVypXw7vSSHxBZpBQ== 113 | dependencies: 114 | babel-runtime "^6.0.0" 115 | 116 | classnames@^2.2.5, classnames@^2.2.6: 117 | version "2.2.6" 118 | resolved "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" 119 | integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== 120 | 121 | core-js@^2.4.0: 122 | version "2.6.11" 123 | resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" 124 | integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== 125 | 126 | csstype@^3.0.2: 127 | version "3.0.4" 128 | resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.4.tgz#b156d7be03b84ff425c9a0a4b1e5f4da9c5ca888" 129 | integrity sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA== 130 | 131 | dom7@^2.1.2: 132 | version "2.1.5" 133 | resolved "https://registry.npmjs.org/dom7/-/dom7-2.1.5.tgz#a79411017800b31d8400070cdaebbfc92c1f6377" 134 | integrity sha512-xnhwVgyOh3eD++/XGtH+5qBwYTgCm0aW91GFgPJ3XG+jlsRLyJivnbP0QmUBFhI+Oaz9FV0s7cxgXHezwOEBYA== 135 | dependencies: 136 | ssr-window "^2.0.0" 137 | 138 | history@^4.10.1: 139 | version "4.10.1" 140 | resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" 141 | integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== 142 | dependencies: 143 | "@babel/runtime" "^7.1.2" 144 | loose-envify "^1.2.0" 145 | resolve-pathname "^3.0.0" 146 | tiny-invariant "^1.0.2" 147 | tiny-warning "^1.0.0" 148 | value-equal "^1.0.1" 149 | 150 | intersection-observer@^0.7.0: 151 | version "0.7.0" 152 | resolved "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz#ee16bee978db53516ead2f0a8154b09b400bbdc9" 153 | integrity sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg== 154 | 155 | "js-tokens@^3.0.0 || ^4.0.0": 156 | version "4.0.0" 157 | resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 158 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 159 | 160 | jsonp-retry@^1.0.3: 161 | version "1.0.3" 162 | resolved "https://registry.npmjs.org/jsonp-retry/-/jsonp-retry-1.0.3.tgz#9e6b18b02ec767a621dd44b4e99439a8a43a6419" 163 | integrity sha512-/jmE9+shtKP+oIt2AWO9Wx+C27NTGpLCEw4QHOqpoV2X6ta374HE9C+EEdgu8r3iLKgFMx7u5j0mCwxWN8UdlA== 164 | dependencies: 165 | object-assign "^4.1.1" 166 | 167 | loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.4.0: 168 | version "1.4.0" 169 | resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 170 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 171 | dependencies: 172 | js-tokens "^3.0.0 || ^4.0.0" 173 | 174 | mobile-detect@^1.4.2: 175 | version "1.4.4" 176 | resolved "https://registry.npmjs.org/mobile-detect/-/mobile-detect-1.4.4.tgz#686c74e92d3cc06b09a9b3594b7b981494b137f6" 177 | integrity sha512-vTgEjKjS89C5yHL5qWPpT6BzKuOVqABp+A3Szpbx34pIy3sngxlGaFpgHhfj6fKze1w0QKeOSDbU7SKu7wDvRQ== 178 | 179 | object-assign@^4.1.1: 180 | version "4.1.1" 181 | resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 182 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 183 | 184 | omit.js@^1.0.0: 185 | version "1.0.2" 186 | resolved "https://registry.npmjs.org/omit.js/-/omit.js-1.0.2.tgz#91a14f0eba84066dfa015bf30e474c47f30bc858" 187 | integrity sha512-/QPc6G2NS+8d4L/cQhbk6Yit1WTB6Us2g84A7A/1+w9d/eRGHyEqC5kkQtHVoHZ5NFWGG7tUGgrhVZwgZanKrQ== 188 | dependencies: 189 | babel-runtime "^6.23.0" 190 | 191 | path-to-regexp@^3.1.0: 192 | version "3.2.0" 193 | resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f" 194 | integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA== 195 | 196 | performance-now@^2.1.0: 197 | version "2.1.0" 198 | resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" 199 | integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= 200 | 201 | prop-types@^15.6.2: 202 | version "15.7.2" 203 | resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" 204 | integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== 205 | dependencies: 206 | loose-envify "^1.4.0" 207 | object-assign "^4.1.1" 208 | react-is "^16.8.1" 209 | 210 | querystringify@^2.1.1: 211 | version "2.2.0" 212 | resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" 213 | integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== 214 | 215 | raf@^3.4.1: 216 | version "3.4.1" 217 | resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" 218 | integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== 219 | dependencies: 220 | performance-now "^2.1.0" 221 | 222 | react-is@^16.8.1: 223 | version "16.13.1" 224 | resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" 225 | integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== 226 | 227 | react@^16.10.0: 228 | version "16.14.0" 229 | resolved "https://registry.npmjs.org/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" 230 | integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== 231 | dependencies: 232 | loose-envify "^1.1.0" 233 | object-assign "^4.1.1" 234 | prop-types "^15.6.2" 235 | 236 | regenerator-runtime@^0.11.0: 237 | version "0.11.1" 238 | resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" 239 | integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== 240 | 241 | regenerator-runtime@^0.13.4: 242 | version "0.13.7" 243 | resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" 244 | integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== 245 | 246 | requires-port@^1.0.0: 247 | version "1.0.0" 248 | resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" 249 | integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= 250 | 251 | resolve-pathname@^3.0.0: 252 | version "3.0.0" 253 | resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" 254 | integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== 255 | 256 | ssr-window@^1.0.1: 257 | version "1.0.1" 258 | resolved "https://registry.npmjs.org/ssr-window/-/ssr-window-1.0.1.tgz#30752a6a4666e7767f0b7e6aa6fc2fdbd0d9b369" 259 | integrity sha512-dgFqB+f00LJTEgb6UXhx0h+SrG50LJvti2yMKMqAgzfUmUXZrLSv2fjULF7AWGwK25EXu8+smLR3jYsJQChPsg== 260 | 261 | ssr-window@^2.0.0: 262 | version "2.0.0" 263 | resolved "https://registry.npmjs.org/ssr-window/-/ssr-window-2.0.0.tgz#98c301aef99523317f8d69618f0010791096efc4" 264 | integrity sha512-NXzN+/HPObKAx191H3zKlYomE5WrVIkoCB5IaSdvKokxTpjBdWfr0RaP+1Z5KOfDT0ZVz+2tdtiBkhsEQ9p+0A== 265 | 266 | swiper@4.4.2: 267 | version "4.4.2" 268 | resolved "https://registry.npmjs.org/swiper/-/swiper-4.4.2.tgz#3a35237cbf4870034784e158b4197b65b763d647" 269 | integrity sha512-Vfl4Zw4Z7iZwUu5S11JeC7OSy4nwky29nkUulkmg8lIqcWla6UtOhdap0gkyJRYS+UJXki+GWQsbFM0SZRxZPQ== 270 | dependencies: 271 | dom7 "^2.1.2" 272 | ssr-window "^1.0.1" 273 | 274 | tiny-invariant@^1.0.2: 275 | version "1.1.0" 276 | resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" 277 | integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== 278 | 279 | tiny-warning@^1.0.0: 280 | version "1.0.3" 281 | resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" 282 | integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== 283 | 284 | typescript@3.8.2: 285 | version "3.8.2" 286 | resolved "https://registry.npmjs.org/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a" 287 | integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ== 288 | 289 | typescript@^3.5.2: 290 | version "3.9.7" 291 | resolved "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" 292 | integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== 293 | 294 | universal-router@^8.3.0: 295 | version "8.3.0" 296 | resolved "https://registry.npmjs.org/universal-router/-/universal-router-8.3.0.tgz#533bce135d7b1abf591421c5d2028d54407a34a0" 297 | integrity sha512-cBkihRoHvRQAjdUnDE1GGuuw/TPAIi8z2pEsSmUVAWLeZdgjHzzAb1+0VOO6NvBOvySItOTQikzaGlRxRdJBnA== 298 | dependencies: 299 | path-to-regexp "^3.1.0" 300 | 301 | url-parse@^1.4.7: 302 | version "1.4.7" 303 | resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" 304 | integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== 305 | dependencies: 306 | querystringify "^2.1.1" 307 | requires-port "^1.0.0" 308 | 309 | value-equal@^1.0.1: 310 | version "1.0.1" 311 | resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" 312 | integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== 313 | 314 | weui@^1.1.2: 315 | version "1.1.3" 316 | resolved "https://registry.npmjs.org/weui/-/weui-1.1.3.tgz#0f0899bb61bb2ec603b2648367a8139298f81514" 317 | integrity sha512-vC6eWUvG1MYoE8yLsvBBmLB2+4DZWynQOL47MUscHMwPVltOZPGsiRb2PE7y3z+w3ElF1SsmJsyhr40wiXgP5A== 318 | 319 | whatwg-fetch@^3.4.0: 320 | version "3.5.0" 321 | resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz#605a2cd0a7146e5db141e29d1c62ab84c0c4c868" 322 | integrity sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A== 323 | --------------------------------------------------------------------------------