react-native-rectangle-doc-scanner 3.114.0 → 3.117.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.
@@ -23,6 +23,7 @@ export interface FullDocScannerStrings {
23
23
  first?: string;
24
24
  second?: string;
25
25
  secondBtn?: string;
26
+ secondPrompt?: string;
26
27
  }
27
28
  export interface FullDocScannerProps {
28
29
  onResult: (results: FullDocScannerResult[]) => void;
@@ -145,6 +145,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
145
145
  first: strings?.first ?? 'Front',
146
146
  second: strings?.second ?? 'Back',
147
147
  secondBtn: strings?.secondBtn ?? 'Capture Back Side?',
148
+ secondPrompt: strings?.secondPrompt ?? strings?.secondBtn ?? 'Capture Back Side?',
148
149
  }), [strings]);
149
150
  const emitError = (0, react_1.useCallback)((error, fallbackMessage) => {
150
151
  console.error('[FullDocScanner] error', error);
@@ -392,20 +393,24 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
392
393
  };
393
394
  const updatedPhotos = [...capturedPhotos, currentPhoto];
394
395
  console.log('[FullDocScanner] Photos captured:', updatedPhotos.length, 'of', maxPhotos);
395
- // Business 모드이고 아직 첫 번째 사진만 찍은 경우
396
- if (isBusinessMode && updatedPhotos.length === 1) {
397
- // 두 번째 사진 촬영 여부를 물어봄 (UI에서 버튼으로 표시)
398
- setCapturedPhotos(updatedPhotos);
399
- setCurrentPhotoIndex(1);
400
- // 확인 화면을 유지하고 "뒷면 촬영" 버튼을 표시
401
- return;
402
- }
403
396
  // 모든 사진 촬영 완료 - 결과 반환
404
397
  console.log('[FullDocScanner] All photos captured, returning results');
405
398
  onResult(updatedPhotos);
406
- }, [croppedImageData, rotationDegrees, capturedPhotos, isBusinessMode, maxPhotos, onResult]);
399
+ }, [croppedImageData, rotationDegrees, capturedPhotos, onResult]);
407
400
  const handleCaptureSecondPhoto = (0, react_1.useCallback)(() => {
408
401
  console.log('[FullDocScanner] Capturing second photo');
402
+ if (!croppedImageData) {
403
+ return;
404
+ }
405
+ // 현재 사진(앞면)을 먼저 저장
406
+ const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
407
+ const currentPhoto = {
408
+ path: croppedImageData.path,
409
+ base64: croppedImageData.base64,
410
+ rotationDegrees: rotationNormalized,
411
+ };
412
+ setCapturedPhotos([currentPhoto]);
413
+ setCurrentPhotoIndex(1);
409
414
  // 확인 화면을 닫고 카메라로 돌아감
410
415
  setCroppedImageData(null);
411
416
  setRotationDegrees(0);
@@ -425,14 +430,34 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
425
430
  if (docScannerRef.current?.reset) {
426
431
  docScannerRef.current.reset();
427
432
  }
428
- }, []);
433
+ }, [croppedImageData, rotationDegrees]);
429
434
  const handleSkipSecondPhoto = (0, react_1.useCallback)(() => {
430
- console.log('[FullDocScanner] Skipping second photo');
431
- // 번째 사진만 반환
432
- onResult(capturedPhotos);
433
- }, [capturedPhotos, onResult]);
435
+ console.log('[FullDocScanner] Skipping second photo - saving current photo only');
436
+ if (!croppedImageData) {
437
+ return;
438
+ }
439
+ // 현재 사진만 저장하고 완료
440
+ const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
441
+ const currentPhoto = {
442
+ path: croppedImageData.path,
443
+ base64: croppedImageData.base64,
444
+ rotationDegrees: rotationNormalized,
445
+ };
446
+ onResult([currentPhoto]);
447
+ }, [croppedImageData, rotationDegrees, onResult]);
434
448
  const handleRetake = (0, react_1.useCallback)(() => {
435
449
  console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
450
+ // Business 모드에서 두 번째 사진을 다시 찍는 경우, 첫 번째 사진 유지
451
+ if (isBusinessMode && capturedPhotos.length === 1) {
452
+ console.log('[FullDocScanner] Retake detected on back photo - keeping front photo');
453
+ setCurrentPhotoIndex(1);
454
+ }
455
+ else {
456
+ // 첫 번째 사진 또는 일반 모드: 모든 상태 초기화
457
+ console.log('[FullDocScanner] Retake detected - resetting all photos');
458
+ setCapturedPhotos([]);
459
+ setCurrentPhotoIndex(0);
460
+ }
436
461
  setCroppedImageData(null);
437
462
  setRotationDegrees(0);
438
463
  setProcessing(false);
@@ -452,7 +477,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
452
477
  if (docScannerRef.current?.reset) {
453
478
  docScannerRef.current.reset();
454
479
  }
455
- }, []);
480
+ }, [capturedPhotos.length, isBusinessMode]);
456
481
  const handleRectangleDetect = (0, react_1.useCallback)((event) => {
457
482
  const stableCounter = event.stableCounter ?? 0;
458
483
  const rectangleCoordinates = event.rectangleOnScreen ?? event.rectangleCoordinates;
@@ -521,7 +546,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
521
546
  react_1.default.createElement(react_native_1.View, { style: styles.confirmationButtons },
522
547
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.retakeButton], onPress: handleRetake, accessibilityLabel: mergedStrings.retake, accessibilityRole: "button" },
523
548
  react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
524
- isBusinessMode && capturedPhotos.length === 1 && currentPhotoIndex === 1 ? (react_1.default.createElement(react_1.default.Fragment, null,
549
+ isBusinessMode && capturedPhotos.length === 0 ? (react_1.default.createElement(react_1.default.Fragment, null,
525
550
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleCaptureSecondPhoto, accessibilityLabel: mergedStrings.secondBtn, accessibilityRole: "button" },
526
551
  react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.secondBtn)),
527
552
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.skipButton], onPress: handleSkipSecondPhoto, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
@@ -718,6 +743,14 @@ const styles = react_native_1.StyleSheet.create({
718
743
  width: '100%',
719
744
  height: '80%',
720
745
  },
746
+ confirmationPromptText: {
747
+ color: '#fff',
748
+ fontSize: 18,
749
+ fontWeight: '600',
750
+ textAlign: 'center',
751
+ paddingHorizontal: 32,
752
+ marginTop: 24,
753
+ },
721
754
  confirmationButtons: {
722
755
  flexDirection: 'row',
723
756
  justifyContent: 'center',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.114.0",
3
+ "version": "3.117.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -138,6 +138,7 @@ export interface FullDocScannerStrings {
138
138
  first?: string;
139
139
  second?: string;
140
140
  secondBtn?: string;
141
+ secondPrompt?: string;
141
142
  }
142
143
 
143
144
  export interface FullDocScannerProps {
@@ -205,6 +206,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
205
206
  first: strings?.first ?? 'Front',
206
207
  second: strings?.second ?? 'Back',
207
208
  secondBtn: strings?.secondBtn ?? 'Capture Back Side?',
209
+ secondPrompt: strings?.secondPrompt ?? strings?.secondBtn ?? 'Capture Back Side?',
208
210
  }),
209
211
  [strings],
210
212
  );
