react-native-rectangle-doc-scanner 3.86.0 → 3.88.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.
@@ -109,6 +109,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
109
109
  const [isGalleryOpen, setIsGalleryOpen] = (0, react_1.useState)(false);
110
110
  const [rectangleDetected, setRectangleDetected] = (0, react_1.useState)(false);
111
111
  const [rectangleHint, setRectangleHint] = (0, react_1.useState)(false);
112
+ const [flashEnabled, setFlashEnabled] = (0, react_1.useState)(false);
112
113
  const resolvedGridColor = gridColor ?? overlayColor;
113
114
  const docScannerRef = (0, react_1.useRef)(null);
114
115
  const captureModeRef = (0, react_1.useRef)(null);
@@ -318,6 +319,9 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
318
319
  const handleClose = (0, react_1.useCallback)(() => {
319
320
  onClose?.();
320
321
  }, [onClose]);
322
+ const handleFlashToggle = (0, react_1.useCallback)(() => {
323
+ setFlashEnabled(prev => !prev);
324
+ }, []);
321
325
  const handleConfirm = (0, react_1.useCallback)(() => {
322
326
  if (croppedImageData) {
323
327
  onResult({
@@ -417,7 +421,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
417
421
  react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
418
422
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
419
423
  react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
420
- 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 },
424
+ 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 },
421
425
  react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
422
426
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
423
427
  react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
@@ -426,13 +430,17 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
426
430
  mergedStrings.captureHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.captureHint)),
427
431
  mergedStrings.manualHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.manualHint))))),
428
432
  react_1.default.createElement(react_native_1.View, { style: styles.shutterContainer, pointerEvents: "box-none" },
429
- enableGallery && (react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.galleryButton, processing && styles.buttonDisabled], onPress: handleGalleryPick, disabled: processing, accessibilityLabel: mergedStrings.galleryButton, accessibilityRole: "button" },
430
- react_1.default.createElement(react_native_1.Text, { style: styles.galleryButtonText }, "\uD83D\uDCC1"))),
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 ? '⚡' : '⚡️'))),
431
438
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.shutterButton, processing && styles.buttonDisabled], onPress: triggerManualCapture, disabled: processing, accessibilityLabel: mergedStrings.manualHint, accessibilityRole: "button" },
432
439
  react_1.default.createElement(react_native_1.View, { style: [
433
440
  styles.shutterInner,
434
441
  rectangleHint && { backgroundColor: overlayColor }
435
- ] })))))),
442
+ ] })),
443
+ react_1.default.createElement(react_native_1.View, { style: styles.rightButtonsPlaceholder }))))),
436
444
  processing && (react_1.default.createElement(react_native_1.View, { style: styles.processingOverlay },
437
445
  react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: overlayColor }),
438
446
  mergedStrings.processing && (react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing))))));
