react-native-signature-canvas 5.0.1 → 5.0.2

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 CHANGED
@@ -1,4 +1,13 @@
1
- # [5.0.0](https://github.com/YanYuanFE/react-native-signature-canvas/compare/v4.5.1...v5.0.0) (2025-06-28)
1
+ ## [5.0.2](https://github.com/YanYuanFE/react-native-signature-canvas/compare/v5.0.1...v5.0.2) (2025-12-28)
2
+
3
+
4
+ ### Features
5
+
6
+ * enhance signature canvas with bottom sheet integration and WebView improvements ([69f84a1](https://github.com/YanYuanFE/react-native-signature-canvas/commit/69f84a1))
7
+
8
+
9
+
10
+ ## [5.0.1](https://github.com/YanYuanFE/react-native-signature-canvas/compare/v4.5.1...v5.0.1) (2025-12-28)
2
11
 
3
12
 
4
13
  ### Bug Fixes
package/README.md CHANGED
@@ -401,12 +401,6 @@ const styles = StyleSheet.create({
401
401
 
402
402
  ## Performance & Reliability
403
403
 
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
409
-
410
404
  ### Performance Features
411
405
  - **Debounced resize handling** for smooth interaction
412
406
  - **Memory pressure detection** with adaptive optimization
@@ -421,7 +415,7 @@ const styles = StyleSheet.create({
421
415
 
422
416
  ## Migration Guide
423
417
 
424
- ### From v4.6.x to v4.7.x
418
+ ### From v4.x to v5.x
425
419
 
426
420
  This version is fully backward compatible. New features:
427
421
 
@@ -515,7 +509,7 @@ npm install && npm start
515
509
 
516
510
  ## Changelog
517
511
 
518
- ### v4.7.x (Latest)
512
+ ### v5.0.1 (Latest)
519
513
  - 🆕 Added `webviewProps` for WebView customization
520
514
  - 🆕 Enhanced error handling with automatic recovery
521
515
  - 🆕 Performance monitoring and optimization
package/h5/html.js CHANGED
@@ -12,36 +12,36 @@ export default (script) =>
12
12
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
13
13
 
14
14
  <style>
15
+ * {
16
+ box-sizing: border-box;
17
+ margin: 0;
18
+ padding: 0;
19
+ }
20
+ html, body {
21
+ width: 100%;
22
+ height: 100%;
23
+ margin: 0;
24
+ padding: 0;
25
+ overflow: hidden;
26
+ }
15
27
  body {
16
28
  font-family: Helvetica, Sans-Serif;
17
-
18
29
  -moz-user-select: none;
19
30
  -webkit-user-select: none;
20
31
  -ms-user-select: none;
21
- margin:0;
22
- overflow:hidden;
23
- }
24
- body,html {
25
- width: 100%;
26
- height: 300px;
27
32
  }
28
- * {
29
- box-sizing: border-box;
30
- margin: 0;
31
- padding: 0;
32
- }
33
-
33
+
34
34
  .rotated-true {
35
35
  transform: rotate(90deg);
36
36
  transform-origin:bottom left;
37
-
37
+
38
38
  position:absolute;
39
39
  top: -100vw;
40
40
  left: 0;
41
-
41
+
42
42
  height:100vw;
43
43
  width:100vh;
44
-
44
+
45
45
  overflow:auto;
46
46
  }
47
47
  .rotated-false {
@@ -56,15 +56,16 @@ export default (script) =>
56
56
  background-color: #fff;
57
57
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.08) inset;
58
58
  }
59
-
59
+
60
60
  .m-signature-pad--body {
61
61
  position: relative;
62
+ width: 100%;
62
63
  height: 100%;
63
64
  border: 1px solid #f4f4f4;
64
65
  }
65
-
66
- .m-signature-pad--body
67
- canvas {
66
+
67
+ .m-signature-pad--body canvas {
68
+ display: block;
68
69
  position: absolute;
69
70
  left: 0;
70
71
  top: 0;
@@ -125,7 +126,7 @@ export default (script) =>
125
126
 
126
127
  @media screen and (min-device-width: 768px) and (max-device-width: 1024px) {
127
128
  .m-signature-pad {
128
- margin: 10%;
129
+ margin: 0;
129
130
  }
130
131
  }
131
132
 
package/h5/js/app.js CHANGED
@@ -1,56 +1,39 @@
1
1
  export default `
2
- // Enhanced error handling and validation
3
2
  var wrapper = document.getElementById("signature-pad"),
4
3
  clearButton = wrapper && wrapper.querySelector("[data-action=clear]"),
5
4
  saveButton = wrapper && wrapper.querySelector("[data-action=save]"),
6
5
  canvas = wrapper && wrapper.querySelector("canvas"),
7
6
  signaturePad;
8
-
9
- if (!wrapper || !canvas) {
10
- console.error('Required DOM elements not found');
11
- }
12
-
13
- // Enhanced canvas resize with debouncing
14
- function debounce(func, wait) {
15
- var timeout;
16
- return function executedFunction() {
17
- var later = function() {
18
- clearTimeout(timeout);
19
- func.apply(this, arguments);
20
- };
21
- clearTimeout(timeout);
22
- timeout = setTimeout(later, wait);
23
- };
24
- }
25
-
7
+
26
8
  function resizeCanvas() {
27
- if (!canvas || !canvas.getContext) {
28
- console.warn('Canvas not available for resize');
9
+ if (!canvas || !canvas.getContext || !signaturePad) {
29
10
  return;
30
11
  }
31
-
32
- try {
33
- var context = canvas.getContext("2d");
34
- var imgData = signaturePad ? signaturePad.toData() : null;
35
- var ratio = Math.max(window.devicePixelRatio || 1, 1);
36
-
37
- canvas.width = canvas.offsetWidth * ratio;
38
- canvas.height = canvas.offsetHeight * ratio;
39
- context.scale(ratio, ratio);
40
-
41
- if (imgData && signaturePad) {
42
- signaturePad.fromData(imgData);
43
- }
44
- } catch (error) {
45
- console.error('Error resizing canvas:', error);
12
+
13
+ var context = canvas.getContext("2d");
14
+ var ratio = Math.max(window.devicePixelRatio || 1, 1);
15
+
16
+ // Save current signature data before resizing
17
+ var imgData = signaturePad.toData();
18
+ var hasDrawnContent = imgData && imgData.length > 0;
19
+
20
+ // Use canvas client dimensions
21
+ var width = canvas.clientWidth;
22
+ var height = canvas.clientHeight;
23
+
24
+ // Resize canvas (this clears the canvas)
25
+ canvas.width = width * ratio;
26
+ canvas.height = height * ratio;
27
+ context.scale(ratio, ratio);
28
+
29
+ // Restore signature content
30
+ if (hasDrawnContent) {
31
+ signaturePad.fromData(imgData);
32
+ } else if (dataURL) {
33
+ signaturePad.fromDataURL(dataURL);
46
34
  }
47
35
  }
48
-
49
- // Use debounced resize handler
50
- var debouncedResize = debounce(resizeCanvas, 100);
51
- window.addEventListener('resize', debouncedResize);
52
- resizeCanvas();
53
-
36
+
54
37
  signaturePad = new SignaturePad(canvas, {
55
38
  onBegin: () => window.ReactNativeWebView.postMessage("BEGIN"),
56
39
  onEnd: () => window.ReactNativeWebView.postMessage("END"),
@@ -62,16 +45,20 @@ export default `
62
45
  minDistance: <%minDistance%>,
63
46
  });
64
47
 
48
+ // Initial canvas setup
49
+ resizeCanvas();
50
+
65
51
  function clearSignature () {
66
52
  signaturePad.clear();
53
+ dataURL='';
67
54
  window.ReactNativeWebView.postMessage("CLEAR");
68
55
  }
69
-
56
+
70
57
  function undo() {
71
58
  signaturePad.undo();
72
59
  window.ReactNativeWebView.postMessage("UNDO");
73
60
  }
74
-
61
+
75
62
  function redo() {
76
63
  signaturePad.redo();
77
64
  window.ReactNativeWebView.postMessage("REDO");
@@ -79,31 +66,24 @@ export default `
79
66
 
80
67
  function changePenColor(color) {
81
68
  if (!signaturePad) {
82
- console.warn('SignaturePad not initialized');
83
69
  return;
84
70
  }
85
-
86
71
  signaturePad.penColor = color;
87
72
  window.ReactNativeWebView && window.ReactNativeWebView.postMessage("CHANGE_PEN");
88
73
  }
89
74
 
90
75
  function changePenSize(minW, maxW) {
91
76
  if (!signaturePad) {
92
- console.warn('SignaturePad not initialized');
93
77
  return;
94
78
  }
95
-
96
- // Validate numeric values
97
79
  if (typeof minW !== 'number' || typeof maxW !== 'number' || minW < 0 || maxW < minW) {
98
- console.warn('Invalid pen size values:', minW, maxW);
99
80
  return;
100
81
  }
101
-
102
82
  signaturePad.minWidth = minW;
103
83
  signaturePad.maxWidth = maxW;
104
84
  window.ReactNativeWebView && window.ReactNativeWebView.postMessage("CHANGE_PEN_SIZE");
105
85
  }
106
-
86
+
107
87
  function getData () {
108
88
  var data = signaturePad.toData();
109
89
  window.ReactNativeWebView.postMessage(JSON.stringify(data));
@@ -128,11 +108,10 @@ export default `
128
108
  var myImage = new Image();
129
109
  myImage.crossOrigin = "Anonymous";
130
110
  myImage.onload = function(){
131
- window.ReactNativeWebView.postMessage(removeImageBlanks(myImage)); //Will return cropped image data
111
+ window.ReactNativeWebView.postMessage(removeImageBlanks(myImage));
132
112
  }
133
113
  myImage.src = url;
134
114
 
135
- //-----------------------------------------//
136
115
  function removeImageBlanks(imageObject) {
137
116
  var imgWidth = imageObject.width;
138
117
  var imgHeight = imageObject.height;
@@ -157,49 +136,40 @@ export default `
157
136
  };
158
137
  },
159
138
  isWhite = function (rgb) {
160
- // many images contain noise, as the white is not a pure #fff white
161
139
  return !rgb.opacity || (rgb.red > 200 && rgb.green > 200 && rgb.blue > 200);
162
140
  },
163
- scanY = function (fromTop) {
164
- var offset = fromTop ? 1 : -1;
165
-
166
- // loop through each row
167
- for(var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {
168
-
169
- // loop through each column
170
- for(var x = 0; x < imgWidth; x++) {
171
- var rgb = getRGB(x, y);
172
- if (!isWhite(rgb)) {
173
- if (fromTop) {
174
- return y;
175
- } else {
176
- return Math.min(y + 1, imgHeight);
141
+ scanY = function (fromTop) {
142
+ var offset = fromTop ? 1 : -1;
143
+ for(var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {
144
+ for(var x = 0; x < imgWidth; x++) {
145
+ var rgb = getRGB(x, y);
146
+ if (!isWhite(rgb)) {
147
+ if (fromTop) {
148
+ return y;
149
+ } else {
150
+ return Math.min(y + 1, imgHeight);
151
+ }
177
152
  }
178
153
  }
179
154
  }
180
- }
181
- return null; // all image is white
182
- },
183
- scanX = function (fromLeft) {
184
- var offset = fromLeft? 1 : -1;
185
-
186
- // loop through each column
187
- for(var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {
188
-
189
- // loop through each row
190
- for(var y = 0; y < imgHeight; y++) {
191
- var rgb = getRGB(x, y);
192
- if (!isWhite(rgb)) {
193
- if (fromLeft) {
194
- return x;
195
- } else {
196
- return Math.min(x + 1, imgWidth);
155
+ return null;
156
+ },
157
+ scanX = function (fromLeft) {
158
+ var offset = fromLeft? 1 : -1;
159
+ for(var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {
160
+ for(var y = 0; y < imgHeight; y++) {
161
+ var rgb = getRGB(x, y);
162
+ if (!isWhite(rgb)) {
163
+ if (fromLeft) {
164
+ return x;
165
+ } else {
166
+ return Math.min(x + 1, imgWidth);
167
+ }
197
168
  }
198
- }
169
+ }
199
170
  }
200
- }
201
- return null; // all image is white
202
- };
171
+ return null;
172
+ };
203
173
 
204
174
  var cropTop = scanY(true),
205
175
  cropBottom = scanY(false),
@@ -210,7 +180,6 @@ export default `
210
180
 
211
181
  canvas.setAttribute("width", cropWidth);
212
182
  canvas.setAttribute("height", cropHeight);
213
- // finally crop the guy
214
183
  canvas.getContext("2d").drawImage(imageObject,
215
184
  cropLeft, cropTop, cropWidth, cropHeight,
216
185
  0, 0, cropWidth, cropHeight);
@@ -221,34 +190,29 @@ export default `
221
190
 
222
191
  function readSignature() {
223
192
  if (!signaturePad) {
224
- console.warn('SignaturePad not initialized');
225
193
  return;
226
194
  }
227
-
228
- try {
229
- if (signaturePad.isEmpty()) {
230
- window.ReactNativeWebView && window.ReactNativeWebView.postMessage("EMPTY");
195
+
196
+ if (signaturePad.isEmpty()) {
197
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage("EMPTY");
198
+ } else {
199
+ var imageType = '<%imageType%>' || 'image/png';
200
+ var url = signaturePad.toDataURL(imageType);
201
+
202
+ if (trimWhitespace === true) {
203
+ cropWhitespace(url);
231
204
  } else {
232
- var imageType = '<%imageType%>' || 'image/png';
233
- var url = signaturePad.toDataURL(imageType);
234
-
235
- if (trimWhitespace === true) {
236
- cropWhitespace(url);
237
- } else {
238
- window.ReactNativeWebView && window.ReactNativeWebView.postMessage(url);
239
- }
240
-
241
- if (autoClear === true && signaturePad) {
242
- signaturePad.clear();
243
- }
205
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage(url);
206
+ }
207
+
208
+ if (autoClear === true && signaturePad) {
209
+ signaturePad.clear();
244
210
  }
245
- } catch (error) {
246
- console.error('Error reading signature:', error);
247
211
  }
248
212
  }
249
213
 
250
214
  var autoClear = <%autoClear%>;
251
-
215
+
252
216
  var trimWhitespace = <%trimWhitespace%>;
253
217
 
254
218
  var dataURL = '<%dataURL%>';
@@ -259,18 +223,12 @@ export default `
259
223
  clearButton.addEventListener("click", clearSignature);
260
224
  }
261
225
 
262
- // Prevent race conditions by sequencing operations
263
226
  if (saveButton) {
264
227
  saveButton.addEventListener("click", function() {
265
- try {
266
- readSignature();
267
- // Small delay to prevent race condition
268
- setTimeout(function() {
269
- getData();
270
- }, 10);
271
- } catch (error) {
272
- console.error('Error in save button click:', error);
273
- }
228
+ readSignature();
229
+ setTimeout(function() {
230
+ getData();
231
+ }, 10);
274
232
  });
275
233
  }
276
234
  `;
package/index.d.ts CHANGED
@@ -76,8 +76,11 @@ declare module "react-native-signature-canvas" {
76
76
  readSignature: () => void;
77
77
  undo: () => void;
78
78
  redo: () => void;
79
- fromData: (pointGroups, suppressClear = false) => void;
80
- // Removed cropWhitespace as it's not exposed in the component
79
+ fromData: (pointGroups: any[], suppressClear?: boolean) => void;
80
+ /** Set dataURL without causing WebView reload - useful for restoring signatures */
81
+ setDataURL: (url: string) => void;
82
+ /** Force reinitialize WebView - useful for bottom sheets/modals where WebView state is lost */
83
+ reinitialize: () => void;
81
84
  };
82
85
 
83
86
  // Enhanced component interface with better type safety
package/index.js CHANGED
@@ -46,6 +46,17 @@ const styles = StyleSheet.create({
46
46
  },
47
47
  });
48
48
 
49
+ const getParamForInjection = (param) => {
50
+ switch (typeof param) {
51
+ case "string":
52
+ return `'${param}'`
53
+ case "object":
54
+ return JSON.stringify(param)
55
+ default:
56
+ return param
57
+ }
58
+ }
59
+
49
60
  const SignatureView = forwardRef(
50
61
  (
51
62
  {
@@ -97,18 +108,29 @@ const SignatureView = forwardRef(
97
108
  ref
98
109
  ) => {
99
110
  const [loading, setLoading] = useState(true);
100
-
101
111
  const [hasError, setHasError] = useState(false);
102
112
  const [retryCount, setRetryCount] = useState(0);
113
+ // Key to force WebView remount when needed (e.g., after content process termination)
114
+ const [webViewKey, setWebViewKey] = useState(0);
103
115
  const maxRetries = 3;
104
116
  const webViewRef = useRef();
117
+ // Store dataURL for injection - updates when dataURL prop changes
118
+ const currentDataURLRef = useRef(dataURL);
119
+
120
+ // Update ref when dataURL prop changes
121
+ useEffect(() => {
122
+ currentDataURLRef.current = dataURL;
123
+ }, [dataURL]);
124
+
105
125
  // Split source generation for better performance
126
+ // Include webViewKey to regenerate script when WebView needs remounting
106
127
  const injectedScript = useMemo(() => {
107
128
  let script = injectedSignaturePad + injectedApplication;
108
129
  script = script.replace(/<%autoClear%>/g, autoClear);
109
130
  script = script.replace(/<%trimWhitespace%>/g, trimWhitespace);
110
131
  script = script.replace(/<%imageType%>/g, imageType || "image/png");
111
- script = script.replace(/<%dataURL%>/g, dataURL || "");
132
+ // Use currentDataURLRef to get the latest dataURL value
133
+ script = script.replace(/<%dataURL%>/g, currentDataURLRef.current || "");
112
134
  script = script.replace(/<%penColor%>/g, penColor || "black");
113
135
  script = script.replace(/<%backgroundColor%>/g, backgroundColor || "rgba(255,255,255,0)");
114
136
  script = script.replace(/<%dotSize%>/g, dotSize || "null");
@@ -117,7 +139,7 @@ const SignatureView = forwardRef(
117
139
  script = script.replace(/<%minDistance%>/g, minDistance || 5);
118
140
  script = script.replace(/<%orientation%>/g, rotated || false);
119
141
  return script;
120
- }, [autoClear, trimWhitespace, imageType, dataURL, penColor, backgroundColor, dotSize, minWidth, maxWidth, minDistance, rotated]);
142
+ }, [autoClear, trimWhitespace, imageType, penColor, backgroundColor, dotSize, minWidth, maxWidth, minDistance, rotated, webViewKey]);
121
143
 
122
144
  const source = useMemo(() => {
123
145
  const htmlContentValue = customHtml || htmlContent;
@@ -137,23 +159,33 @@ const SignatureView = forwardRef(
137
159
  return { html };
138
160
  }, [injectedScript, customHtml, bgWidth, bgHeight, bgSrc, overlayWidth, overlayHeight, overlaySrc, webStyle, descriptionText, confirmText, clearText, rotated]);
139
161
 
140
- // Optimize WebView reload to prevent excessive reloads
141
- const [shouldReload, setShouldReload] = useState(false);
162
+ // Handle dataURL changes dynamically without reloading WebView
163
+ const prevDataURLRef = useRef(dataURL);
142
164
 
143
165
  useEffect(() => {
144
- setShouldReload(true);
145
- }, [source]);
166
+ // Skip if dataURL hasn't changed or WebView isn't ready
167
+ if (prevDataURLRef.current === dataURL || !webViewRef.current || loading) {
168
+ return;
169
+ }
146
170
 
147
- useEffect(() => {
148
- if (shouldReload && webViewRef.current) {
171
+ prevDataURLRef.current = dataURL;
172
+
173
+ // Update dataURL in WebView without full reload
174
+ if (dataURL) {
175
+ const script = `
176
+ dataURL = '${dataURL}';
177
+ if (signaturePad && signaturePad.isEmpty()) {
178
+ signaturePad.fromDataURL(dataURL);
179
+ }
180
+ true;
181
+ `;
149
182
  try {
150
- webViewRef.current.reload();
151
- setShouldReload(false);
183
+ webViewRef.current.injectJavaScript(script);
152
184
  } catch (error) {
153
- console.warn("WebView reload failed:", error);
185
+ console.warn("Failed to update dataURL:", error);
154
186
  }
155
187
  }
156
- }, [shouldReload]);
188
+ }, [dataURL, loading]);
157
189
 
158
190
  const isJson = (str) => {
159
191
  try {
@@ -228,7 +260,7 @@ const SignatureView = forwardRef(
228
260
 
229
261
  try {
230
262
  const script = params.length > 0
231
- ? `${method}(${params.map(p => typeof p === 'string' ? `'${p}'` : p).join(',')});true;`
263
+ ? `${method}(${params.map(getParamForInjection).join(',')});true;`
232
264
  : `${method}();true;`;
233
265
  webViewRef.current.injectJavaScript(script);
234
266
  } catch (error) {
@@ -267,6 +299,38 @@ const SignatureView = forwardRef(
267
299
  }
268
300
  executeWebViewMethod('fromData', [pointGroups, false]);
269
301
  },
302
+ // New method to set dataURL without causing WebView reload
303
+ setDataURL: (url) => {
304
+ if (typeof url !== 'string') {
305
+ console.warn('setDataURL: url must be a string');
306
+ return;
307
+ }
308
+ if (!webViewRef.current) {
309
+ console.warn('WebView ref is null when calling setDataURL');
310
+ return;
311
+ }
312
+ const script = `
313
+ dataURL = '${url}';
314
+ if (signaturePad) {
315
+ signaturePad.clear();
316
+ if (dataURL) {
317
+ signaturePad.fromDataURL(dataURL);
318
+ }
319
+ }
320
+ true;
321
+ `;
322
+ try {
323
+ webViewRef.current.injectJavaScript(script);
324
+ } catch (error) {
325
+ console.error('Error executing setDataURL:', error);
326
+ }
327
+ },
328
+ // Force reinitialize WebView - useful for bottom sheets/modals where WebView state is lost
329
+ reinitialize: () => {
330
+ setLoading(true);
331
+ setHasError(false);
332
+ setWebViewKey(prev => prev + 1);
333
+ },
270
334
  }),
271
335
  [executeWebViewMethod]
272
336
  );
@@ -296,6 +360,16 @@ const SignatureView = forwardRef(
296
360
  }
297
361
  }, [onError, retryCount, maxRetries]);
298
362
 
363
+ // Handle iOS WebView content process termination (WKWebView can be killed when app is backgrounded)
364
+ // This is crucial for bottom sheets and modals where the component stays mounted but WebView is killed
365
+ const handleContentProcessDidTerminate = useCallback(() => {
366
+ console.warn("WebView content process terminated, reinitializing...");
367
+ setLoading(true);
368
+ setHasError(false);
369
+ // Increment key to force WebView remount with fresh JavaScript context
370
+ setWebViewKey(prev => prev + 1);
371
+ }, []);
372
+
299
373
  const handleLoadEnd = useCallback(() => {
300
374
  setLoading(false);
301
375
  setHasError(false);
@@ -323,6 +397,8 @@ const SignatureView = forwardRef(
323
397
  return (
324
398
  <View style={[styles.webBg, style]}>
325
399
  <WebView
400
+ // Key for forcing remount when WebView needs reinitialization
401
+ key={`signature-webview-${webViewKey}`}
326
402
  // Core functionality props (cannot be overridden)
327
403
  ref={webViewRef}
328
404
  source={source}
@@ -331,11 +407,13 @@ const SignatureView = forwardRef(
331
407
  onLoadEnd={handleLoadEnd}
332
408
  onLoadStart={handleLoadStart}
333
409
  onLoadProgress={handleLoadProgress}
410
+ // Handle iOS WKWebView content process termination (crucial for bottom sheets/modals)
411
+ onContentProcessDidTerminate={handleContentProcessDidTerminate}
334
412
  javaScriptEnabled={true}
335
413
  useWebKit={true}
336
414
  // Default component props (can be overridden by webviewProps)
337
415
  bounces={false}
338
- style={[webviewContainerStyle]}
416
+ style={[{ flex: 1 }, webviewContainerStyle]}
339
417
  scrollEnabled={scrollable}
340
418
  androidLayerType={androidLayerType}
341
419
  androidHardwareAccelerationDisabled={
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "react-native-signature-canvas",
3
- "version": "5.0.1",
3
+ "version": "5.0.2",
4
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
- "genlog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
7
+ "genlog": "conventional-changelog -p angular -i CHANGELOG.md -s",
8
8
  "postversion": "git push --follow-tags"
9
9
  },
10
10
  "repository": {