@@ -529,22 +531,29 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
529
531
  const updatedPhotos = [...capturedPhotos, currentPhoto];
530
532
  console.log('[FullDocScanner] Photos captured:', updatedPhotos.length, 'of', maxPhotos);
531
533
 
532
- // Business 모드이고 아직 첫 번째 사진만 찍은 경우
533
- if (isBusinessMode && updatedPhotos.length === 1) {
534
- // 두 번째 사진 촬영 여부를 물어봄 (UI에서 버튼으로 표시)
535
- setCapturedPhotos(updatedPhotos);
536
- setCurrentPhotoIndex(1);
537
- // 확인 화면을 유지하고 "뒷면 촬영" 버튼을 표시
538
- return;
539
- }
540
-
541
534
  // 모든 사진 촬영 완료 - 결과 반환
542
535
  console.log('[FullDocScanner] All photos captured, returning results');
543
536
  onResult(updatedPhotos);
544
- }, [croppedImageData, rotationDegrees, capturedPhotos, isBusinessMode, maxPhotos, onResult]);
537
+ }, [croppedImageData, rotationDegrees, capturedPhotos, onResult]);
545
538
 
546
539
  const handleCaptureSecondPhoto = useCallback(() => {
547
540
  console.log('[FullDocScanner] Capturing second photo');
541
+
542
+ if (!croppedImageData) {
543
+ return;
544
+ }
545
+
546
+ // 현재 사진(앞면)을 먼저 저장
547
+ const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
548
+ const currentPhoto: FullDocScannerResult = {
549
+ path: croppedImageData.path,
550
+ base64: croppedImageData.base64,
551
+ rotationDegrees: rotationNormalized,
552
+ };
553
+
554
+ setCapturedPhotos([currentPhoto]);
555
+ setCurrentPhotoIndex(1);
556
+
548
557
  // 확인 화면을 닫고 카메라로 돌아감
549
558
  setCroppedImageData(null);
550
559
  setRotationDegrees(0);
@@ -564,16 +573,40 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
564
573
  if (docScannerRef.current?.reset) {
565
574
  docScannerRef.current.reset();
566
575
  }
567
- }, []);
576
+ }, [croppedImageData, rotationDegrees]);
568
577
 
