react-native-rectangle-doc-scanner 3.122.0 → 3.123.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/FullDocScanner.js +31 -50
- package/package.json +1 -1
- package/src/FullDocScanner.tsx +41 -51
package/dist/FullDocScanner.js
CHANGED
|
@@ -125,6 +125,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
125
125
|
const [rotationDegrees, setRotationDegrees] = (0, react_1.useState)(0);
|
|
126
126
|
const [capturedPhotos, setCapturedPhotos] = (0, react_1.useState)([]);
|
|
127
127
|
const [currentPhotoIndex, setCurrentPhotoIndex] = (0, react_1.useState)(0);
|
|
128
|
+
const [scannerSession, setScannerSession] = (0, react_1.useState)(0);
|
|
128
129
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
129
130
|
const docScannerRef = (0, react_1.useRef)(null);
|
|
130
131
|
const captureModeRef = (0, react_1.useRef)(null);
|
|
@@ -132,6 +133,29 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
132
133
|
const rectangleCaptureTimeoutRef = (0, react_1.useRef)(null);
|
|
133
134
|
const rectangleHintTimeoutRef = (0, react_1.useRef)(null);
|
|
134
135
|
const isBusinessMode = type === 'business';
|
|
136
|
+
const resetScannerView = (0, react_1.useCallback)((options) => {
|
|
137
|
+
setProcessing(false);
|
|
138
|
+
setCroppedImageData(null);
|
|
139
|
+
setRotationDegrees(0);
|
|
140
|
+
setRectangleDetected(false);
|
|
141
|
+
setRectangleHint(false);
|
|
142
|
+
captureModeRef.current = null;
|
|
143
|
+
captureInProgressRef.current = false;
|
|
144
|
+
if (rectangleCaptureTimeoutRef.current) {
|
|
145
|
+
clearTimeout(rectangleCaptureTimeoutRef.current);
|
|
146
|
+
rectangleCaptureTimeoutRef.current = null;
|
|
147
|
+
}
|
|
148
|
+
if (rectangleHintTimeoutRef.current) {
|
|
149
|
+
clearTimeout(rectangleHintTimeoutRef.current);
|
|
150
|
+
rectangleHintTimeoutRef.current = null;
|
|
151
|
+
}
|
|
152
|
+
if (docScannerRef.current?.reset) {
|
|
153
|
+
docScannerRef.current.reset();
|
|
154
|
+
}
|
|
155
|
+
if (options?.remount) {
|
|
156
|
+
setScannerSession((prev) => prev + 1);
|
|
157
|
+
}
|
|
158
|
+
}, []);
|
|
135
159
|
const mergedStrings = (0, react_1.useMemo)(() => ({
|
|
136
160
|
captureHint: strings?.captureHint,
|
|
137
161
|
manualHint: strings?.manualHint,
|
|
@@ -191,15 +215,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
191
215
|
});
|
|
192
216
|
}
|
|
193
217
|
catch (error) {
|
|
194
|
-
|
|
195
|
-
// Reset capture state when cropper fails or is cancelled
|
|
196
|
-
captureInProgressRef.current = false;
|
|
197
|
-
captureModeRef.current = null;
|
|
198
|
-
setRectangleDetected(false);
|
|
199
|
-
setRectangleHint(false);
|
|
200
|
-
if (docScannerRef.current?.reset) {
|
|
201
|
-
docScannerRef.current.reset();
|
|
202
|
-
}
|
|
218
|
+
resetScannerView({ remount: true });
|
|
203
219
|
const errorCode = error?.code;
|
|
204
220
|
const errorMessageRaw = error?.message ?? String(error);
|
|
205
221
|
const errorMessage = typeof errorMessageRaw === 'string' ? errorMessageRaw : String(errorMessageRaw);
|
|
@@ -220,7 +236,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
220
236
|
emitError(error instanceof Error ? error : new Error(errorMessage), 'Failed to crop image. Please try again.');
|
|
221
237
|
}
|
|
222
238
|
}
|
|
223
|
-
}, [cropWidth, cropHeight, emitError]);
|
|
239
|
+
}, [cropWidth, cropHeight, emitError, resetScannerView]);
|
|
224
240
|
const handleCapture = (0, react_1.useCallback)(async (document) => {
|
|
225
241
|
console.log('[FullDocScanner] handleCapture called:', {
|
|
226
242
|
origin: document.origin,
|
|
@@ -419,25 +435,8 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
419
435
|
setCapturedPhotos([currentPhoto]);
|
|
420
436
|
setCurrentPhotoIndex(1);
|
|
421
437
|
// 확인 화면을 닫고 카메라로 돌아감
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
setProcessing(false);
|
|
425
|
-
setRectangleDetected(false);
|
|
426
|
-
setRectangleHint(false);
|
|
427
|
-
captureModeRef.current = null;
|
|
428
|
-
captureInProgressRef.current = false;
|
|
429
|
-
if (rectangleCaptureTimeoutRef.current) {
|
|
430
|
-
clearTimeout(rectangleCaptureTimeoutRef.current);
|
|
431
|
-
rectangleCaptureTimeoutRef.current = null;
|
|
432
|
-
}
|
|
433
|
-
if (rectangleHintTimeoutRef.current) {
|
|
434
|
-
clearTimeout(rectangleHintTimeoutRef.current);
|
|
435
|
-
rectangleHintTimeoutRef.current = null;
|
|
436
|
-
}
|
|
437
|
-
if (docScannerRef.current?.reset) {
|
|
438
|
-
docScannerRef.current.reset();
|
|
439
|
-
}
|
|
440
|
-
}, [croppedImageData, rotationDegrees]);
|
|
438
|
+
resetScannerView({ remount: true });
|
|
439
|
+
}, [croppedImageData, resetScannerView, rotationDegrees]);
|
|
441
440
|
const handleRetake = (0, react_1.useCallback)(() => {
|
|
442
441
|
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|
|
443
442
|
// Business 모드에서 두 번째 사진을 다시 찍는 경우, 첫 번째 사진 유지
|
|
@@ -451,26 +450,8 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
451
450
|
setCapturedPhotos([]);
|
|
452
451
|
setCurrentPhotoIndex(0);
|
|
453
452
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
setProcessing(false);
|
|
457
|
-
setRectangleDetected(false);
|
|
458
|
-
setRectangleHint(false);
|
|
459
|
-
captureModeRef.current = null;
|
|
460
|
-
captureInProgressRef.current = false;
|
|
461
|
-
if (rectangleCaptureTimeoutRef.current) {
|
|
462
|
-
clearTimeout(rectangleCaptureTimeoutRef.current);
|
|
463
|
-
rectangleCaptureTimeoutRef.current = null;
|
|
464
|
-
}
|
|
465
|
-
if (rectangleHintTimeoutRef.current) {
|
|
466
|
-
clearTimeout(rectangleHintTimeoutRef.current);
|
|
467
|
-
rectangleHintTimeoutRef.current = null;
|
|
468
|
-
}
|
|
469
|
-
// Reset DocScanner state
|
|
470
|
-
if (docScannerRef.current?.reset) {
|
|
471
|
-
docScannerRef.current.reset();
|
|
472
|
-
}
|
|
473
|
-
}, [capturedPhotos.length, isBusinessMode]);
|
|
453
|
+
resetScannerView({ remount: true });
|
|
454
|
+
}, [capturedPhotos.length, isBusinessMode, resetScannerView]);
|
|
474
455
|
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
|
475
456
|
const stableCounter = event.stableCounter ?? 0;
|
|
476
457
|
const rectangleCoordinates = event.rectangleOnScreen ?? event.rectangleCoordinates;
|
|
@@ -548,7 +529,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
548
529
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
|
|
549
530
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
|
|
550
531
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
551
|
-
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, enableTorch: flashEnabled },
|
|
532
|
+
react_1.default.createElement(DocScanner_1.DocScanner, { key: scannerSession, ref: docScannerRef, autoCapture: false, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, onRectangleDetect: handleRectangleDetect, showManualCaptureButton: false, enableTorch: flashEnabled },
|
|
552
533
|
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
553
534
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [
|
|
554
535
|
styles.iconButton,
|
package/package.json
CHANGED
package/src/FullDocScanner.tsx
CHANGED
|
@@ -183,6 +183,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
183
183
|
const [rotationDegrees, setRotationDegrees] = useState(0);
|
|
184
184
|
const [capturedPhotos, setCapturedPhotos] = useState<FullDocScannerResult[]>([]);
|
|
185
185
|
const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0);
|
|
186
|
+
const [scannerSession, setScannerSession] = useState(0);
|
|
186
187
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
187
188
|
const docScannerRef = useRef<DocScannerHandle | null>(null);
|
|
188
189
|
const captureModeRef = useRef<'grid' | 'no-grid' | null>(null);
|
|
@@ -192,6 +193,37 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
192
193
|
|
|
193
194
|
const isBusinessMode = type === 'business';
|
|
194
195
|
|
|
196
|
+
const resetScannerView = useCallback(
|
|
197
|
+
(options?: { remount?: boolean }) => {
|
|
198
|
+
setProcessing(false);
|
|
199
|
+
setCroppedImageData(null);
|
|
200
|
+
setRotationDegrees(0);
|
|
201
|
+
setRectangleDetected(false);
|
|
202
|
+
setRectangleHint(false);
|
|
203
|
+
captureModeRef.current = null;
|
|
204
|
+
captureInProgressRef.current = false;
|
|
205
|
+
|
|
206
|
+
if (rectangleCaptureTimeoutRef.current) {
|
|
207
|
+
clearTimeout(rectangleCaptureTimeoutRef.current);
|
|
208
|
+
rectangleCaptureTimeoutRef.current = null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (rectangleHintTimeoutRef.current) {
|
|
212
|
+
clearTimeout(rectangleHintTimeoutRef.current);
|
|
213
|
+
rectangleHintTimeoutRef.current = null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (docScannerRef.current?.reset) {
|
|
217
|
+
docScannerRef.current.reset();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (options?.remount) {
|
|
221
|
+
setScannerSession((prev) => prev + 1);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
[],
|
|
225
|
+
);
|
|
226
|
+
|
|
195
227
|
const mergedStrings = useMemo(
|
|
196
228
|
() => ({
|
|
197
229
|
captureHint: strings?.captureHint,
|
|
@@ -268,20 +300,12 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
268
300
|
base64: croppedImage.data ?? undefined,
|
|
269
301
|
});
|
|
270
302
|
} catch (error) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// Reset capture state when cropper fails or is cancelled
|
|
274
|
-
captureInProgressRef.current = false;
|
|
275
|
-
captureModeRef.current = null;
|
|
276
|
-
setRectangleDetected(false);
|
|
277
|
-
setRectangleHint(false);
|
|
278
|
-
if (docScannerRef.current?.reset) {
|
|
279
|
-
docScannerRef.current.reset();
|
|
280
|
-
}
|
|
303
|
+
resetScannerView({ remount: true });
|
|
281
304
|
|
|
282
305
|
const errorCode = (error as any)?.code;
|
|
283
306
|
const errorMessageRaw = (error as any)?.message ?? String(error);
|
|
284
|
-
const errorMessage =
|
|
307
|
+
const errorMessage =
|
|
308
|
+
typeof errorMessageRaw === 'string' ? errorMessageRaw : String(errorMessageRaw);
|
|
285
309
|
const normalizedMessage = errorMessage.toLowerCase();
|
|
286
310
|
const isUserCancelled =
|
|
287
311
|
errorCode === 'E_PICKER_CANCELLED' ||
|
|
@@ -309,7 +333,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
309
333
|
}
|
|
310
334
|
}
|
|
311
335
|
},
|
|
312
|
-
[cropWidth, cropHeight, emitError],
|
|
336
|
+
[cropWidth, cropHeight, emitError, resetScannerView],
|
|
313
337
|
);
|
|
314
338
|
|
|
315
339
|
const handleCapture = useCallback(
|
|
@@ -564,25 +588,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
564
588
|
setCurrentPhotoIndex(1);
|
|
565
589
|
|
|
566
590
|
// 확인 화면을 닫고 카메라로 돌아감
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
setProcessing(false);
|
|
570
|
-
setRectangleDetected(false);
|
|
571
|
-
setRectangleHint(false);
|
|
572
|
-
captureModeRef.current = null;
|
|
573
|
-
captureInProgressRef.current = false;
|
|
574
|
-
if (rectangleCaptureTimeoutRef.current) {
|
|
575
|
-
clearTimeout(rectangleCaptureTimeoutRef.current);
|
|
576
|
-
rectangleCaptureTimeoutRef.current = null;
|
|
577
|
-
}
|
|
578
|
-
if (rectangleHintTimeoutRef.current) {
|
|
579
|
-
clearTimeout(rectangleHintTimeoutRef.current);
|
|
580
|
-
rectangleHintTimeoutRef.current = null;
|
|
581
|
-
}
|
|
582
|
-
if (docScannerRef.current?.reset) {
|
|
583
|
-
docScannerRef.current.reset();
|
|
584
|
-
}
|
|
585
|
-
}, [croppedImageData, rotationDegrees]);
|
|
591
|
+
resetScannerView({ remount: true });
|
|
592
|
+
}, [croppedImageData, resetScannerView, rotationDegrees]);
|
|
586
593
|
|
|
587
594
|
|
|
588
595
|
const handleRetake = useCallback(() => {
|
|
@@ -599,26 +606,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
599
606
|
setCurrentPhotoIndex(0);
|
|
600
607
|
}
|
|
601
608
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
setProcessing(false);
|
|
605
|
-
setRectangleDetected(false);
|
|
606
|
-
setRectangleHint(false);
|
|
607
|
-
captureModeRef.current = null;
|
|
608
|
-
captureInProgressRef.current = false;
|
|
609
|
-
if (rectangleCaptureTimeoutRef.current) {
|
|
610
|
-
clearTimeout(rectangleCaptureTimeoutRef.current);
|
|
611
|
-
rectangleCaptureTimeoutRef.current = null;
|
|
612
|
-
}
|
|
613
|
-
if (rectangleHintTimeoutRef.current) {
|
|
614
|
-
clearTimeout(rectangleHintTimeoutRef.current);
|
|
615
|
-
rectangleHintTimeoutRef.current = null;
|
|
616
|
-
}
|
|
617
|
-
// Reset DocScanner state
|
|
618
|
-
if (docScannerRef.current?.reset) {
|
|
619
|
-
docScannerRef.current.reset();
|
|
620
|
-
}
|
|
621
|
-
}, [capturedPhotos.length, isBusinessMode]);
|
|
609
|
+
resetScannerView({ remount: true });
|
|
610
|
+
}, [capturedPhotos.length, isBusinessMode, resetScannerView]);
|
|
622
611
|
|
|
623
612
|
const handleRectangleDetect = useCallback((event: RectangleDetectEvent) => {
|
|
624
613
|
const stableCounter = event.stableCounter ?? 0;
|
|
@@ -781,6 +770,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
781
770
|
) : (
|
|
782
771
|
<View style={styles.flex}>
|
|
783
772
|
<DocScanner
|
|
773
|
+
key={scannerSession}
|
|
784
774
|
ref={docScannerRef}
|
|
785
775
|
autoCapture={false}
|
|
786
776
|
overlayColor={overlayColor}
|