react-native-rectangle-doc-scanner 3.88.0 → 3.90.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.
@@ -301,14 +301,19 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
301
301
  hasAssets: !!result.assets,
302
302
  assetsLength: result.assets?.length,
303
303
  });
304
- setIsGalleryOpen(false);
305
304
  if (result.didCancel || !result.assets?.[0]?.uri) {
306
305
  console.log('[FullDocScanner] User cancelled gallery picker or no image selected');
306
+ setIsGalleryOpen(false);
307
307
  return;
308
308
  }
309
309
  const imageUri = result.assets[0].uri;
310
310
  console.log('[FullDocScanner] Gallery image selected:', imageUri);
311
- await openCropper(imageUri);
311
+ // Set gallery closed state immediately but wait for modal to dismiss
312
+ setIsGalleryOpen(false);
313
+ // Wait for the image picker modal to fully dismiss before opening cropper
314
+ await new Promise(resolve => setTimeout(resolve, 500));
315
+ // Now open cropper after picker is dismissed
316
+ await openCropper(imageUri, { waitForPickerDismissal: false });
312
317
  }
313
318
  catch (error) {
314
319
  console.error('[FullDocScanner] Gallery pick error:', error);
@@ -423,18 +428,24 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
423
428
  react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
424
429
  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 },
425
430
  react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
426
- react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
427
- react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
431
+ react_1.default.createElement(react_native_1.TouchableOpacity, { style: [
432
+ styles.iconButton,
433
+ processing && styles.buttonDisabled,
434
+ flashEnabled && styles.flashButtonActive
435
+ ], onPress: handleFlashToggle, disabled: processing, accessibilityLabel: "Toggle flash", accessibilityRole: "button" },
436
+ react_1.default.createElement(react_native_1.View, { style: styles.iconContainer },
437
+ react_1.default.createElement(react_native_1.Text, { style: styles.iconText }, "\u26A1\uFE0F"))),
438
+ react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.iconButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
439
+ react_1.default.createElement(react_native_1.View, { style: styles.iconContainer },
440
+ react_1.default.createElement(react_native_1.Text, { style: styles.closeIconText }, "\u00D7")))),
428
441
  (mergedStrings.captureHint || mergedStrings.manualHint) && (react_1.default.createElement(react_native_1.View, { style: styles.instructionsContainer, pointerEvents: "none" },
429
442
  react_1.default.createElement(react_native_1.View, { style: styles.instructions },
430
443
  mergedStrings.captureHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.captureHint)),
431
444
  mergedStrings.manualHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.manualHint))))),
