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/WEBVIEW_PROPS.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# WebView Props Configuration
|
|
2
|
+
|
|
3
|
+
The `react-native-signature-canvas` component now supports a `webviewProps` parameter that allows you to customize the underlying WebView behavior while maintaining the core signature functionality.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```jsx
|
|
8
|
+
import SignatureCanvas from 'react-native-signature-canvas';
|
|
9
|
+
|
|
10
|
+
<SignatureCanvas
|
|
11
|
+
// ... other props
|
|
12
|
+
webviewProps={{
|
|
13
|
+
// Any WebView props can be passed here
|
|
14
|
+
cacheEnabled: false,
|
|
15
|
+
allowsFullscreenVideo: false,
|
|
16
|
+
decelerationRate: 'fast',
|
|
17
|
+
// ... more WebView props
|
|
18
|
+
}}
|
|
19
|
+
/>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Core vs Customizable Props
|
|
23
|
+
|
|
24
|
+
### Core Props (Cannot be overridden)
|
|
25
|
+
These props are essential for the signature functionality and cannot be overridden via `webviewProps`:
|
|
26
|
+
|
|
27
|
+
- `ref` - Internal WebView reference
|
|
28
|
+
- `source` - HTML content for signature pad
|
|
29
|
+
- `onMessage` - Message handler for signature events
|
|
30
|
+
- `onError` - Error handler (enhanced with retry logic)
|
|
31
|
+
- `onLoadEnd` - Load completion handler
|
|
32
|
+
- `onLoadStart` - Load start handler
|
|
33
|
+
- `onLoadProgress` - Load progress handler
|
|
34
|
+
- `javaScriptEnabled` - Must be true for signature pad to work
|
|
35
|
+
- `useWebKit` - Uses modern WebKit engine
|
|
36
|
+
|
|
37
|
+
### Default Props (Can be overridden)
|
|
38
|
+
These props have sensible defaults but can be customized via `webviewProps`:
|
|
39
|
+
|
|
40
|
+
#### Performance Optimizations
|
|
41
|
+
```jsx
|
|
42
|
+
webviewProps={{
|
|
43
|
+
cacheEnabled: true, // Enable/disable WebView cache
|
|
44
|
+
allowsInlineMediaPlayback: false, // Disable media playback
|
|
45
|
+
mediaPlaybackRequiresUserAction: true, // Require user action for media
|
|
46
|
+
allowsBackForwardNavigationGestures: false, // Disable navigation gestures
|
|
47
|
+
}}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
#### Security Enhancements
|
|
51
|
+
```jsx
|
|
52
|
+
webviewProps={{
|
|
53
|
+
allowsLinkPreview: false, // Disable link previews
|
|
54
|
+
allowFileAccess: false, // Disable file access
|
|
55
|
+
allowFileAccessFromFileURLs: false, // Disable file URL access
|
|
56
|
+
allowUniversalAccessFromFileURLs: false, // Disable universal access
|
|
57
|
+
mixedContentMode: "never", // Block mixed content
|
|
58
|
+
originWhitelist: ['*'], // Allow all origins
|
|
59
|
+
}}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### UI/UX Customization
|
|
63
|
+
```jsx
|
|
64
|
+
webviewProps={{
|
|
65
|
+
bounces: false, // Disable bounce effect
|
|
66
|
+
scrollEnabled: false, // Disable scrolling (use scrollable prop instead)
|
|
67
|
+
decelerationRate: 'fast', // Scroll deceleration rate
|
|
68
|
+
showsHorizontalScrollIndicator: false, // Hide horizontal scroll
|
|
69
|
+
showsVerticalScrollIndicator: false, // Hide vertical scroll
|
|
70
|
+
}}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### Android-Specific
|
|
74
|
+
```jsx
|
|
75
|
+
webviewProps={{
|
|
76
|
+
androidLayerType: "hardware", // Use hardware acceleration
|
|
77
|
+
androidHardwareAccelerationDisabled: false, // Enable hardware acceleration
|
|
78
|
+
}}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Common Use Cases
|
|
82
|
+
|
|
83
|
+
### High Performance Mode
|
|
84
|
+
```jsx
|
|
85
|
+
<SignatureCanvas
|
|
86
|
+
webviewProps={{
|
|
87
|
+
cacheEnabled: true,
|
|
88
|
+
androidLayerType: "hardware",
|
|
89
|
+
androidHardwareAccelerationDisabled: false,
|
|
90
|
+
}}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Low Memory Mode
|
|
95
|
+
```jsx
|
|
96
|
+
<SignatureCanvas
|
|
97
|
+
webviewProps={{
|
|
98
|
+
cacheEnabled: false,
|
|
99
|
+
androidLayerType: "software",
|
|
100
|
+
androidHardwareAccelerationDisabled: true,
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Enhanced Security
|
|
106
|
+
```jsx
|
|
107
|
+
<SignatureCanvas
|
|
108
|
+
webviewProps={{
|
|
109
|
+
allowFileAccess: false,
|
|
110
|
+
allowFileAccessFromFileURLs: false,
|
|
111
|
+
allowUniversalAccessFromFileURLs: false,
|
|
112
|
+
mixedContentMode: "never",
|
|
113
|
+
originWhitelist: [], // Block all external origins
|
|
114
|
+
}}
|
|
115
|
+
/>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Custom Scrolling Behavior
|
|
119
|
+
```jsx
|
|
120
|
+
<SignatureCanvas
|
|
121
|
+
webviewProps={{
|
|
122
|
+
decelerationRate: 'normal',
|
|
123
|
+
alwaysBounceVertical: false,
|
|
124
|
+
alwaysBounceHorizontal: false,
|
|
125
|
+
directionalLockEnabled: true,
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Important Notes
|
|
131
|
+
|
|
132
|
+
1. **Core Functionality**: The `webviewProps` cannot override core functionality props. These are protected to ensure the signature canvas works correctly.
|
|
133
|
+
|
|
134
|
+
2. **Prop Priority**: User-provided `webviewProps` take precedence over default props but not core props.
|
|
135
|
+
|
|
136
|
+
3. **TypeScript Support**: The `webviewProps` parameter is fully typed with `Partial<WebViewProps>` from `react-native-webview`.
|
|
137
|
+
|
|
138
|
+
4. **Performance Impact**: Some WebView props can significantly impact performance. Test thoroughly when customizing performance-related settings.
|
|
139
|
+
|
|
140
|
+
5. **Platform Differences**: Some props may behave differently on iOS vs Android. Refer to the `react-native-webview` documentation for platform-specific behavior.
|
|
141
|
+
|
|
142
|
+
## Migration from Previous Versions
|
|
143
|
+
|
|
144
|
+
If you were previously using individual WebView-related props, you can now consolidate them under `webviewProps`:
|
|
145
|
+
|
|
146
|
+
### Before
|
|
147
|
+
```jsx
|
|
148
|
+
<SignatureCanvas
|
|
149
|
+
androidLayerType="hardware"
|
|
150
|
+
androidHardwareAccelerationDisabled={false}
|
|
151
|
+
// other props...
|
|
152
|
+
/>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### After
|
|
156
|
+
```jsx
|
|
157
|
+
<SignatureCanvas
|
|
158
|
+
webviewProps={{
|
|
159
|
+
androidLayerType: "hardware",
|
|
160
|
+
androidHardwareAccelerationDisabled: false,
|
|
161
|
+
}}
|
|
162
|
+
// other props...
|
|
163
|
+
/>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Note: The old individual props are still supported for backward compatibility.
|
package/h5/js/app.js
CHANGED
|
@@ -1,28 +1,54 @@
|
|
|
1
1
|
export default `
|
|
2
|
+
// Enhanced error handling and validation
|
|
2
3
|
var wrapper = document.getElementById("signature-pad"),
|
|
3
|
-
clearButton = wrapper.querySelector("[data-action=clear]"),
|
|
4
|
-
saveButton = wrapper.querySelector("[data-action=save]"),
|
|
5
|
-
canvas = wrapper.querySelector("canvas"),
|
|
4
|
+
clearButton = wrapper && wrapper.querySelector("[data-action=clear]"),
|
|
5
|
+
saveButton = wrapper && wrapper.querySelector("[data-action=save]"),
|
|
6
|
+
canvas = wrapper && wrapper.querySelector("canvas"),
|
|
6
7
|
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
|
+
}
|
|
7
25
|
|
|
8
|
-
// Adjust canvas coordinate space taking into account pixel ratio,
|
|
9
|
-
// to make it look crisp on mobile devices.
|
|
10
|
-
// This also causes canvas to be cleared.
|
|
11
26
|
function resizeCanvas() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
if (!canvas || !canvas.getContext) {
|
|
28
|
+
console.warn('Canvas not available for resize');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
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);
|
|
46
|
+
}
|
|
23
47
|
}
|
|
24
48
|
|
|
25
|
-
|
|
49
|
+
// Use debounced resize handler
|
|
50
|
+
var debouncedResize = debounce(resizeCanvas, 100);
|
|
51
|
+
window.addEventListener('resize', debouncedResize);
|
|
26
52
|
resizeCanvas();
|
|
27
53
|
|
|
28
54
|
signaturePad = new SignaturePad(canvas, {
|
|
@@ -52,14 +78,30 @@ export default `
|
|
|
52
78
|
}
|
|
53
79
|
|
|
54
80
|
function changePenColor(color) {
|
|
81
|
+
if (!signaturePad) {
|
|
82
|
+
console.warn('SignaturePad not initialized');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
55
86
|
signaturePad.penColor = color;
|
|
56
|
-
window.ReactNativeWebView.postMessage("CHANGE_PEN");
|
|
87
|
+
window.ReactNativeWebView && window.ReactNativeWebView.postMessage("CHANGE_PEN");
|
|
57
88
|
}
|
|
58
89
|
|
|
59
90
|
function changePenSize(minW, maxW) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
91
|
+
if (!signaturePad) {
|
|
92
|
+
console.warn('SignaturePad not initialized');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Validate numeric values
|
|
97
|
+
if (typeof minW !== 'number' || typeof maxW !== 'number' || minW < 0 || maxW < minW) {
|
|
98
|
+
console.warn('Invalid pen size values:', minW, maxW);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
signaturePad.minWidth = minW;
|
|
103
|
+
signaturePad.maxWidth = maxW;
|
|
104
|
+
window.ReactNativeWebView && window.ReactNativeWebView.postMessage("CHANGE_PEN_SIZE");
|
|
63
105
|
}
|
|
64
106
|
|
|
65
107
|
function getData () {
|
|
@@ -67,6 +109,11 @@ export default `
|
|
|
67
109
|
window.ReactNativeWebView.postMessage(JSON.stringify(data));
|
|
68
110
|
}
|
|
69
111
|
|
|
112
|
+
function fromData (pointGroups) {
|
|
113
|
+
signaturePad.fromData(pointGroups);
|
|
114
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(pointGroups));
|
|
115
|
+
}
|
|
116
|
+
|
|
70
117
|
function draw() {
|
|
71
118
|
signaturePad.draw();
|
|
72
119
|
window.ReactNativeWebView.postMessage("DRAW");
|
|
@@ -87,8 +134,8 @@ export default `
|
|
|
87
134
|
|
|
88
135
|
//-----------------------------------------//
|
|
89
136
|
function removeImageBlanks(imageObject) {
|
|
90
|
-
imgWidth = imageObject.width;
|
|
91
|
-
imgHeight = imageObject.height;
|
|
137
|
+
var imgWidth = imageObject.width;
|
|
138
|
+
var imgHeight = imageObject.height;
|
|
92
139
|
var canvas = document.createElement('canvas');
|
|
93
140
|
canvas.setAttribute("width", imgWidth);
|
|
94
141
|
canvas.setAttribute("height", imgHeight);
|
|
@@ -97,7 +144,10 @@ export default `
|
|
|
97
144
|
|
|
98
145
|
var imageData = context.getImageData(0, 0, imgWidth, imgHeight),
|
|
99
146
|
data = imageData.data,
|
|
100
|
-
|
|
147
|
+
getRGB = function(x, y) {
|
|
148
|
+
if (x < 0 || x >= imgWidth || y < 0 || y >= imgHeight) {
|
|
149
|
+
return { red: 255, green: 255, blue: 255, opacity: 255 };
|
|
150
|
+
}
|
|
101
151
|
var offset = imgWidth * y + x;
|
|
102
152
|
return {
|
|
103
153
|
red: data[offset * 4],
|
|
@@ -118,7 +168,7 @@ export default `
|
|
|
118
168
|
|
|
119
169
|
// loop through each column
|
|
120
170
|
for(var x = 0; x < imgWidth; x++) {
|
|
121
|
-
var rgb =
|
|
171
|
+
var rgb = getRGB(x, y);
|
|
122
172
|
if (!isWhite(rgb)) {
|
|
123
173
|
if (fromTop) {
|
|
124
174
|
return y;
|
|
@@ -138,7 +188,7 @@ export default `
|
|
|
138
188
|
|
|
139
189
|
// loop through each row
|
|
140
190
|
for(var y = 0; y < imgHeight; y++) {
|
|
141
|
-
var rgb =
|
|
191
|
+
var rgb = getRGB(x, y);
|
|
142
192
|
if (!isWhite(rgb)) {
|
|
143
193
|
if (fromLeft) {
|
|
144
194
|
return x;
|
|
@@ -169,13 +219,31 @@ export default `
|
|
|
169
219
|
}
|
|
170
220
|
}
|
|
171
221
|
|
|
172
|
-
function readSignature()
|
|
173
|
-
if (signaturePad
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
222
|
+
function readSignature() {
|
|
223
|
+
if (!signaturePad) {
|
|
224
|
+
console.warn('SignaturePad not initialized');
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
if (signaturePad.isEmpty()) {
|
|
230
|
+
window.ReactNativeWebView && window.ReactNativeWebView.postMessage("EMPTY");
|
|
231
|
+
} 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
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error('Error reading signature:', error);
|
|
179
247
|
}
|
|
180
248
|
}
|
|
181
249
|
|
|
@@ -187,10 +255,22 @@ export default `
|
|
|
187
255
|
|
|
188
256
|
if (dataURL) signaturePad.fromDataURL(dataURL);
|
|
189
257
|
|
|
190
|
-
clearButton
|
|
258
|
+
if (clearButton) {
|
|
259
|
+
clearButton.addEventListener("click", clearSignature);
|
|
260
|
+
}
|
|
191
261
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
262
|
+
// Prevent race conditions by sequencing operations
|
|
263
|
+
if (saveButton) {
|
|
264
|
+
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
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
196
276
|
`;
|
package/index.d.ts
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
declare module "react-native-signature-canvas" {
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { StyleProp, ViewStyle } from "react-native";
|
|
4
|
+
import { WebViewProps } from "react-native-webview";
|
|
5
|
+
|
|
6
|
+
// Enhanced type definitions with better error handling
|
|
4
7
|
|
|
5
8
|
type ImageType = "image/png" | "image/jpeg" | "image/svg+xml";
|
|
6
9
|
|
|
7
|
-
type DataURL =
|
|
10
|
+
type DataURL = string; // Simplified - should be base64 data URL
|
|
8
11
|
|
|
9
12
|
type ForwardRef<T, P> = React.ForwardRefExoticComponent<
|
|
10
13
|
React.PropsWithoutRef<P> & React.RefAttributes<T>
|
|
11
14
|
>;
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
// Enhanced callback types
|
|
17
|
+
type SignatureCallback = (signature: string) => void;
|
|
18
|
+
type EmptyCallback = () => void;
|
|
19
|
+
type ErrorCallback = (error: Error) => void;
|
|
20
|
+
|
|
21
|
+
export type SignatureViewProps = {
|
|
14
22
|
androidHardwareAccelerationDisabled?: boolean;
|
|
15
23
|
autoClear?: boolean;
|
|
16
24
|
backgroundColor?: string;
|
|
@@ -27,21 +35,23 @@ declare module "react-native-signature-canvas" {
|
|
|
27
35
|
minWidth?: number;
|
|
28
36
|
maxWidth?: number;
|
|
29
37
|
minDistance?: number;
|
|
38
|
+
onError?: ErrorCallback; // Added missing prop
|
|
30
39
|
nestedScrollEnabled?: boolean;
|
|
31
40
|
showsVerticalScrollIndicator?: boolean;
|
|
32
|
-
onOK?:
|
|
33
|
-
onEmpty?:
|
|
34
|
-
onClear?:
|
|
35
|
-
onUndo?:
|
|
36
|
-
onRedo?:
|
|
37
|
-
onDraw?:
|
|
38
|
-
onErase?:
|
|
39
|
-
onGetData?: (data:
|
|
40
|
-
onChangePenColor?:
|
|
41
|
-
onChangePenSize?:
|
|
42
|
-
onBegin?:
|
|
43
|
-
onEnd?:
|
|
44
|
-
onLoadEnd?:
|
|
41
|
+
onOK?: SignatureCallback;
|
|
42
|
+
onEmpty?: EmptyCallback;
|
|
43
|
+
onClear?: EmptyCallback;
|
|
44
|
+
onUndo?: EmptyCallback;
|
|
45
|
+
onRedo?: EmptyCallback;
|
|
46
|
+
onDraw?: EmptyCallback;
|
|
47
|
+
onErase?: EmptyCallback;
|
|
48
|
+
onGetData?: (data: string) => void; // Should be JSON string
|
|
49
|
+
onChangePenColor?: EmptyCallback;
|
|
50
|
+
onChangePenSize?: EmptyCallback;
|
|
51
|
+
onBegin?: EmptyCallback;
|
|
52
|
+
onEnd?: EmptyCallback;
|
|
53
|
+
onLoadEnd?: EmptyCallback;
|
|
54
|
+
onError?: ErrorCallback; // Added missing error callback
|
|
45
55
|
overlayHeight?: number;
|
|
46
56
|
overlayWidth?: number;
|
|
47
57
|
overlaySrc?: string;
|
|
@@ -53,21 +63,32 @@ declare module "react-native-signature-canvas" {
|
|
|
53
63
|
webStyle?: string;
|
|
54
64
|
webviewContainerStyle?: StyleProp<ViewStyle>;
|
|
55
65
|
androidLayerType?: "none" | "software" | "hardware";
|
|
66
|
+
webviewProps?: Partial<WebViewProps>;
|
|
56
67
|
};
|
|
57
68
|
|
|
58
69
|
export type SignatureViewRef = {
|
|
59
70
|
changePenColor: (color: string) => void;
|
|
60
71
|
changePenSize: (minW: number, maxW: number) => void;
|
|
61
72
|
clearSignature: () => void;
|
|
62
|
-
cropWhitespace: (url: string) => void;
|
|
63
73
|
draw: () => void;
|
|
64
74
|
erase: () => void;
|
|
65
75
|
getData: () => void;
|
|
66
76
|
readSignature: () => void;
|
|
67
77
|
undo: () => void;
|
|
68
78
|
redo: () => void;
|
|
79
|
+
fromData: (pointGroups, suppressClear = false) => void;
|
|
80
|
+
// Removed cropWhitespace as it's not exposed in the component
|
|
69
81
|
};
|
|
70
82
|
|
|
71
|
-
|
|
83
|
+
// Enhanced component interface with better type safety
|
|
84
|
+
interface SignatureCanvasComponent
|
|
85
|
+
extends ForwardRef<SignatureViewRef, SignatureViewProps> {
|
|
86
|
+
displayName?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const SignatureView: SignatureCanvasComponent;
|
|
72
90
|
export default SignatureView;
|
|
91
|
+
|
|
92
|
+
// Export additional types for external use
|
|
93
|
+
export { SignatureViewProps, SignatureViewRef, ImageType, DataURL };
|
|
73
94
|
}
|