@@ -466,11 +474,20 @@ const styles = react_native_1.StyleSheet.create({
466
474
  left: 0,
467
475
  right: 0,
468
476
  flexDirection: 'row',
469
- justifyContent: 'center',
477
+ justifyContent: 'space-between',
470
478
  alignItems: 'center',
471
- gap: 24,
479
+ paddingHorizontal: 40,
472
480
  zIndex: 10,
473
481
  },
482
+ leftButtonsContainer: {
483
+ flexDirection: 'row',
484
+ gap: 12,
485
+ alignItems: 'center',
486
+ flex: 1,
487
+ },
488
+ rightButtonsPlaceholder: {
489
+ flex: 1,
490
+ },
474
491
  closeButton: {
475
492
  width: 40,
476
493
  height: 40,
@@ -497,9 +514,9 @@ const styles = react_native_1.StyleSheet.create({
497
514
  textAlign: 'center',
498
515
  },
499
516
  galleryButton: {
500
- width: 60,
501
- height: 60,
502
- borderRadius: 30,
517
+ width: 56,
518
+ height: 56,
519
+ borderRadius: 28,
503
520
  borderWidth: 3,
504
521
  borderColor: '#fff',
505
522
  justifyContent: 'center',
@@ -507,7 +524,20 @@ const styles = react_native_1.StyleSheet.create({
507
524
  backgroundColor: 'rgba(255,255,255,0.1)',
508
525
  },
509
526
  galleryButtonText: {
510
- fontSize: 28,
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,
511
541
  },
512
542
  shutterButton: {
513
543
  width: 80,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.86.0",
3
+ "version": "3.88.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -150,6 +150,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
150
150
  const [isGalleryOpen, setIsGalleryOpen] = useState(false);
151
151
  const [rectangleDetected, setRectangleDetected] = useState(false);
152
152
  const [rectangleHint, setRectangleHint] = useState(false);
153
+ const [flashEnabled, setFlashEnabled] = useState(false);
153
154
  const resolvedGridColor = gridColor ?? overlayColor;
154
155
  const docScannerRef = useRef<DocScannerHandle | null>(null);
155
156
  const captureModeRef = useRef<'grid' | 'no-grid' | null>(null);
@@ -426,6 +427,10 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
426
427
  onClose?.();
427
428
  }, [onClose]);
428
429
 
430
+ const handleFlashToggle = useCallback(() => {
431
+ setFlashEnabled(prev => !prev);
432
+ }, []);
433
+
429
434
  const handleConfirm = useCallback(() => {
430
435
  if (croppedImageData) {
431
436
  onResult({
@@ -569,6 +574,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
569
574
  onCapture={handleCapture}
570
575
  onRectangleDetect={handleRectangleDetect}
571
576
  showManualCaptureButton={false}
577
+ enableTorch={flashEnabled}
572
578
  >
573
579
  <View style={styles.overlayTop} pointerEvents="box-none">
574
580
  <TouchableOpacity
@@ -593,17 +599,28 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
593
599
  </View>
594
600
  )}
595
601
  <View style={styles.shutterContainer} pointerEvents="box-none">
596
- {enableGallery && (
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
+ )}
597
614
  <TouchableOpacity
598
- style={[styles.galleryButton, processing && styles.buttonDisabled]}
599
- onPress={handleGalleryPick}
615
+ style={[styles.flashButton, processing && styles.buttonDisabled]}
616
+ onPress={handleFlashToggle}
600
617
  disabled={processing}
601
- accessibilityLabel={mergedStrings.galleryButton}
618
+ accessibilityLabel="Toggle flash"
602
619
  accessibilityRole="button"
603
620
  >
604
- <Text style={styles.galleryButtonText}>📁</Text>
621
+ <Text style={styles.flashButtonText}>{flashEnabled ? '⚡' : '⚡️'}</Text>
605
622
  </TouchableOpacity>
606
- )}
623
+ </View>
607
624
  <TouchableOpacity
608
625
  style={[styles.shutterButton, processing && styles.buttonDisabled]}
609
626
  onPress={triggerManualCapture}
@@ -616,6 +633,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
616
633
  rectangleHint && { backgroundColor: overlayColor }
617
634
  ]} />
618
635
  </TouchableOpacity>
636
+ <View style={styles.rightButtonsPlaceholder} />
619
637
  </View>
620
638
  </DocScanner>
621
639
  </View>
@@ -661,11 +679,20 @@ const styles = StyleSheet.create({
661
679
  left: 0,
662
680
  right: 0,
663
681
  flexDirection: 'row',
664
- justifyContent: 'center',
682
+ justifyContent: 'space-between',
665
683
  alignItems: 'center',
666
- gap: 24,
684
+ paddingHorizontal: 40,
667
685
  zIndex: 10,
668
686
  },
687
+ leftButtonsContainer: {
688
+ flexDirection: 'row',
689
+ gap: 12,
690
+ alignItems: 'center',
691
+ flex: 1,
692
+ },
693
+ rightButtonsPlaceholder: {
694
+ flex: 1,
695
+ },
669
696
  closeButton: {
670
697
  width: 40,
671
698
  height: 40,
@@ -692,9 +719,9 @@ const styles = StyleSheet.create({
692
719
  textAlign: 'center',
693
720
  },
694
721
  galleryButton: {
695
- width: 60,
696
- height: 60,
697
- borderRadius: 30,
722
+ width: 56,
723
+ height: 56,
724
+ borderRadius: 28,
698
725
  borderWidth: 3,
699
726
  borderColor: '#fff',
700
727
  justifyContent: 'center',
@@ -702,7 +729,20 @@ const styles = StyleSheet.create({
702
729
  backgroundColor: 'rgba(255,255,255,0.1)',
703
730
  },
704
731
  galleryButtonText: {
705
- fontSize: 28,
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,
706
746
  },
707
747
  shutterButton: {
708
748
  width: 80,
@@ -29,11 +29,9 @@
29
29
  [self start];
30
30
  _hasSetupCamera = YES;
31
31
  } else if (_hasSetupCamera && self.window && !CGRectIsEmpty(self.bounds)) {
32
- // Check if camera session is running, restart if needed
33
- if (self.captureSession && !self.captureSession.isRunning) {
34
- NSLog(@"[DocumentScanner] Camera session not running, restarting...");
35
- [self start];
36
- }
32
+ // Restart camera if needed (defensive check)
33
+ NSLog(@"[DocumentScanner] Layout update, ensuring camera is running");
34
+ [self start];
37
35
  }
38
36
  }
39
37
 
@@ -41,12 +39,10 @@
41
39
  [super didMoveToWindow];
42
40
  if (self.window && _hasSetupCamera) {
43
41
  // Restart camera when view is added back to window
44
- if (self.captureSession && !self.captureSession.isRunning) {
45
- NSLog(@"[DocumentScanner] View added to window, restarting camera...");
46
- dispatch_async(dispatch_get_main_queue(), ^{
47
- [self start];
48
- });
49
- }
42
+ NSLog(@"[DocumentScanner] View added to window, restarting camera...");
43
+ dispatch_async(dispatch_get_main_queue(), ^{
44
+ [self start];
45
+ });
50
46
  } else if (!self.window && _hasSetupCamera) {
51
47
  // Stop camera when view is removed from window
52
48
  NSLog(@"[DocumentScanner] View removed from window, stopping camera");