react-native-rectangle-doc-scanner 3.59.0 → 3.60.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/dist/DocScanner.js +2 -1
- package/dist/FullDocScanner.js +31 -16
- package/package.json +1 -1
- package/src/DocScanner.tsx +2 -1
- package/src/FullDocScanner.tsx +42 -19
package/dist/DocScanner.js
CHANGED
|
@@ -167,7 +167,8 @@ exports.DocScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor = DEFAUL
|
|
|
167
167
|
captureOriginRef.current = 'manual';
|
|
168
168
|
capture().catch((error) => {
|
|
169
169
|
captureOriginRef.current = 'auto';
|
|
170
|
-
console.
|
|
170
|
+
console.error('[DocScanner] manual capture failed', error);
|
|
171
|
+
throw error;
|
|
171
172
|
});
|
|
172
173
|
}, [capture]);
|
|
173
174
|
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
package/dist/FullDocScanner.js
CHANGED
|
@@ -83,8 +83,12 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
83
83
|
try {
|
|
84
84
|
console.log('[FullDocScanner] openCropper called with path:', imagePath);
|
|
85
85
|
setProcessing(true);
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
// Normalize path - ensure file:// prefix for iOS
|
|
87
|
+
const normalizedPath = imagePath.startsWith('file://') ? imagePath : `file://${imagePath}`;
|
|
88
|
+
console.log('[FullDocScanner] Normalized path:', normalizedPath);
|
|
89
|
+
// Add timeout to prevent hanging
|
|
90
|
+
const cropperPromise = react_native_image_crop_picker_1.default.openCropper({
|
|
91
|
+
path: normalizedPath,
|
|
88
92
|
mediaType: 'photo',
|
|
89
93
|
width: cropWidth,
|
|
90
94
|
height: cropHeight,
|
|
@@ -94,12 +98,16 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
94
98
|
includeBase64: true,
|
|
95
99
|
compressImageQuality: 0.9,
|
|
96
100
|
});
|
|
101
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
102
|
+
setTimeout(() => reject(new Error('Cropper timeout after 30 seconds')), 30000);
|
|
103
|
+
});
|
|
104
|
+
const croppedImage = await Promise.race([cropperPromise, timeoutPromise]);
|
|
97
105
|
console.log('[FullDocScanner] Cropper returned:', {
|
|
98
106
|
path: croppedImage.path,
|
|
99
107
|
hasBase64: !!croppedImage.data,
|
|
100
108
|
});
|
|
101
109
|
setProcessing(false);
|
|
102
|
-
// Show
|
|
110
|
+
// Show confirmation screen
|
|
103
111
|
setCroppedImageData({
|
|
104
112
|
path: croppedImage.path,
|
|
105
113
|
base64: croppedImage.data ?? undefined,
|
|
@@ -108,11 +116,14 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
108
116
|
catch (error) {
|
|
109
117
|
console.error('[FullDocScanner] openCropper error:', error);
|
|
110
118
|
setProcessing(false);
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
const errorMessage = error?.message || String(error);
|
|
120
|
+
if (errorMessage === 'User cancelled image selection' ||
|
|
121
|
+
errorMessage.includes('cancelled') ||
|
|
122
|
+
errorMessage.includes('cancel')) {
|
|
123
|
+
console.log('[FullDocScanner] User cancelled cropper');
|
|
113
124
|
}
|
|
114
125
|
else {
|
|
115
|
-
|
|
126
|
+
emitError(error instanceof Error ? error : new Error(errorMessage), 'Failed to crop image. Please try again.');
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
129
|
}, [cropWidth, cropHeight, emitError]);
|
|
@@ -125,14 +136,9 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
125
136
|
captureMode: captureModeRef.current,
|
|
126
137
|
});
|
|
127
138
|
captureInProgressRef.current = false;
|
|
128
|
-
if (document.origin === 'auto') {
|
|
129
|
-
console.log('[FullDocScanner] Ignoring auto capture result');
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
139
|
const captureMode = captureModeRef.current;
|
|
133
140
|
if (!captureMode) {
|
|
134
|
-
console.warn('[FullDocScanner] Missing capture mode for
|
|
135
|
-
captureModeRef.current = null;
|
|
141
|
+
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
136
142
|
return;
|
|
137
143
|
}
|
|
138
144
|
captureModeRef.current = null;
|
|
@@ -184,29 +190,37 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
184
190
|
captureInProgressRef.current = false;
|
|
185
191
|
})
|
|
186
192
|
.catch((error) => {
|
|
193
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
194
|
+
console.error('[FullDocScanner] Manual capture failed:', errorMessage, error);
|
|
187
195
|
captureModeRef.current = null;
|
|
188
196
|
captureInProgressRef.current = false;
|
|
189
|
-
console.error('[FullDocScanner] Manual capture failed:', error);
|
|
190
197
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
191
|
-
emitError(error, 'Failed to capture image.');
|
|
198
|
+
emitError(error, 'Failed to capture image. Please try again.');
|
|
192
199
|
}
|
|
193
200
|
});
|
|
194
201
|
}, [processing, rectangleDetected, emitError]);
|
|
195
202
|
const handleGalleryPick = (0, react_1.useCallback)(async () => {
|
|
196
203
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
197
204
|
if (processing || isGalleryOpen) {
|
|
205
|
+
console.log('[FullDocScanner] Skipping gallery pick - already processing:', { processing, isGalleryOpen });
|
|
198
206
|
return;
|
|
199
207
|
}
|
|
200
208
|
try {
|
|
201
209
|
setIsGalleryOpen(true);
|
|
210
|
+
console.log('[FullDocScanner] Launching image library...');
|
|
202
211
|
const result = await (0, react_native_image_picker_1.launchImageLibrary)({
|
|
203
212
|
mediaType: 'photo',
|
|
204
213
|
quality: 1,
|
|
205
214
|
selectionLimit: 1,
|
|
206
215
|
});
|
|
216
|
+
console.log('[FullDocScanner] Image library result:', {
|
|
217
|
+
didCancel: result.didCancel,
|
|
218
|
+
hasAssets: !!result.assets,
|
|
219
|
+
assetsLength: result.assets?.length,
|
|
220
|
+
});
|
|
207
221
|
setIsGalleryOpen(false);
|
|
208
222
|
if (result.didCancel || !result.assets?.[0]?.uri) {
|
|
209
|
-
console.log('[FullDocScanner] User cancelled gallery picker');
|
|
223
|
+
console.log('[FullDocScanner] User cancelled gallery picker or no image selected');
|
|
210
224
|
return;
|
|
211
225
|
}
|
|
212
226
|
const imageUri = result.assets[0].uri;
|
|
@@ -215,6 +229,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
215
229
|
await openCropper(imageUri);
|
|
216
230
|
}
|
|
217
231
|
catch (error) {
|
|
232
|
+
console.error('[FullDocScanner] Gallery pick error:', error);
|
|
218
233
|
setIsGalleryOpen(false);
|
|
219
234
|
emitError(error instanceof Error ? error : new Error(String(error)), 'Failed to pick image from gallery.');
|
|
220
235
|
}
|
|
@@ -290,7 +305,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
290
305
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
|
|
291
306
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
|
|
292
307
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
293
|
-
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture:
|
|
308
|
+
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: false, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, onRectangleDetect: handleRectangleDetect, showManualCaptureButton: false },
|
|
294
309
|
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
295
310
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
|
|
296
311
|
react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -241,7 +241,8 @@ export const DocScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
241
241
|
captureOriginRef.current = 'manual';
|
|
242
242
|
capture().catch((error) => {
|
|
243
243
|
captureOriginRef.current = 'auto';
|
|
244
|
-
console.
|
|
244
|
+
console.error('[DocScanner] manual capture failed', error);
|
|
245
|
+
throw error;
|
|
245
246
|
});
|
|
246
247
|
}, [capture]);
|
|
247
248
|
|
package/src/FullDocScanner.tsx
CHANGED
|
@@ -121,8 +121,14 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
121
121
|
try {
|
|
122
122
|
console.log('[FullDocScanner] openCropper called with path:', imagePath);
|
|
123
123
|
setProcessing(true);
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
|
|
125
|
+
// Normalize path - ensure file:// prefix for iOS
|
|
126
|
+
const normalizedPath = imagePath.startsWith('file://') ? imagePath : `file://${imagePath}`;
|
|
127
|
+
console.log('[FullDocScanner] Normalized path:', normalizedPath);
|
|
128
|
+
|
|
129
|
+
// Add timeout to prevent hanging
|
|
130
|
+
const cropperPromise = ImageCropPicker.openCropper({
|
|
131
|
+
path: normalizedPath,
|
|
126
132
|
mediaType: 'photo',
|
|
127
133
|
width: cropWidth,
|
|
128
134
|
height: cropHeight,
|
|
@@ -133,6 +139,12 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
133
139
|
compressImageQuality: 0.9,
|
|
134
140
|
});
|
|
135
141
|
|
|
142
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
143
|
+
setTimeout(() => reject(new Error('Cropper timeout after 30 seconds')), 30000);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const croppedImage = await Promise.race([cropperPromise, timeoutPromise]) as any;
|
|
147
|
+
|
|
136
148
|
console.log('[FullDocScanner] Cropper returned:', {
|
|
137
149
|
path: croppedImage.path,
|
|
138
150
|
hasBase64: !!croppedImage.data,
|
|
@@ -140,7 +152,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
140
152
|
|
|
141
153
|
setProcessing(false);
|
|
142
154
|
|
|
143
|
-
// Show
|
|
155
|
+
// Show confirmation screen
|
|
144
156
|
setCroppedImageData({
|
|
145
157
|
path: croppedImage.path,
|
|
146
158
|
base64: croppedImage.data ?? undefined,
|
|
@@ -148,13 +160,18 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
148
160
|
} catch (error) {
|
|
149
161
|
console.error('[FullDocScanner] openCropper error:', error);
|
|
150
162
|
setProcessing(false);
|
|
151
|
-
|
|
163
|
+
|
|
164
|
+
const errorMessage = (error as any)?.message || String(error);
|
|
165
|
+
|
|
166
|
+
if (errorMessage === 'User cancelled image selection' ||
|
|
167
|
+
errorMessage.includes('cancelled') ||
|
|
168
|
+
errorMessage.includes('cancel')) {
|
|
169
|
+
console.log('[FullDocScanner] User cancelled cropper');
|
|
170
|
+
} else {
|
|
152
171
|
emitError(
|
|
153
|
-
error instanceof Error ? error : new Error(
|
|
154
|
-
'Failed to crop image.',
|
|
172
|
+
error instanceof Error ? error : new Error(errorMessage),
|
|
173
|
+
'Failed to crop image. Please try again.',
|
|
155
174
|
);
|
|
156
|
-
} else {
|
|
157
|
-
console.log('[FullDocScanner] User cancelled cropper');
|
|
158
175
|
}
|
|
159
176
|
}
|
|
160
177
|
},
|
|
@@ -173,16 +190,10 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
173
190
|
|
|
174
191
|
captureInProgressRef.current = false;
|
|
175
192
|
|
|
176
|
-
if (document.origin === 'auto') {
|
|
177
|
-
console.log('[FullDocScanner] Ignoring auto capture result');
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
193
|
const captureMode = captureModeRef.current;
|
|
182
194
|
|
|
183
195
|
if (!captureMode) {
|
|
184
|
-
console.warn('[FullDocScanner] Missing capture mode for
|
|
185
|
-
captureModeRef.current = null;
|
|
196
|
+
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
186
197
|
return;
|
|
187
198
|
}
|
|
188
199
|
|
|
@@ -248,13 +259,15 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
248
259
|
captureInProgressRef.current = false;
|
|
249
260
|
})
|
|
250
261
|
.catch((error: unknown) => {
|
|
262
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
263
|
+
console.error('[FullDocScanner] Manual capture failed:', errorMessage, error);
|
|
251
264
|
captureModeRef.current = null;
|
|
252
265
|
captureInProgressRef.current = false;
|
|
253
|
-
|
|
266
|
+
|
|
254
267
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
255
268
|
emitError(
|
|
256
269
|
error,
|
|
257
|
-
'Failed to capture image.',
|
|
270
|
+
'Failed to capture image. Please try again.',
|
|
258
271
|
);
|
|
259
272
|
}
|
|
260
273
|
});
|
|
@@ -263,21 +276,30 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
263
276
|
const handleGalleryPick = useCallback(async () => {
|
|
264
277
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
265
278
|
if (processing || isGalleryOpen) {
|
|
279
|
+
console.log('[FullDocScanner] Skipping gallery pick - already processing:', { processing, isGalleryOpen });
|
|
266
280
|
return;
|
|
267
281
|
}
|
|
268
282
|
|
|
269
283
|
try {
|
|
270
284
|
setIsGalleryOpen(true);
|
|
285
|
+
console.log('[FullDocScanner] Launching image library...');
|
|
286
|
+
|
|
271
287
|
const result = await launchImageLibrary({
|
|
272
288
|
mediaType: 'photo',
|
|
273
289
|
quality: 1,
|
|
274
290
|
selectionLimit: 1,
|
|
275
291
|
});
|
|
276
292
|
|
|
293
|
+
console.log('[FullDocScanner] Image library result:', {
|
|
294
|
+
didCancel: result.didCancel,
|
|
295
|
+
hasAssets: !!result.assets,
|
|
296
|
+
assetsLength: result.assets?.length,
|
|
297
|
+
});
|
|
298
|
+
|
|
277
299
|
setIsGalleryOpen(false);
|
|
278
300
|
|
|
279
301
|
if (result.didCancel || !result.assets?.[0]?.uri) {
|
|
280
|
-
console.log('[FullDocScanner] User cancelled gallery picker');
|
|
302
|
+
console.log('[FullDocScanner] User cancelled gallery picker or no image selected');
|
|
281
303
|
return;
|
|
282
304
|
}
|
|
283
305
|
|
|
@@ -287,6 +309,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
287
309
|
// Open cropper with the selected image
|
|
288
310
|
await openCropper(imageUri);
|
|
289
311
|
} catch (error) {
|
|
312
|
+
console.error('[FullDocScanner] Gallery pick error:', error);
|
|
290
313
|
setIsGalleryOpen(false);
|
|
291
314
|
emitError(
|
|
292
315
|
error instanceof Error ? error : new Error(String(error)),
|
|
@@ -395,7 +418,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
395
418
|
<View style={styles.flex}>
|
|
396
419
|
<DocScanner
|
|
397
420
|
ref={docScannerRef}
|
|
398
|
-
autoCapture={
|
|
421
|
+
autoCapture={false}
|
|
399
422
|
overlayColor={overlayColor}
|
|
400
423
|
showGrid={showGrid}
|
|
401
424
|
gridColor={resolvedGridColor}
|