432
445
  react_1.default.createElement(react_native_1.View, { style: styles.shutterContainer, pointerEvents: "box-none" },
433
- react_1.default.createElement(react_native_1.View, { style: styles.leftButtonsContainer },
434
- enableGallery && (react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.galleryButton, processing && styles.buttonDisabled], onPress: handleGalleryPick, disabled: processing, accessibilityLabel: mergedStrings.galleryButton, accessibilityRole: "button" },
435
- react_1.default.createElement(react_native_1.Text, { style: styles.galleryButtonText }, "\uD83D\uDCC1"))),
436
- react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.flashButton, processing && styles.buttonDisabled], onPress: handleFlashToggle, disabled: processing, accessibilityLabel: "Toggle flash", accessibilityRole: "button" },
437
- react_1.default.createElement(react_native_1.Text, { style: styles.flashButtonText }, flashEnabled ? '⚡' : '⚡️'))),
446
+ enableGallery && (react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.iconButton, processing && styles.buttonDisabled], onPress: handleGalleryPick, disabled: processing, accessibilityLabel: mergedStrings.galleryButton, accessibilityRole: "button" },
447
+ react_1.default.createElement(react_native_1.View, { style: styles.iconContainer },
448
+ react_1.default.createElement(react_native_1.Text, { style: styles.iconText }, "\uD83D\uDDBC\uFE0F")))),
438
449
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.shutterButton, processing && styles.buttonDisabled], onPress: triggerManualCapture, disabled: processing, accessibilityLabel: mergedStrings.manualHint, accessibilityRole: "button" },
439
450
  react_1.default.createElement(react_native_1.View, { style: [
440
451
  styles.shutterInner,
@@ -457,7 +468,11 @@ const styles = react_native_1.StyleSheet.create({
457
468
  overlayTop: {
458
469
  position: 'absolute',
459
470
  top: 48,
471
+ left: 24,
460
472
  right: 24,
473
+ flexDirection: 'row',
474
+ justifyContent: 'space-between',
475
+ alignItems: 'center',
461
476
  zIndex: 10,
462
477
  },
463
478
  instructionsContainer: {
@@ -479,28 +494,34 @@ const styles = react_native_1.StyleSheet.create({
479
494
  paddingHorizontal: 40,
480
495
  zIndex: 10,
481
496
  },
482
- leftButtonsContainer: {
483
- flexDirection: 'row',
484
- gap: 12,
485
- alignItems: 'center',
486
- flex: 1,
487
- },
488
497
  rightButtonsPlaceholder: {
489
- flex: 1,
498
+ width: 56,
490
499
  },
491
- closeButton: {
492
- width: 40,
493
- height: 40,
494
- borderRadius: 20,
495
- backgroundColor: 'rgba(0,0,0,0.5)',
500
+ iconButton: {
501
+ width: 44,
502
+ height: 44,
503
+ borderRadius: 22,
504
+ backgroundColor: 'rgba(50,50,50,0.8)',
496
505
  justifyContent: 'center',
497
506
  alignItems: 'center',
507
+ borderWidth: 1,
508
+ borderColor: 'rgba(255,255,255,0.3)',
509
+ },
510
+ iconContainer: {
511
+ justifyContent: 'center',
512
+ alignItems: 'center',
513
+ },
514
+ iconText: {
515
+ fontSize: 22,
498
516
  },
499
- closeButtonLabel: {
517
+ closeIconText: {
518
+ fontSize: 32,
519
+ fontWeight: '300',
500
520
  color: '#fff',
501
- fontSize: 28,
502
- lineHeight: 32,
503
- marginTop: -3,
521
+ },
522
+ flashButtonActive: {
523
+ backgroundColor: 'rgba(255,215,0,0.5)',
524
+ borderColor: '#FFD700',
504
525
  },
505
526
  instructions: {
506
527
  backgroundColor: 'rgba(0,0,0,0.55)',
@@ -513,32 +534,6 @@ const styles = react_native_1.StyleSheet.create({
513
534
  fontSize: 15,
514
535
  textAlign: 'center',
515
536
  },
516
- galleryButton: {
517
- width: 56,
518
- height: 56,
519
- borderRadius: 28,
520
- borderWidth: 3,
521
- borderColor: '#fff',
522
- justifyContent: 'center',
523
- alignItems: 'center',
524
- backgroundColor: 'rgba(255,255,255,0.1)',
525
- },
526
- galleryButtonText: {
527
- fontSize: 24,
528
- },
529
- flashButton: {
530
- width: 56,
531
- height: 56,
532
- borderRadius: 28,
533
- borderWidth: 3,
534
- borderColor: '#fff',
535
- justifyContent: 'center',
536
- alignItems: 'center',
537
- backgroundColor: 'rgba(255,255,255,0.1)',
538
- },
539
- flashButtonText: {
540
- fontSize: 24,
541
- },
542
537
  shutterButton: {
543
538
  width: 80,
544
539
  height: 80,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.88.0",
3
+ "version": "3.90.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -402,17 +402,23 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
402
402
  assetsLength: result.assets?.length,
403
403
  });
404
404
 
405
- setIsGalleryOpen(false);
406
-
407
405
  if (result.didCancel || !result.assets?.[0]?.uri) {
408
406
  console.log('[FullDocScanner] User cancelled gallery picker or no image selected');
407
+ setIsGalleryOpen(false);
409
408
  return;
410
409
  }
411
410
 
412
411
  const imageUri = result.assets[0].uri;
413
412
  console.log('[FullDocScanner] Gallery image selected:', imageUri);
414
413
 
415
- await openCropper(imageUri);
414
+ // Set gallery closed state immediately but wait for modal to dismiss
415
+ setIsGalleryOpen(false);
416
+
417
+ // Wait for the image picker modal to fully dismiss before opening cropper
418
+ await new Promise(resolve => setTimeout(resolve, 500));
419
+
420
+ // Now open cropper after picker is dismissed
421
+ await openCropper(imageUri, { waitForPickerDismissal: false });
416
422
  } catch (error) {
417
423
  console.error('[FullDocScanner] Gallery pick error:', error);
418
424
  setIsGalleryOpen(false);
@@ -578,12 +584,29 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
578
584
  >
579
585
  <View style={styles.overlayTop} pointerEvents="box-none">
580
586
  <TouchableOpacity
581
- style={styles.closeButton}
587
+ style={[
588
+ styles.iconButton,
589
+ processing && styles.buttonDisabled,
590
+ flashEnabled && styles.flashButtonActive
591
+ ]}
592
+ onPress={handleFlashToggle}
593
+ disabled={processing}
594
+ accessibilityLabel="Toggle flash"
595
+ accessibilityRole="button"
596
+ >
597
+ <View style={styles.iconContainer}>
598
+ <Text style={styles.iconText}>⚡️</Text>
599
+ </View>
600
+ </TouchableOpacity>
601
+ <TouchableOpacity
602
+ style={styles.iconButton}
582
603
  onPress={handleClose}
583
604
  accessibilityLabel={mergedStrings.cancel}
584
605
  accessibilityRole="button"
585
606
  >
586
- <Text style={styles.closeButtonLabel}>×</Text>
607
+ <View style={styles.iconContainer}>
608
+ <Text style={styles.closeIconText}>×</Text>
609
+ </View>
587
610
  </TouchableOpacity>
588
611
  </View>
589
612
  {(mergedStrings.captureHint || mergedStrings.manualHint) && (
@@ -599,28 +622,19 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
599
622
  </View>
600
623
  )}
601
624
  <View style={styles.shutterContainer} pointerEvents="box-none">
602
- <View style={styles.leftButtonsContainer}>
603
- {enableGallery && (
604
- <TouchableOpacity
605
- style={[styles.galleryButton, processing && styles.buttonDisabled]}
606
- onPress={handleGalleryPick}
607
- disabled={processing}
608
- accessibilityLabel={mergedStrings.galleryButton}
609
- accessibilityRole="button"
610
- >
611
- <Text style={styles.galleryButtonText}>📁</Text>
612
- </TouchableOpacity>
613
- )}
625
+ {enableGallery && (
614
626
  <TouchableOpacity
615
- style={[styles.flashButton, processing && styles.buttonDisabled]}
616
- onPress={handleFlashToggle}
627
+ style={[styles.iconButton, processing && styles.buttonDisabled]}
628
+ onPress={handleGalleryPick}
617
629
  disabled={processing}
618
- accessibilityLabel="Toggle flash"
630
+ accessibilityLabel={mergedStrings.galleryButton}
619
631
  accessibilityRole="button"
620
632
  >
621
- <Text style={styles.flashButtonText}>{flashEnabled ? '⚡' : '⚡️'}</Text>
633
+ <View style={styles.iconContainer}>
634
+ <Text style={styles.iconText}>🖼️</Text>
635
+ </View>
622
636
  </TouchableOpacity>
623
- </View>
637
+ )}
624
638
  <TouchableOpacity
625
639
  style={[styles.shutterButton, processing && styles.buttonDisabled]}
626
640
  onPress={triggerManualCapture}
@@ -662,7 +676,11 @@ const styles = StyleSheet.create({
662
676
  overlayTop: {
663
677
  position: 'absolute',
664
678
  top: 48,
679
+ left: 24,
665
680
  right: 24,
681
+ flexDirection: 'row',
682
+ justifyContent: 'space-between',
683
+ alignItems: 'center',
666
684
  zIndex: 10,
667
685
  },
668
686
  instructionsContainer: {
@@ -684,28 +702,34 @@ const styles = StyleSheet.create({
684
702
  paddingHorizontal: 40,
685
703
  zIndex: 10,
686
704
  },
687
- leftButtonsContainer: {
688
- flexDirection: 'row',
689
- gap: 12,
690
- alignItems: 'center',
691
- flex: 1,
692
- },
693
705
  rightButtonsPlaceholder: {
694
- flex: 1,
706
+ width: 56,
695
707
  },
696
- closeButton: {
697
- width: 40,
698
- height: 40,
699
- borderRadius: 20,
700
- backgroundColor: 'rgba(0,0,0,0.5)',
708
+ iconButton: {
709
+ width: 44,
710
+ height: 44,
711
+ borderRadius: 22,
712
+ backgroundColor: 'rgba(50,50,50,0.8)',
701
713
  justifyContent: 'center',
702
714
  alignItems: 'center',
715
+ borderWidth: 1,
716
+ borderColor: 'rgba(255,255,255,0.3)',
717
+ },
718
+ iconContainer: {
719
+ justifyContent: 'center',
720
+ alignItems: 'center',
721
+ },
722
+ iconText: {
723
+ fontSize: 22,
703
724
  },
704
- closeButtonLabel: {
725
+ closeIconText: {
726
+ fontSize: 32,
727
+ fontWeight: '300',
705
728
  color: '#fff',
706
- fontSize: 28,
707
- lineHeight: 32,
708
- marginTop: -3,
729
+ },
730
+ flashButtonActive: {
731
+ backgroundColor: 'rgba(255,215,0,0.5)',
732
+ borderColor: '#FFD700',
709
733
  },
710
734
  instructions: {
711
735
  backgroundColor: 'rgba(0,0,0,0.55)',
@@ -718,32 +742,6 @@ const styles = StyleSheet.create({
718
742
  fontSize: 15,
719
743
  textAlign: 'center',
720
744
  },
721
- galleryButton: {
722
- width: 56,
723
- height: 56,
724
- borderRadius: 28,
725
- borderWidth: 3,
726
- borderColor: '#fff',
727
- justifyContent: 'center',
728
- alignItems: 'center',
729
- backgroundColor: 'rgba(255,255,255,0.1)',
730
- },
731
- galleryButtonText: {
732
- fontSize: 24,
733
- },
734
- flashButton: {
735
- width: 56,
736
- height: 56,
737
- borderRadius: 28,
738
- borderWidth: 3,
739
- borderColor: '#fff',
740
- justifyContent: 'center',
741
- alignItems: 'center',
742
- backgroundColor: 'rgba(255,255,255,0.1)',
743
- },
744
- flashButtonText: {
745
- fontSize: 24,
746
- },
747
745
  shutterButton: {
748
746
  width: 80,
749
747
  height: 80,
@@ -3,6 +3,7 @@
3
3
 
4
4
  @implementation DocumentScannerView {
5
5
  BOOL _hasSetupCamera;
6
+ BOOL _cameraStarted;
6
7
  IPDFRectangeType _lastDetectionType;
7
8
  }
8
9
 
@@ -12,6 +13,7 @@
12
13
  [self setEnableBorderDetection:YES];
13
14
  [self setDelegate: self];
14
15
  _hasSetupCamera = NO;
16
+ _cameraStarted = NO;
15
17
  self.manualOnly = NO; // Changed from YES to NO - allow manual capture to work
16
18
  self.detectionCountBeforeCapture = 99999; // High threshold to prevent auto-capture
17
19
  }
@@ -28,25 +30,24 @@
28
30
  [self setupCameraView];
29
31
  [self start];
30
32
  _hasSetupCamera = YES;
31
- } else if (_hasSetupCamera && self.window && !CGRectIsEmpty(self.bounds)) {
32
- // Restart camera if needed (defensive check)
33
- NSLog(@"[DocumentScanner] Layout update, ensuring camera is running");
34
- [self start];
33
+ _cameraStarted = YES;
35
34
  }
36
35
  }
37
36
 
38
37
  - (void)didMoveToWindow {
39
38
  [super didMoveToWindow];
40
- if (self.window && _hasSetupCamera) {
41
- // Restart camera when view is added back to window
39
+ if (self.window && _hasSetupCamera && !_cameraStarted) {
40
+ // Restart camera when view is added back to window (only if it was stopped)
42
41
  NSLog(@"[DocumentScanner] View added to window, restarting camera...");
43
42
  dispatch_async(dispatch_get_main_queue(), ^{
44
43
  [self start];
44
+ self->_cameraStarted = YES;
45
45
  });
46
- } else if (!self.window && _hasSetupCamera) {
46
+ } else if (!self.window && _hasSetupCamera && _cameraStarted) {
47
47
  // Stop camera when view is removed from window
48
48
  NSLog(@"[DocumentScanner] View removed from window, stopping camera");
49
49
  [self stop];
50
+ _cameraStarted = NO;
50
51
  }
51
52
  }
52
53