569
578
  const handleSkipSecondPhoto = useCallback(() => {
570
- console.log('[FullDocScanner] Skipping second photo');
571
- // 첫 번째 사진만 반환
572
- onResult(capturedPhotos);
573
- }, [capturedPhotos, onResult]);
579
+ console.log('[FullDocScanner] Skipping second photo - saving current photo only');
580
+
581
+ if (!croppedImageData) {
582
+ return;
583
+ }
584
+
585
+ // 현재 사진만 저장하고 완료
586
+ const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
587
+ const currentPhoto: FullDocScannerResult = {
588
+ path: croppedImageData.path,
589
+ base64: croppedImageData.base64,
590
+ rotationDegrees: rotationNormalized,
591
+ };
592
+
593
+ onResult([currentPhoto]);
594
+ }, [croppedImageData, rotationDegrees, onResult]);
574
595
 
575
596
  const handleRetake = useCallback(() => {
576
597
  console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
598
+
599
+ // Business 모드에서 두 번째 사진을 다시 찍는 경우, 첫 번째 사진 유지
600
+ if (isBusinessMode && capturedPhotos.length === 1) {
601
+ console.log('[FullDocScanner] Retake detected on back photo - keeping front photo');
602
+ setCurrentPhotoIndex(1);
603
+ } else {
604
+ // 첫 번째 사진 또는 일반 모드: 모든 상태 초기화
605
+ console.log('[FullDocScanner] Retake detected - resetting all photos');
606
+ setCapturedPhotos([]);
607
+ setCurrentPhotoIndex(0);
608
+ }
609
+
577
610
  setCroppedImageData(null);
578
611
  setRotationDegrees(0);
579
612
  setProcessing(false);
@@ -593,7 +626,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
593
626
  if (docScannerRef.current?.reset) {
594
627
  docScannerRef.current.reset();
595
628
  }
596
- }, []);
629
+ }, [capturedPhotos.length, isBusinessMode]);
597
630
 
598
631
  const handleRectangleDetect = useCallback((event: RectangleDetectEvent) => {
599
632
  const stableCounter = event.stableCounter ?? 0;
@@ -707,8 +740,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
707
740
  <Text style={styles.confirmButtonText}>{mergedStrings.retake}</Text>
708
741
  </TouchableOpacity>
709
742
 
710
- {/* Business 모드이고 첫 번째 사진을 찍은 후: 뒷면 촬영 버튼 또는 확인 버튼 */}
711
- {isBusinessMode && capturedPhotos.length === 1 && currentPhotoIndex === 1 ? (
743
+ {/* Business 모드이고 첫 번째 사진일 때: 뒷면 촬영 버튼과 확인 버튼 동시 표시 */}
744
+ {isBusinessMode && capturedPhotos.length === 0 ? (
712
745
  <>
713
746
  <TouchableOpacity
714
747
  style={[styles.confirmButton, styles.confirmButtonPrimary]}
@@ -1008,6 +1041,14 @@ const styles = StyleSheet.create({
1008
1041
  width: '100%',
1009
1042
  height: '80%',
1010
1043
  },
1044
+ confirmationPromptText: {
1045
+ color: '#fff',
1046
+ fontSize: 18,
1047
+ fontWeight: '600',
1048
+ textAlign: 'center',
1049
+ paddingHorizontal: 32,
1050
+ marginTop: 24,
1051
+ },
1011
1052
  confirmationButtons: {
1012
1053
  flexDirection: 'row',
1013
1054
  justifyContent: 'center',