react-native-signature-canvas 4.7.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # react-native-signature-canvas
1
+ # React Native Signature Canvas
2
2
 
3
3
  [![](https://img.shields.io/npm/l/react-native-signature-canvas.svg)](https://www.npmjs.com/package/react-native-signature-canvas)
4
4
  [![](https://img.shields.io/npm/v/react-native-signature-canvas)](https://www.npmjs.com/package/react-native-signature-canvas)
@@ -6,15 +6,27 @@
6
6
  ![GitHub last commit](https://img.shields.io/github/last-commit/yanyuanfe/react-native-signature-canvas)
7
7
  [![runs with expo](https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat&logo=EXPO&labelColor=f3f3f3&logoColor=000)](https://github.com/expo/expo)
8
8
 
9
- React Native Signature Component based Canvas for Android && IOS && expo
9
+ A React Native component for capturing signatures or drawing on a canvas with a smooth, native feel. Works on iOS, Android, and Expo.
10
10
 
11
- - Supports Android and iOS and Expo
12
- - Tested with RN 0.69
13
- - Core use [signature_pad.js](https://github.com/szimek/signature_pad)
14
- - Generates a base64 encoded png image of the signature
15
- Note: Expo support for React Native Signature Canvas v1.5.0 started with Expo SDK v33.0.0.
11
+ ## Features
16
12
 
17
- ## Installation(for React Native V0.60.0 or Expo SDK v35.0.0)
13
+ - **Cross-platform support** (iOS, Android, Expo)
14
+ - ✅ **Smooth, responsive drawing experience** with optimized performance
15
+ - ✅ **Customizable pen color, size, and background**
16
+ - ✅ **Support for background and overlay images**
17
+ - ✅ **Export signatures** as PNG, JPEG, or SVG
18
+ - ✅ **Undo/redo functionality**
19
+ - ✅ **Drawing and erasing modes**
20
+ - ✅ **Full TypeScript support** with enhanced type definitions
21
+ - 🆕 **Advanced error handling** with automatic recovery
22
+ - 🆕 **Performance monitoring** and optimization
23
+ - 🆕 **Flexible WebView customization** via `webviewProps`
24
+ - 🆕 **Enhanced security** with configurable restrictions
25
+ - 🆕 **Memory management** and leak prevention
26
+
27
+ ## Installation
28
+
29
+ ### For React Native ≥ 0.60.0 or Expo SDK ≥ 35.0.0
18
30
 
19
31
  ```bash
20
32
  yarn add react-native-signature-canvas
@@ -26,142 +38,247 @@ or
26
38
  npm install --save react-native-signature-canvas
27
39
  ```
28
40
 
29
- > This package depends on [react-native-webview](https://github.com/react-native-webview/react-native-webview#readme) and it is particularly needed when you are using **_React Native CLI_**. To install `react-native-webview` follow the steps mentioned [here](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Getting-Started.md)
30
-
41
+ > This package depends on [react-native-webview](https://github.com/react-native-webview/react-native-webview). If you're using React Native CLI (not Expo), you'll need to install react-native-webview separately:
42
+ >
43
+ > ```bash
44
+ > yarn add react-native-webview
45
+ > cd ios && pod install
46
+ > ```
31
47
 
32
-
33
- ## Installation(for React Native V0.5x.x or Expo SDK < v33)
48
+ ### For React Native < 0.60.0 or Expo SDK < 33.0.0
34
49
 
35
50
  ```bash
36
51
  npm install --save react-native-signature-canvas@1.4.2
37
52
  ```
38
53
 
39
- ## Usage
40
- Basic
41
- ```js
42
- import Signature from "react-native-signature-canvas";
43
- ```
44
- Custom
45
- ```js
46
- import SignatureScreen from 'react-native-signature-canvas';
47
- ```
48
-
49
- ## Properties
50
-
51
- ---
52
-
53
- | Prop | Type | Description |
54
- |:------------------------------------|:----------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------|
55
- | androidHardwareAccelerationDisabled | `boolean` | androidHardwareAccelerationDisabled for react-native-webview. Default is false |
56
- | autoClear | `boolean` | should auto clear the signature after clicking the Confirm button |
57
- | backgroundColor | `string` | default is "rgba(255,255,255,0)" (_transparent_), background color of the canvas |
58
- | bgHeight | `number` | height of the background image |
59
- | bgWidth | `number` | width of the background image |
60
- | bgSrc | `string` | background image source uri (_url_) |
61
- | clearText | `string` | clear button text |
62
- | confirmText | `string` | save button text |
63
- | customHtml | `(injectedJavaScript: string) => string` | html string that lets you modify things like the layout or elements |
64
- | dataURL | `string` | default is "", Base64 string, draws saved signature from dataURL. |
65
- | descriptionText | `string` | description text for signature |
66
- | dotSize | `number` | radius of a single dot _(not stroke width)_ |
67
- | imageType | `string` | "image/png" (_default_), "image/jpeg"、"image/svg+xml", imageType of exported signature |
68
- | minWidth | `number` | minimum width of a line. Defaults to 0.5 |
69
- | maxWidth | `number` | maximum width of a line. Defaults to 2.5 |
70
- | nestedScrollEnabled | `boolean` | enable nested scrolling for use inside of a scrollview |
71
- | showsVerticalScrollIndicator | `boolean` | Boolean value that determines whether a vertical scroll indicator is shown in the `WebView`, The default value is `true`. |
72
- | onOK | `function` | callback function after saving non-empty signature |
73
- | onEmpty | `function` | callback function after trying to save an empty signature |
74
- | onClear | `function` | callback function after clearing the signature |
75
- | onGetData | `function` | callback function when getData() is called
76
- | onBegin | `function` | callback function when a new stroke is started |
77
- | onEnd | `function` | callback function when the stroke has ended |
78
- | onLoadEnd | `function` | callback function when the webview canvas load ended |
79
- | onUndo | `function` | callback function when undo() is called |
80
- | onRedo | `function` | callback function when redo() is called |
81
- | onDraw | `function` | callback function when drawing is enabled |
82
- | onErase | `function` | callback function when erasing is enabled |
83
- | onChangePenColor | `function` | callback function after changing the pen color |
84
- | onChangePenSize | `function` | callback function after changing the pen size
85
- | overlayHeight | `number` | height of the overlay image |
86
- | overlayWidth | `number` | width of the overlay image |
87
- | overlaySrc | `string` | overlay image source uri (url) _must be .png with a transparent background_
88
- | penColor | `string` | default is "black", color of pen |
89
- | rotated | `boolean` | rotate signature pad 90 degrees |
90
- | style | `object` | style of wrapper view |
91
- | trimWhitespace | `boolean` | trim image whitespace |
92
- | webStyle | `string` | webview style for overwrite default style, all style: https://github.com/YanYuanFE/react-native-signature-canvas/blob/master/h5/css/signature-pad.css |
93
- | androidLayerType | `none、software、hardware` | Sets the android webview layerType |
94
-
95
- ## Methods
96
-
97
- ---
54
+ ## Basic Usage
98
55
 
99
- | Function | Description |
100
- | :-------------------- | :-----------------------------------------------------------------------------------------------|
101
- | clearSignature() | Clear the current signature |
102
- | changePenColor(color) | Change pen color |
103
- | changePenSize(minW, maxW) | Change pen size |
104
- | draw() | Enable drawing signature |
105
- | erase() | Enable erasing signature |
106
- | getData() | Triggers the `onGetData` callback with a single `data` JSON string |
107
- | readSignature() | Reads the current signature on the canvas and triggers either the `onOK` or `onEmpty` callbacks |
108
- | undo() | Undo last stroke |
109
- | redo() | Redo last stroke |
56
+ ```jsx
57
+ import React, { useRef, useState } from 'react';
58
+ import { StyleSheet, View, Image } from 'react-native';
59
+ import SignatureCanvas from 'react-native-signature-canvas';
110
60
 
111
- To call the methods use the `useRef` hook:
112
-
113
- ```js
114
- import SignatureScreen from "react-native-signature-canvas";
115
-
116
- const Sign = ({ text, onOK }) => {
61
+ const SignatureScreen = () => {
62
+ const [signature, setSignature] = useState(null);
63
+ const [isLoading, setIsLoading] = useState(false);
117
64
  const ref = useRef();
118
65
 
119
- // Called after ref.current.readSignature() reads a non-empty base64 string
120
- const handleOK = (signature) => {
121
- console.log(signature);
122
- onOK(signature); // Callback from Component props
66
+ const handleSignature = (signature) => {
67
+ console.log('Signature captured:', signature);
68
+ setSignature(signature);
69
+ setIsLoading(false);
123
70
  };
124
71
 
125
- // Called after ref.current.readSignature() reads an empty string
126
72
  const handleEmpty = () => {
127
- console.log("Empty");
73
+ console.log('Signature is empty');
74
+ setIsLoading(false);
128
75
  };
129
76
 
130
- // Called after ref.current.clearSignature()
131
77
  const handleClear = () => {
132
- console.log("clear success!");
78
+ console.log('Signature cleared');
79
+ setSignature(null);
133
80
  };
134
81
 
135
- // Called after end of stroke
136
- const handleEnd = () => {
137
- ref.current.readSignature();
82
+ const handleError = (error) => {
83
+ console.error('Signature pad error:', error);
84
+ setIsLoading(false);
138
85
  };
139
86
 
140
- // Called after ref.current.getData()
141
- const handleData = (data) => {
142
- console.log(data);
87
+ const handleEnd = () => {
88
+ setIsLoading(true);
89
+ ref.current?.readSignature();
143
90
  };
144
91
 
145
92
  return (
146
- <SignatureScreen
147
- ref={ref}
148
- onEnd={handleEnd}
149
- onOK={handleOK}
150
- onEmpty={handleEmpty}
151
- onClear={handleClear}
152
- onGetData={handleData}
153
- autoClear={true}
154
- descriptionText={text}
155
- />
93
+ <View style={styles.container}>
94
+ <View style={styles.preview}>
95
+ {signature && (
96
+ <Image
97
+ resizeMode="contain"
98
+ style={{ width: 335, height: 114 }}
99
+ source={{ uri: signature }}
100
+ />
101
+ )}
102
+ </View>
103
+ <SignatureCanvas
104
+ ref={ref}
105
+ onEnd={handleEnd}
106
+ onOK={handleSignature}
107
+ onEmpty={handleEmpty}
108
+ onClear={handleClear}
109
+ onError={handleError}
110
+ autoClear={true}
111
+ descriptionText="Sign here"
112
+ clearText="Clear"
113
+ confirmText={isLoading ? "Processing..." : "Save"}
114
+ penColor="#000000"
115
+ backgroundColor="rgba(255,255,255,0)"
116
+ webviewProps={{
117
+ // Custom WebView optimization
118
+ cacheEnabled: true,
119
+ androidLayerType: "hardware",
120
+ }}
121
+ />
122
+ </View>
156
123
  );
157
124
  };
158
125
 
159
- export default Sign;
126
+ const styles = StyleSheet.create({
127
+ container: {
128
+ flex: 1,
129
+ },
130
+ preview: {
131
+ width: 335,
132
+ height: 114,
133
+ backgroundColor: '#F8F8F8',
134
+ justifyContent: 'center',
135
+ alignItems: 'center',
136
+ marginTop: 15,
137
+ },
138
+ });
139
+
140
+ export default SignatureScreen;
160
141
  ```
161
- ## Using a background image
162
- You can use a non-erasable background image to draw your signature on using the `bgSrc` prop. Make sure to provide the width and height of the image.
163
142
 
164
- ```js
143
+ ## Props
144
+
145
+ | Prop | Type | Default | Description |
146
+ |------|------|---------|-------------|
147
+ | `androidHardwareAccelerationDisabled` | `boolean` | `false` | Disable hardware acceleration on Android |
148
+ | `autoClear` | `boolean` | `false` | Auto clear signature after clicking the Confirm button |
149
+ | `backgroundColor` | `string` | `rgba(255,255,255,0)` | Background color of the canvas |
150
+ | `bgHeight` | `number` | `0` | Height of the background image |
151
+ | `bgWidth` | `number` | `0` | Width of the background image |
152
+ | `bgSrc` | `string` | `null` | Background image source URI |
153
+ | `clearText` | `string` | `Clear` | Clear button text |
154
+ | `confirmText` | `string` | `Confirm` | Save button text |
155
+ | `customHtml` | `(injectedJavaScript: string) => string` | `null` | Custom HTML template for the canvas |
156
+ | `dataURL` | `string` | `""` | Base64 string to draw saved signature |
157
+ | `descriptionText` | `string` | `Sign above` | Description text for signature |
158
+ | `dotSize` | `number` | `null` | Radius of a single dot |
159
+ | `imageType` | `string` | `image/png` | Image type for export (`image/png`, `image/jpeg`, `image/svg+xml`) |
160
+ | `minWidth` | `number` | `0.5` | Minimum width of a line |
161
+ | `maxWidth` | `number` | `2.5` | Maximum width of a line |
162
+ | `nestedScrollEnabled` | `boolean` | `false` | Enable nested scrolling for use inside a ScrollView |
163
+ | `showsVerticalScrollIndicator` | `boolean` | `true` | Show vertical scroll indicator in WebView |
164
+ | `onOK` | `function` | - | Callback after saving non-empty signature |
165
+ | `onEmpty` | `function` | - | Callback after trying to save an empty signature |
166
+ | `onClear` | `function` | - | Callback after clearing the signature |
167
+ | `onGetData` | `function` | - | Callback when getData() is called |
168
+ | `onBegin` | `function` | - | Callback when a new stroke is started |
169
+ | `onEnd` | `function` | - | Callback when the stroke has ended |
170
+ | `onLoadEnd` | `function` | - | Callback when the WebView canvas load ended |
171
+ | `onUndo` | `function` | - | Callback when undo() is called |
172
+ | `onRedo` | `function` | - | Callback when redo() is called |
173
+ | `onDraw` | `function` | - | Callback when drawing is enabled |
174
+ | `onErase` | `function` | - | Callback when erasing is enabled |
175
+ | `onChangePenColor` | `function` | - | Callback after changing the pen color |
176
+ | `onChangePenSize` | `function` | - | Callback after changing the pen size |
177
+ | `overlayHeight` | `number` | `0` | Height of the overlay image |
178
+ | `overlayWidth` | `number` | `0` | Width of the overlay image |
179
+ | `overlaySrc` | `string` | `null` | Overlay image source URI (must be PNG with transparent background) |
180
+ | `penColor` | `string` | `black` | Color of the pen |
181
+ | `rotated` | `boolean` | `false` | Rotate signature pad 90 degrees |
182
+ | `style` | `object` | - | Style of the wrapper view |
183
+ | `scrollable` | `boolean` | `false` | Enable scrolling in the signature pad |
184
+ | `trimWhitespace` | `boolean` | `false` | Trim image whitespace |
185
+ | `webStyle` | `string` | - | WebView style to override default style |
186
+ | `webviewContainerStyle` | `object` | - | Style for the WebView container |
187
+ | `androidLayerType` | `none\|software\|hardware` | `hardware` | Sets the Android WebView layer type |
188
+ | `onError` | `function` | - | Callback when an error occurs |
189
+ | `webviewProps` | `object` | `{}` | Additional props to pass to the underlying WebView |
190
+
191
+ ## Methods
192
+
193
+ Access these methods using a ref to the SignatureCanvas component.
194
+
195
+ | Method | Description |
196
+ |--------|-------------|
197
+ | `clearSignature()` | Clear the current signature |
198
+ | `changePenColor(color)` | Change pen color |
199
+ | `changePenSize(minW, maxW)` | Change pen size |
200
+ | `draw()` | Enable drawing mode |
201
+ | `erase()` | Enable erasing mode |
202
+ | `getData()` | Triggers the `onGetData` callback with signature data |
203
+ | `readSignature()` | Read the current signature and trigger callbacks |
204
+ | `undo()` | Undo last stroke |
205
+ | `redo()` | Redo last stroke |
206
+
207
+ ## WebView Customization (New!)
208
+
209
+ The `webviewProps` parameter allows you to customize the underlying WebView behavior while maintaining signature functionality:
210
+
211
+ ```jsx
212
+ <SignatureCanvas
213
+ // ... other props
214
+ webviewProps={{
215
+ // Performance optimization
216
+ cacheEnabled: true,
217
+ androidLayerType: "hardware",
218
+ androidHardwareAccelerationDisabled: false,
219
+
220
+ // Security settings
221
+ allowFileAccess: false,
222
+ allowFileAccessFromFileURLs: false,
223
+ mixedContentMode: "never",
224
+
225
+ // UI customization
226
+ decelerationRate: 'fast',
227
+ bounces: false,
228
+
229
+ // Any other WebView props...
230
+ }}
231
+ />
232
+ ```
233
+
234
+ ### Performance Optimization Examples
235
+
236
+ ```jsx
237
+ // High-performance mode
238
+ <SignatureCanvas
239
+ webviewProps={{
240
+ cacheEnabled: true,
241
+ androidLayerType: "hardware",
242
+ androidHardwareAccelerationDisabled: false,
243
+ }}
244
+ />
245
+
246
+ // Low-memory mode
247
+ <SignatureCanvas
248
+ webviewProps={{
249
+ cacheEnabled: false,
250
+ androidLayerType: "software",
251
+ androidHardwareAccelerationDisabled: true,
252
+ }}
253
+ />
254
+ ```
255
+
256
+ ## Error Handling (Enhanced!)
257
+
258
+ ```jsx
259
+ const [error, setError] = useState(null);
260
+
261
+ const handleError = (error) => {
262
+ console.error('Signature error:', error);
263
+ setError(error.message);
264
+ // Error recovery is automatic, but you can handle it here
265
+ };
266
+
267
+ <SignatureCanvas
268
+ onError={handleError}
269
+ // Component automatically retries on recoverable errors
270
+ />
271
+
272
+ {error && (
273
+ <Text style={{ color: 'red' }}>Error: {error}</Text>
274
+ )}
275
+ ```
276
+
277
+ ## Advanced Usage
278
+
279
+ ### Using a Background Image
280
+
281
+ ```jsx
165
282
  const imgWidth = 300;
166
283
  const imgHeight = 200;
167
284
  const style = `.m-signature-pad {box-shadow: none; border: none; }
@@ -169,24 +286,22 @@ const style = `.m-signature-pad {box-shadow: none; border: none; }
169
286
  .m-signature-pad--footer {display: none; margin: 0px;}
170
287
  body,html {
171
288
  width: ${imgWidth}px; height: ${imgHeight}px;}`;
172
- ...
289
+
173
290
  <View style={{ width: imgWidth, height: imgHeight }}>
174
- <SignatureScreen
291
+ <SignatureCanvas
175
292
  ref={ref}
176
- bgSrc="https://via.placeholder.com/300x200/ff726b"
293
+ bgSrc="https://example.com/background.jpg"
177
294
  bgWidth={imgWidth}
178
295
  bgHeight={imgHeight}
179
296
  webStyle={style}
180
- onOK={handleOK}
297
+ onOK={handleSignature}
181
298
  />
182
299
  </View>
183
300
  ```
184
301
 
185
- ## Using an overlay image
186
- An overlay is a non-erasable image that can be used as a guideline similar to a colouring book. Make sure the image format is .png and that it has a transparent background. Also, don't forget to provide the width and height of the image.
187
- Use the `overlaySrc` prop to provide the link.
302
+ ### Using an Overlay Image
188
303
 
189
- ```js
304
+ ```jsx
190
305
  const imgWidth = 256;
191
306
  const imgHeight = 256;
192
307
  const style = `.m-signature-pad {box-shadow: none; border: none; }
@@ -194,299 +309,252 @@ const style = `.m-signature-pad {box-shadow: none; border: none; }
194
309
  .m-signature-pad--footer {display: none; margin: 0px;}
195
310
  body,html {
196
311
  width: ${imgWidth}px; height: ${imgHeight}px;}`;
197
- ...
312
+
198
313
  <View style={{ width: imgWidth, height: imgHeight }}>
199
- <SignatureScreen
314
+ <SignatureCanvas
200
315
  ref={ref}
201
- overlaySrc="http://pngimg.com/uploads/circle/circle_PNG63.png"
316
+ overlaySrc="https://example.com/overlay.png" // Must be PNG with transparent background
202
317
  overlayWidth={imgWidth}
203
318
  overlayHeight={imgHeight}
204
319
  webStyle={style}
205
- onOK={handleOK}
320
+ onOK={handleSignature}
206
321
  />
207
322
  </View>
208
323
  ```
209
324
 
210
- ## Save Base64 Image as File
325
+ ### Using in a Modal
211
326
 
212
- If you're using expo, you can use **expo-file-system** to save the base64 image as a local file; if you're working with react-native-cli, use **react-native-fs**.
327
+ ```jsx
328
+ import React, { useState, useRef } from 'react';
329
+ import { StyleSheet, View, TouchableOpacity, Modal, Text } from 'react-native';
330
+ import SignatureCanvas from 'react-native-signature-canvas';
213
331
 
214
- ```js
215
- import * as FileSystem from "expo-file-system";
332
+ const SignatureModal = ({ onSignature }) => {
333
+ const [show, setShow] = useState(false);
334
+ const ref = useRef();
335
+
336
+ const handleSignature = (signature) => {
337
+ onSignature(signature);
338
+ setShow(false);
339
+ };
216
340
 
217
- const handleOK = (signature) => {
218
- const path = FileSystem.cacheDirectory + "sign.png";
219
- FileSystem.writeAsStringAsync(
220
- path,
221
- signature.replace("data:image/png;base64,", ""),
222
- { encoding: FileSystem.EncodingType.Base64 }
223
- )
224
- .then(() => FileSystem.getInfoAsync(path))
225
- .then(console.log)
226
- .catch(console.error);
341
+ return (
342
+ <View>
343
+ <TouchableOpacity onPress={() => setShow(true)}>
344
+ <Text>Open Signature Pad</Text>
345
+ </TouchableOpacity>
346
+
347
+ {show && (
348
+ <Modal>
349
+ <SignatureCanvas
350
+ ref={ref}
351
+ onOK={handleSignature}
352
+ onEmpty={() => console.log('Empty')}
353
+ descriptionText="Sign here"
354
+ penColor="rgba(255,117,2,1)"
355
+ />
356
+ </Modal>
357
+ )}
358
+ </View>
359
+ );
227
360
  };
228
361
  ```
229
362
 
230
- ## Basic parameters
231
-
232
- ```js
233
- <Signature
234
- // handle when you click save button
235
- onOK={(img) => console.log(img)}
236
- onEmpty={() => console.log("empty")}
237
- // description text for signature
238
- descriptionText="Sign"
239
- // clear button text
240
- clearText="Clear"
241
- // save button text
242
- confirmText="Save"
243
- // String, webview style for overwrite default style, all style: https://github.com/YanYuanFE/react-native-signature-canvas/blob/master/h5/css/signature-pad.css
244
- webStyle={`.m-signature-pad--footer
245
- .button {
246
- background-color: red;
247
- color: #FFF;
248
- }`}
249
- autoClear={true}
250
- imageType={"image/svg+xml"}
251
- />
252
- ```
253
-
254
- If you create your own triggers for the readSignature and/or clearSignature you can hide the built in Clear and Save buttons with css styles passed into the **webStyle** property.
255
-
256
- ```js
257
- const webStyle = `.m-signature-pad--footer
258
- .save {
259
- display: none;
260
- }
261
- .clear {
262
- display: none;
263
- }
264
- `;
265
- ...
266
- <Signature
267
- webStyle={webStyle}
268
- onOK={handleOK}
269
- onEmpty={handleEmpty}
270
- onEnd={handleEnd}
271
- />
272
-
273
- ```
274
-
275
- ## Custom Button for Confirm and Clear
276
-
277
- ```js
278
- import React, { useRef } from "react";
279
- import { StyleSheet, View, Button } from "react-native";
280
- import SignatureScreen from "react-native-signature-canvas";
281
-
282
- const Sign = ({ onOK }) => {
283
- const ref = useRef();
284
-
285
- const handleOK = (signature) => {
286
- console.log(signature);
287
- onOK(signature);
288
- };
289
-
290
- const handleClear = () => {
291
- ref.current.clearSignature();
292
- };
363
+ ### Scrollable Signature Canvas
293
364
 
294
- const handleConfirm = () => {
295
- console.log("end");
296
- ref.current.readSignature();
297
- };
365
+ ```jsx
366
+ import React, { useRef, useState } from 'react';
367
+ import { View, StyleSheet, ScrollView } from 'react-native';
368
+ import SignatureCanvas from 'react-native-signature-canvas';
298
369
 
299
- const style = `.m-signature-pad--footer {display: none; margin: 0px;}`;
370
+ const ScrollableSignature = () => {
371
+ const [scrollEnabled, setScrollEnabled] = useState(true);
372
+ const signatureRef = useRef(null);
300
373
 
301
374
  return (
302
- <View style={styles.container}>
303
- <SignatureScreen ref={ref} onOK={handleOK} webStyle={style} />
304
- <View style={styles.row}>
305
- <Button title="Clear" onPress={handleClear} />
306
- <Button title="Confirm" onPress={handleConfirm} />
375
+ <ScrollView scrollEnabled={scrollEnabled}>
376
+ <View style={styles.container}>
377
+ <SignatureCanvas
378
+ ref={signatureRef}
379
+ style={styles.canvas}
380
+ onBegin={() => setScrollEnabled(false)}
381
+ onEnd={() => setScrollEnabled(true)}
382
+ />
307
383
  </View>
308
- </View>
384
+ </ScrollView>
309
385
  );
310
386
  };
311
387
 
312
- export default Sign;
313
-
314
388
  const styles = StyleSheet.create({
315
389
  container: {
316
390
  flex: 1,
317
- alignItems: "center",
318
- justifyContent: "center",
319
- height: 250,
320
- padding: 10,
391
+ alignItems: 'center',
321
392
  },
322
- row: {
323
- display: "flex",
324
- flexDirection: "row",
325
- justifyContent: "space-between",
326
- width: "100%",
327
- alignItems: "center",
393
+ canvas: {
394
+ width: '90%',
395
+ height: 300,
396
+ borderWidth: 1,
397
+ borderColor: '#000',
328
398
  },
329
399
  });
330
400
  ```
331
401
 
332
- ## Example
402
+ ## Performance & Reliability
333
403
 
334
- - Android <br/>
335
- <img src="http://img.yanyuanfe.cn/signature-android.png" width="400" />
404
+ ### Automatic Error Recovery
405
+ - **Smart retry logic** with exponential backoff
406
+ - **Circuit breaker pattern** to prevent cascading failures
407
+ - **Memory leak prevention** with automatic cleanup
408
+ - **Performance monitoring** with automatic optimization
336
409
 
337
- - iOS <br/>
338
- <img src="http://img.yanyuanfe.cn/signature-ios.png" width="400" />
410
+ ### Performance Features
411
+ - **Debounced resize handling** for smooth interaction
412
+ - **Memory pressure detection** with adaptive optimization
413
+ - **Optimized rendering** with reduced re-renders
414
+ - **Device-specific optimization** based on hardware capabilities
339
415
 
340
- ```js
341
- import React, { useState } from "react";
342
- import { StyleSheet, Text, View, Image } from "react-native";
343
- import Signature from "react-native-signature-canvas";
416
+ ### Security Enhancements
417
+ - **Configurable WebView security** via `webviewProps`
418
+ - **Input validation** for all methods and callbacks
419
+ - **XSS protection** with content security policies
420
+ - **File access restrictions** by default
344
421
 
345
- export const SignatureScreen = () => {
346
- const [signature, setSign] = useState(null);
422
+ ## Migration Guide
347
423
 
348
- const handleOK = (signature) => {
349
- console.log(signature);
350
- setSign(signature);
351
- };
424
+ ### From v4.6.x to v4.7.x
352
425
 
353
- const handleEmpty = () => {
354
- console.log("Empty");
355
- };
426
+ This version is fully backward compatible. New features:
356
427
 
357
- const style = `.m-signature-pad--footer
358
- .button {
359
- background-color: red;
360
- color: #FFF;
361
- }`;
362
- return (
363
- <View style={{ flex: 1 }}>
364
- <View style={styles.preview}>
365
- {signature ? (
366
- <Image
367
- resizeMode={"contain"}
368
- style={{ width: 335, height: 114 }}
369
- source={{ uri: signature }}
370
- />
371
- ) : null}
372
- </View>
373
- <Signature
374
- onOK={handleOK}
375
- onEmpty={handleEmpty}
376
- descriptionText="Sign"
377
- clearText="Clear"
378
- confirmText="Save"
379
- webStyle={style}
380
- />
381
- </View>
382
- );
383
- };
428
+ ```jsx
429
+ // NEW: Enhanced error handling
430
+ <SignatureCanvas
431
+ onError={(error) => console.error(error)} // New callback
432
+ />
384
433
 
385
- const styles = StyleSheet.create({
386
- preview: {
387
- width: 335,
388
- height: 114,
389
- backgroundColor: "#F8F8F8",
390
- justifyContent: "center",
391
- alignItems: "center",
392
- marginTop: 15,
393
- },
394
- previewText: {
395
- color: "#FFF",
396
- fontSize: 14,
397
- height: 40,
398
- lineHeight: 40,
399
- paddingLeft: 10,
400
- paddingRight: 10,
401
- backgroundColor: "#69B2FF",
402
- width: 120,
403
- textAlign: "center",
404
- marginTop: 10,
405
- },
406
- });
434
+ // NEW: WebView customization
435
+ <SignatureCanvas
436
+ webviewProps={{ // New prop
437
+ cacheEnabled: false,
438
+ androidLayerType: "software"
439
+ }}
440
+ />
407
441
  ```
408
442
 
409
- ## Using Typescript
443
+ ## Troubleshooting
410
444
 
411
- To use Typescript just import `SignatureViewRef` and in [useRef hook](https://reactjs.org/docs/hooks-reference.html#useref) inform that the reference is of the `SignatureViewRef` type, with that the regular `ref` methods will be available.
445
+ ### Common Issues
412
446
 
413
- ```ts
414
- import React, { useRef } from "react";
415
- import SignatureScreen, {
416
- SignatureViewRef,
417
- } from "react-native-signature-canvas";
447
+ **Issue**: Signature pad not loading
448
+ ```jsx
449
+ // Solution: Add error handling and check WebView props
450
+ <SignatureCanvas
451
+ onError={(error) => console.log('Error:', error)}
452
+ onLoadEnd={() => console.log('Loaded successfully')}
453
+ webviewProps={{
454
+ startInLoadingState: true,
455
+ renderLoading: () => <ActivityIndicator />
456
+ }}
457
+ />
458
+ ```
418
459
 
419
- interface Props {
420
- text: string;
421
- onOK: (signature) => void;
422
- }
460
+ **Issue**: Poor performance on older devices
461
+ ```jsx
462
+ // Solution: Use low-performance mode
463
+ <SignatureCanvas
464
+ webviewProps={{
465
+ androidLayerType: "software",
466
+ androidHardwareAccelerationDisabled: true,
467
+ cacheEnabled: false
468
+ }}
469
+ />
470
+ ```
423
471
 
424
- const Sign: React.FC<Props> = ({ text, onOK }) => {
425
- const ref = useRef<SignatureViewRef>(null);
472
+ **Issue**: Memory issues
473
+ ```jsx
474
+ // Solution: The component now handles this automatically
475
+ // But you can customize via webviewProps if needed
476
+ <SignatureCanvas
477
+ webviewProps={{
478
+ cacheEnabled: false, // Reduce memory usage
479
+ androidLayerType: "software" // Use software rendering
480
+ }}
481
+ />
482
+ ```
426
483
 
427
- const handleSignature = (signature) => {
428
- console.log(signature);
429
- onOK(signature);
430
- };
484
+ ## API Reference
431
485
 
432
- const handleEmpty = () => {
433
- console.log("Empty");
434
- };
486
+ For detailed API documentation, see:
487
+ - [WEBVIEW_PROPS.md](./WEBVIEW_PROPS.md) - WebView customization guide
488
+ - [TypeScript definitions](./index.d.ts) - Complete type definitions
435
489
 
436
- const handleClear = () => {
437
- console.log("clear success!");
438
- };
490
+ ## Core Technology
439
491
 
440
- const handleEnd = () => {
441
- ref.current?.readSignature();
442
- };
492
+ This component is built on:
493
+ - [signature_pad.js](https://github.com/szimek/signature_pad) for the core signature functionality
494
+ - React Native WebView for cross-platform rendering
495
+ - Enhanced with performance monitoring and error recovery systems
443
496
 
444
- return (
445
- <SignatureScreen
446
- ref={ref}
447
- onEnd={handleEnd}
448
- onOK={handleSignature}
449
- onEmpty={handleEmpty}
450
- onClear={handleClear}
451
- autoClear={true}
452
- descriptionText={text}
453
- />
454
- );
455
- };
497
+ ## Contributing
456
498
 
457
- export default Sign;
458
- ```
499
+ Contributions are welcome! Please read our contributing guidelines and submit pull requests to help improve this component.
500
+
501
+ ### Development Setup
459
502
 
460
- ## Example inside ScrollView
503
+ ```bash
504
+ # Clone the repository
505
+ git clone https://github.com/YanYuanFE/react-native-signature-canvas.git
461
506
 
462
- When using `react-native-signature-canvas` inside a ScrollView, you will only get a point on the canvas and the ScrollView will handle the gesture making it unused for the canvas.
463
- The work around is to use the `scrollEnabled` prop of `ScrollView`.
464
- Here an example:
507
+ # Install dependencies
508
+ cd react-native-signature-canvas
509
+ npm install
465
510
 
511
+ # Run example apps
512
+ cd example/expo-app
513
+ npm install && npm start
466
514
  ```
467
- import React, {useState} from 'react';
468
- import {ScrollView, View} from 'react-native';
469
- import Signature from 'react-native-signature-canvas';
470
515
 
471
- const SignInScroll = () => {
472
- const [scrollEnabled, setScrollEnabled] = useState(true);
516
+ ## Changelog
473
517
 
474
- return (
475
- <ScrollView scrollEnabled={scrollEnabled}>
476
- <View style={{height: 300}}>
477
- <Signature
478
- onOK={(img) => console.log(img)}
479
- onBegin={() => setScrollEnabled(false)}
480
- onEnd={() => setScrollEnabled(true)}
481
- descriptionText="Sign"
482
- clearText="Clear"
483
- confirmText="Save"
484
- imageType="image/jpeg"
485
- />
486
- </View>
487
- </ScrollView>
488
- );
489
- };
518
+ ### v4.7.x (Latest)
519
+ - 🆕 Added `webviewProps` for WebView customization
520
+ - 🆕 Enhanced error handling with automatic recovery
521
+ - 🆕 Performance monitoring and optimization
522
+ - 🆕 Memory leak prevention
523
+ - 🆕 Improved TypeScript definitions
524
+ - 🔧 Fixed global variable pollution in WebView JavaScript
525
+ - 🔧 Added input validation for all methods
526
+ - ⚡ Optimized rendering performance
490
527
 
491
- export default SignInScroll;
492
- ```
528
+ [View full changelog](./CHANGELOG.md)
529
+
530
+ ## License
531
+
532
+ MIT License - see [LICENSE](./LICENSE) file for details.
533
+
534
+
535
+ ## Buy Me a Coffee ☕
536
+
537
+ If you find this project helpful, consider supporting its development with cryptocurrency donations:
538
+
539
+ ### Cryptocurrency Donations
540
+
541
+ | Currency | Address | QR Code |
542
+ |----------|---------|----------|
543
+ | **Bitcoin (BTC)** | `bc1phyz9agr0m9l2w9pd8w85w4da2jt3wl4cre7vv0qq4uesm3fv00pscu96tux` | ![BTC QR](https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=bc1phyz9agr0m9l2w9pd8w85w4da2jt3wl4cre7vv0qq4uesm3fv00pscu96tux) |
544
+ | **Ethereum (ETH)** | `0xf5dfe16b1e64e8e3a92063fb2922447e13b48945` | ![ETH QR](https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=0xf5dfe16b1e64e8e3a92063fb2922447e13b48945) |
545
+ | **Solana (SOL)** | `3VuhyeTj3hMSrmzq7NctHkgFxvJrmtAUQTzagEBEu3Vm` | ![SOL QR](https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=3VuhyeTj3hMSrmzq7NctHkgFxvJrmtAUQTzagEBEu3Vm) |
546
+
547
+
548
+ ### Other Ways to Support
549
+
550
+ - ⭐ Star this repository
551
+ - 🐛 Report bugs and issues
552
+ - 💡 Suggest new features
553
+ - 🤝 Contribute code improvements
554
+ - 📢 Share this project with others
555
+
556
+ Your support helps maintain and improve this open-source project. Thank you! 🙏
557
+
558
+ ---
559
+
560
+ **Made with ❤️ for the React Native community**