react-native-signature-canvas 4.7.4 → 5.0.1
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/CHANGELOG.md +51 -0
- package/QUICK_START.md +219 -0
- package/README.md +259 -14
- package/WEBVIEW_PROPS.md +166 -0
- package/h5/js/app.js +119 -39
- package/index.d.ts +38 -17
- package/index.js +240 -161
- package/package.json +11 -4
package/index.js
CHANGED
|
@@ -5,8 +5,9 @@ import React, {
|
|
|
5
5
|
useRef,
|
|
6
6
|
forwardRef,
|
|
7
7
|
useImperativeHandle,
|
|
8
|
+
useCallback,
|
|
8
9
|
} from "react";
|
|
9
|
-
import { View, StyleSheet, ActivityIndicator } from "react-native";
|
|
10
|
+
import { View, StyleSheet, ActivityIndicator, Text } from "react-native";
|
|
10
11
|
|
|
11
12
|
import htmlContent from "./h5/html";
|
|
12
13
|
import injectedSignaturePad from "./h5/js/signature_pad";
|
|
@@ -14,6 +15,20 @@ import injectedApplication from "./h5/js/app";
|
|
|
14
15
|
|
|
15
16
|
import { WebView } from "react-native-webview";
|
|
16
17
|
|
|
18
|
+
// Constants for better maintainability
|
|
19
|
+
const MESSAGE_TYPES = {
|
|
20
|
+
BEGIN: "BEGIN",
|
|
21
|
+
END: "END",
|
|
22
|
+
EMPTY: "EMPTY",
|
|
23
|
+
CLEAR: "CLEAR",
|
|
24
|
+
UNDO: "UNDO",
|
|
25
|
+
REDO: "REDO",
|
|
26
|
+
DRAW: "DRAW",
|
|
27
|
+
ERASE: "ERASE",
|
|
28
|
+
CHANGE_PEN: "CHANGE_PEN",
|
|
29
|
+
CHANGE_PEN_SIZE: "CHANGE_PEN_SIZE"
|
|
30
|
+
};
|
|
31
|
+
|
|
17
32
|
const styles = StyleSheet.create({
|
|
18
33
|
webBg: {
|
|
19
34
|
width: "100%",
|
|
@@ -65,6 +80,7 @@ const SignatureView = forwardRef(
|
|
|
65
80
|
onBegin = () => { },
|
|
66
81
|
onEnd = () => { },
|
|
67
82
|
onLoadEnd = () => { },
|
|
83
|
+
onError = () => { },
|
|
68
84
|
overlayHeight = 0,
|
|
69
85
|
overlayWidth = 0,
|
|
70
86
|
overlaySrc = null,
|
|
@@ -76,85 +92,69 @@ const SignatureView = forwardRef(
|
|
|
76
92
|
webStyle = "",
|
|
77
93
|
webviewContainerStyle = null,
|
|
78
94
|
androidLayerType = "hardware",
|
|
95
|
+
webviewProps = {},
|
|
79
96
|
},
|
|
80
97
|
ref
|
|
81
98
|
) => {
|
|
82
99
|
const [loading, setLoading] = useState(true);
|
|
100
|
+
|
|
101
|
+
const [hasError, setHasError] = useState(false);
|
|
102
|
+
const [retryCount, setRetryCount] = useState(0);
|
|
103
|
+
const maxRetries = 3;
|
|
83
104
|
const webViewRef = useRef();
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
injectedJavaScript = injectedJavaScript.replace(
|
|
101
|
-
/<%penColor%>/g,
|
|
102
|
-
penColor
|
|
103
|
-
);
|
|
104
|
-
injectedJavaScript = injectedJavaScript.replace(
|
|
105
|
-
/<%backgroundColor%>/g,
|
|
106
|
-
backgroundColor
|
|
107
|
-
);
|
|
108
|
-
injectedJavaScript = injectedJavaScript.replace(/<%dotSize%>/g, dotSize);
|
|
109
|
-
injectedJavaScript = injectedJavaScript.replace(
|
|
110
|
-
/<%minWidth%>/g,
|
|
111
|
-
minWidth
|
|
112
|
-
);
|
|
113
|
-
injectedJavaScript = injectedJavaScript.replace(
|
|
114
|
-
/<%maxWidth%>/g,
|
|
115
|
-
maxWidth
|
|
116
|
-
);
|
|
117
|
-
injectedJavaScript = injectedJavaScript.replace(
|
|
118
|
-
/<%minDistance%>/g,
|
|
119
|
-
minDistance
|
|
120
|
-
);
|
|
105
|
+
// Split source generation for better performance
|
|
106
|
+
const injectedScript = useMemo(() => {
|
|
107
|
+
let script = injectedSignaturePad + injectedApplication;
|
|
108
|
+
script = script.replace(/<%autoClear%>/g, autoClear);
|
|
109
|
+
script = script.replace(/<%trimWhitespace%>/g, trimWhitespace);
|
|
110
|
+
script = script.replace(/<%imageType%>/g, imageType || "image/png");
|
|
111
|
+
script = script.replace(/<%dataURL%>/g, dataURL || "");
|
|
112
|
+
script = script.replace(/<%penColor%>/g, penColor || "black");
|
|
113
|
+
script = script.replace(/<%backgroundColor%>/g, backgroundColor || "rgba(255,255,255,0)");
|
|
114
|
+
script = script.replace(/<%dotSize%>/g, dotSize || "null");
|
|
115
|
+
script = script.replace(/<%minWidth%>/g, minWidth || 0.5);
|
|
116
|
+
script = script.replace(/<%maxWidth%>/g, maxWidth || 2.5);
|
|
117
|
+
script = script.replace(/<%minDistance%>/g, minDistance || 5);
|
|
118
|
+
script = script.replace(/<%orientation%>/g, rotated || false);
|
|
119
|
+
return script;
|
|
120
|
+
}, [autoClear, trimWhitespace, imageType, dataURL, penColor, backgroundColor, dotSize, minWidth, maxWidth, minDistance, rotated]);
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
html =
|
|
125
|
-
html = html.replace(/<%
|
|
126
|
-
html = html.replace(/<%
|
|
127
|
-
html = html.replace(/<%
|
|
128
|
-
html = html.replace(/<%
|
|
129
|
-
html = html.replace(/<%
|
|
130
|
-
html = html.replace(/<%
|
|
131
|
-
html = html.replace(/<%
|
|
132
|
-
html = html.replace(/<%
|
|
133
|
-
html = html.replace(/<%
|
|
122
|
+
const source = useMemo(() => {
|
|
123
|
+
const htmlContentValue = customHtml || htmlContent;
|
|
124
|
+
let html = htmlContentValue(injectedScript);
|
|
125
|
+
html = html.replace(/<%bgWidth%>/g, bgWidth || 0);
|
|
126
|
+
html = html.replace(/<%bgHeight%>/g, bgHeight || 0);
|
|
127
|
+
html = html.replace(/<%bgSrc%>/g, bgSrc || "null");
|
|
128
|
+
html = html.replace(/<%overlayWidth%>/g, overlayWidth || 0);
|
|
129
|
+
html = html.replace(/<%overlayHeight%>/g, overlayHeight || 0);
|
|
130
|
+
html = html.replace(/<%overlaySrc%>/g, overlaySrc || "null");
|
|
131
|
+
html = html.replace(/<%style%>/g, webStyle || "");
|
|
132
|
+
html = html.replace(/<%description%>/g, descriptionText || "Sign above");
|
|
133
|
+
html = html.replace(/<%confirm%>/g, confirmText || "Confirm");
|
|
134
|
+
html = html.replace(/<%clear%>/g, clearText || "Clear");
|
|
135
|
+
html = html.replace(/<%orientation%>/g, rotated || false);
|
|
134
136
|
|
|
135
137
|
return { html };
|
|
136
|
-
}, [
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
rotated,
|
|
141
|
-
imageType,
|
|
142
|
-
webStyle,
|
|
143
|
-
descriptionText,
|
|
144
|
-
confirmText,
|
|
145
|
-
clearText,
|
|
146
|
-
dataURL,
|
|
147
|
-
bgSrc,
|
|
148
|
-
bgWidth,
|
|
149
|
-
bgHeight,
|
|
150
|
-
]);
|
|
138
|
+
}, [injectedScript, customHtml, bgWidth, bgHeight, bgSrc, overlayWidth, overlayHeight, overlaySrc, webStyle, descriptionText, confirmText, clearText, rotated]);
|
|
139
|
+
|
|
140
|
+
// Optimize WebView reload to prevent excessive reloads
|
|
141
|
+
const [shouldReload, setShouldReload] = useState(false);
|
|
151
142
|
|
|
152
143
|
useEffect(() => {
|
|
153
|
-
|
|
154
|
-
webViewRef.current.reload();
|
|
155
|
-
}
|
|
144
|
+
setShouldReload(true);
|
|
156
145
|
}, [source]);
|
|
157
146
|
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (shouldReload && webViewRef.current) {
|
|
149
|
+
try {
|
|
150
|
+
webViewRef.current.reload();
|
|
151
|
+
setShouldReload(false);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.warn("WebView reload failed:", error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}, [shouldReload]);
|
|
157
|
+
|
|
158
158
|
const isJson = (str) => {
|
|
159
159
|
try {
|
|
160
160
|
JSON.parse(str);
|
|
@@ -164,112 +164,176 @@ const SignatureView = forwardRef(
|
|
|
164
164
|
return true;
|
|
165
165
|
};
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
case "END":
|
|
173
|
-
onEnd();
|
|
174
|
-
break;
|
|
175
|
-
case "EMPTY":
|
|
176
|
-
onEmpty();
|
|
177
|
-
break;
|
|
178
|
-
case "CLEAR":
|
|
179
|
-
onClear();
|
|
180
|
-
break;
|
|
181
|
-
case "UNDO":
|
|
182
|
-
onUndo();
|
|
183
|
-
break;
|
|
184
|
-
case "REDO":
|
|
185
|
-
onRedo();
|
|
186
|
-
break;
|
|
187
|
-
case "DRAW":
|
|
188
|
-
onDraw();
|
|
189
|
-
break;
|
|
190
|
-
case "ERASE":
|
|
191
|
-
onErase();
|
|
192
|
-
break;
|
|
193
|
-
case "CHANGE_PEN":
|
|
194
|
-
onChangePenColor();
|
|
195
|
-
break;
|
|
196
|
-
case "CHANGE_PEN_SIZE":
|
|
197
|
-
onChangePenSize();
|
|
198
|
-
break;
|
|
199
|
-
default:
|
|
200
|
-
isJson(e.nativeEvent.data)
|
|
201
|
-
? onGetData(e.nativeEvent.data)
|
|
202
|
-
: onOK(e.nativeEvent.data);
|
|
167
|
+
// Enhanced message handling with error handling
|
|
168
|
+
const getSignature = useCallback((e) => {
|
|
169
|
+
if (!e?.nativeEvent?.data) {
|
|
170
|
+
console.warn("Invalid message received from WebView");
|
|
171
|
+
return;
|
|
203
172
|
}
|
|
204
|
-
|
|
173
|
+
|
|
174
|
+
const data = e.nativeEvent.data;
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
switch (data) {
|
|
178
|
+
case MESSAGE_TYPES.BEGIN:
|
|
179
|
+
onBegin();
|
|
180
|
+
break;
|
|
181
|
+
case MESSAGE_TYPES.END:
|
|
182
|
+
onEnd();
|
|
183
|
+
break;
|
|
184
|
+
case MESSAGE_TYPES.EMPTY:
|
|
185
|
+
onEmpty();
|
|
186
|
+
break;
|
|
187
|
+
case MESSAGE_TYPES.CLEAR:
|
|
188
|
+
onClear();
|
|
189
|
+
break;
|
|
190
|
+
case MESSAGE_TYPES.UNDO:
|
|
191
|
+
onUndo();
|
|
192
|
+
break;
|
|
193
|
+
case MESSAGE_TYPES.REDO:
|
|
194
|
+
onRedo();
|
|
195
|
+
break;
|
|
196
|
+
case MESSAGE_TYPES.DRAW:
|
|
197
|
+
onDraw();
|
|
198
|
+
break;
|
|
199
|
+
case MESSAGE_TYPES.ERASE:
|
|
200
|
+
onErase();
|
|
201
|
+
break;
|
|
202
|
+
case MESSAGE_TYPES.CHANGE_PEN:
|
|
203
|
+
onChangePenColor();
|
|
204
|
+
break;
|
|
205
|
+
case MESSAGE_TYPES.CHANGE_PEN_SIZE:
|
|
206
|
+
onChangePenSize();
|
|
207
|
+
break;
|
|
208
|
+
default:
|
|
209
|
+
if (isJson(data)) {
|
|
210
|
+
onGetData(data);
|
|
211
|
+
} else if (typeof data === "string" && data.startsWith("data:")) {
|
|
212
|
+
onOK(data);
|
|
213
|
+
} else {
|
|
214
|
+
console.warn("Unknown message type:", data);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error("Error handling WebView message:", error);
|
|
219
|
+
}
|
|
220
|
+
}, [onBegin, onEnd, onEmpty, onClear, onUndo, onRedo, onDraw, onErase, onChangePenColor, onChangePenSize, onGetData, onOK]);
|
|
221
|
+
|
|
222
|
+
// Enhanced WebView method execution with error handling
|
|
223
|
+
const executeWebViewMethod = useCallback((method, params = []) => {
|
|
224
|
+
if (!webViewRef.current) {
|
|
225
|
+
console.warn(`WebView ref is null when calling ${method}`);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const script = params.length > 0
|
|
231
|
+
? `${method}(${params.map(p => typeof p === 'string' ? `'${p}'` : p).join(',')});true;`
|
|
232
|
+
: `${method}();true;`;
|
|
233
|
+
webViewRef.current.injectJavaScript(script);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error(`Error executing WebView method ${method}:`, error);
|
|
236
|
+
}
|
|
237
|
+
}, []);
|
|
205
238
|
|
|
206
239
|
useImperativeHandle(
|
|
207
240
|
ref,
|
|
208
241
|
() => ({
|
|
209
|
-
readSignature: () =>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (webViewRef.current) {
|
|
216
|
-
webViewRef.current.injectJavaScript("clearSignature();true;");
|
|
217
|
-
}
|
|
218
|
-
},
|
|
219
|
-
undo: () => {
|
|
220
|
-
if (webViewRef.current) {
|
|
221
|
-
webViewRef.current.injectJavaScript("undo();true;");
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
redo: () => {
|
|
225
|
-
if (webViewRef.current) {
|
|
226
|
-
webViewRef.current.injectJavaScript("redo();true;");
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
draw: () => {
|
|
230
|
-
if (webViewRef.current) {
|
|
231
|
-
webViewRef.current.injectJavaScript("draw();true;");
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
erase: () => {
|
|
235
|
-
if (webViewRef.current) {
|
|
236
|
-
webViewRef.current.injectJavaScript("erase();true;");
|
|
237
|
-
}
|
|
238
|
-
},
|
|
242
|
+
readSignature: () => executeWebViewMethod('readSignature'),
|
|
243
|
+
clearSignature: () => executeWebViewMethod('clearSignature'),
|
|
244
|
+
undo: () => executeWebViewMethod('undo'),
|
|
245
|
+
redo: () => executeWebViewMethod('redo'),
|
|
246
|
+
draw: () => executeWebViewMethod('draw'),
|
|
247
|
+
erase: () => executeWebViewMethod('erase'),
|
|
239
248
|
changePenColor: (color) => {
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
);
|
|
249
|
+
if (typeof color !== 'string') {
|
|
250
|
+
console.warn('changePenColor: color must be a string');
|
|
251
|
+
return;
|
|
244
252
|
}
|
|
253
|
+
executeWebViewMethod('changePenColor', [color]);
|
|
245
254
|
},
|
|
246
255
|
changePenSize: (minW, maxW) => {
|
|
247
|
-
if (
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
);
|
|
256
|
+
if (typeof minW !== 'number' || typeof maxW !== 'number') {
|
|
257
|
+
console.warn('changePenSize: minW and maxW must be numbers');
|
|
258
|
+
return;
|
|
251
259
|
}
|
|
260
|
+
executeWebViewMethod('changePenSize', [minW, maxW]);
|
|
252
261
|
},
|
|
253
|
-
getData: () =>
|
|
254
|
-
|
|
255
|
-
|
|
262
|
+
getData: () => executeWebViewMethod('getData'),
|
|
263
|
+
fromData: (pointGroups) => {
|
|
264
|
+
if (!pointGroups) {
|
|
265
|
+
console.warn('fromData: pointGroups must be an array');
|
|
266
|
+
return;
|
|
256
267
|
}
|
|
268
|
+
executeWebViewMethod('fromData', [pointGroups, false]);
|
|
257
269
|
},
|
|
258
270
|
}),
|
|
259
|
-
[
|
|
271
|
+
[executeWebViewMethod]
|
|
260
272
|
);
|
|
261
273
|
|
|
262
|
-
const renderError = ({ nativeEvent }) =>
|
|
263
|
-
console.
|
|
274
|
+
const renderError = useCallback(({ nativeEvent }) => {
|
|
275
|
+
console.error("WebView error: ", nativeEvent);
|
|
276
|
+
setHasError(true);
|
|
277
|
+
|
|
278
|
+
// Call user-provided error handler
|
|
279
|
+
try {
|
|
280
|
+
onError(new Error(`WebView error: ${nativeEvent.description || nativeEvent.code}`));
|
|
281
|
+
} catch (err) {
|
|
282
|
+
console.warn('Error in onError callback:', err);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Attempt to recover from error with retry logic
|
|
286
|
+
if (webViewRef.current && nativeEvent.code !== -999 && retryCount < maxRetries) {
|
|
287
|
+
setTimeout(() => {
|
|
288
|
+
try {
|
|
289
|
+
setRetryCount(prev => prev + 1);
|
|
290
|
+
webViewRef.current.reload();
|
|
291
|
+
setHasError(false);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error("Failed to reload WebView after error:", error);
|
|
294
|
+
}
|
|
295
|
+
}, Math.min(1000 * Math.pow(2, retryCount), 5000)); // Exponential backoff
|
|
296
|
+
}
|
|
297
|
+
}, [onError, retryCount, maxRetries]);
|
|
264
298
|
|
|
265
|
-
const handleLoadEnd = () => {
|
|
299
|
+
const handleLoadEnd = useCallback(() => {
|
|
266
300
|
setLoading(false);
|
|
267
|
-
|
|
268
|
-
|
|
301
|
+
setHasError(false);
|
|
302
|
+
setRetryCount(0);
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
onLoadEnd();
|
|
306
|
+
} catch (error) {
|
|
307
|
+
console.warn('Error in onLoadEnd callback:', error);
|
|
308
|
+
}
|
|
309
|
+
}, [onLoadEnd]);
|
|
310
|
+
|
|
311
|
+
// Performance monitoring
|
|
312
|
+
const handleLoadStart = useCallback(() => {
|
|
313
|
+
setLoading(true);
|
|
314
|
+
}, []);
|
|
315
|
+
|
|
316
|
+
const handleLoadProgress = useCallback(({ nativeEvent }) => {
|
|
317
|
+
// Optional: Add progress monitoring
|
|
318
|
+
if (nativeEvent.progress === 1) {
|
|
319
|
+
setLoading(false);
|
|
320
|
+
}
|
|
321
|
+
}, []);
|
|
269
322
|
|
|
270
323
|
return (
|
|
271
324
|
<View style={[styles.webBg, style]}>
|
|
272
325
|
<WebView
|
|
326
|
+
// Core functionality props (cannot be overridden)
|
|
327
|
+
ref={webViewRef}
|
|
328
|
+
source={source}
|
|
329
|
+
onMessage={getSignature}
|
|
330
|
+
onError={renderError}
|
|
331
|
+
onLoadEnd={handleLoadEnd}
|
|
332
|
+
onLoadStart={handleLoadStart}
|
|
333
|
+
onLoadProgress={handleLoadProgress}
|
|
334
|
+
javaScriptEnabled={true}
|
|
335
|
+
useWebKit={true}
|
|
336
|
+
// Default component props (can be overridden by webviewProps)
|
|
273
337
|
bounces={false}
|
|
274
338
|
style={[webviewContainerStyle]}
|
|
275
339
|
scrollEnabled={scrollable}
|
|
@@ -277,19 +341,34 @@ const SignatureView = forwardRef(
|
|
|
277
341
|
androidHardwareAccelerationDisabled={
|
|
278
342
|
androidHardwareAccelerationDisabled
|
|
279
343
|
}
|
|
280
|
-
ref={webViewRef}
|
|
281
|
-
useWebKit={true}
|
|
282
|
-
source={source}
|
|
283
|
-
onMessage={getSignature}
|
|
284
|
-
javaScriptEnabled={true}
|
|
285
|
-
onError={renderError}
|
|
286
|
-
onLoadEnd={handleLoadEnd}
|
|
287
344
|
nestedScrollEnabled={nestedScrollEnabled}
|
|
288
345
|
showsVerticalScrollIndicator={showsVerticalScrollIndicator}
|
|
346
|
+
// Default performance optimizations
|
|
347
|
+
cacheEnabled={true}
|
|
348
|
+
allowsInlineMediaPlayback={false}
|
|
349
|
+
mediaPlaybackRequiresUserAction={true}
|
|
350
|
+
allowsBackForwardNavigationGestures={false}
|
|
351
|
+
// Default security enhancements
|
|
352
|
+
allowsLinkPreview={false}
|
|
353
|
+
allowFileAccess={false}
|
|
354
|
+
allowFileAccessFromFileURLs={false}
|
|
355
|
+
allowUniversalAccessFromFileURLs={false}
|
|
356
|
+
mixedContentMode="never"
|
|
357
|
+
originWhitelist={['*']}
|
|
358
|
+
// Default error recovery
|
|
359
|
+
startInLoadingState={true}
|
|
360
|
+
// User-provided WebView props (can override defaults but not core functionality)
|
|
361
|
+
{...webviewProps}
|
|
289
362
|
/>
|
|
290
|
-
{loading && (
|
|
363
|
+
{(loading || hasError) && (
|
|
291
364
|
<View style={styles.loadingOverlayContainer}>
|
|
292
|
-
|
|
365
|
+
{hasError ? (
|
|
366
|
+
<Text style={{ color: '#ff0000', textAlign: 'center', padding: 10 }}>
|
|
367
|
+
Error loading signature pad{retryCount > 0 ? ` (Retry ${retryCount}/${maxRetries})` : ''}
|
|
368
|
+
</Text>
|
|
369
|
+
) : (
|
|
370
|
+
<ActivityIndicator color={"#007AFF"} size="small" />
|
|
371
|
+
)}
|
|
293
372
|
</View>
|
|
294
373
|
)}
|
|
295
374
|
</View>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-signature-canvas",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "React Native
|
|
3
|
+
"version": "5.0.1",
|
|
4
|
+
"description": "A performant, customizable React Native signature canvas with advanced error handling, WebView optimization, and TypeScript support for iOS, Android, and Expo",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"genlog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
@@ -17,9 +17,16 @@
|
|
|
17
17
|
"ios",
|
|
18
18
|
"android",
|
|
19
19
|
"signature",
|
|
20
|
-
"pad",
|
|
20
|
+
"signature-pad",
|
|
21
21
|
"canvas",
|
|
22
|
-
"expo"
|
|
22
|
+
"expo",
|
|
23
|
+
"typescript",
|
|
24
|
+
"drawing",
|
|
25
|
+
"webview",
|
|
26
|
+
"performance",
|
|
27
|
+
"error-handling",
|
|
28
|
+
"undo-redo",
|
|
29
|
+
"svg-export"
|
|
23
30
|
],
|
|
24
31
|
"author": "YanYuanFE",
|
|
25
32
|
"license": "MIT",
|