react-native-rectangle-doc-scanner 3.36.0 → 3.37.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.
@@ -117,12 +117,26 @@ const CropEditor = ({ document, overlayColor = 'rgba(0,0,0,0.5)', overlayStrokeC
117
117
  };
118
118
  onCropChange?.(rect);
119
119
  }, [imageSize, onCropChange]);
120
- const imageUri = `file://${document.path}`;
120
+ // Ensure proper file URI format
121
+ const imageUri = document.path.startsWith('file://')
122
+ ? document.path
123
+ : `file://${document.path}`;
124
+ const initialRect = getInitialRectangle();
125
+ console.log('[CropEditor] Rendering with:', {
126
+ imageUri,
127
+ imageSize,
128
+ displaySize,
129
+ initialRect,
130
+ isLoading: isImageLoading,
131
+ hasError: !!loadError,
132
+ });
121
133
  return (react_1.default.createElement(react_native_1.View, { style: styles.container, onLayout: handleLayout }, loadError ? (react_1.default.createElement(react_native_1.View, { style: styles.errorContainer },
122
134
  react_1.default.createElement(react_native_1.Text, { style: styles.errorText }, "Failed to load image"),
123
135
  react_1.default.createElement(react_native_1.Text, { style: styles.errorPath }, imageUri))) : !imageSize || isImageLoading ? (react_1.default.createElement(react_native_1.View, { style: styles.loadingContainer },
124
136
  react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: handlerColor }),
125
- react_1.default.createElement(react_native_1.Text, { style: styles.loadingText }, "Loading image..."))) : (react_1.default.createElement(react_native_perspective_image_cropper_1.default, { height: displaySize.height, width: displaySize.width, image: imageUri, rectangleCoordinates: getInitialRectangle(), overlayColor: overlayColor, overlayStrokeColor: overlayStrokeColor, handlerColor: handlerColor, enablePanStrict: enablePanStrict, onDragEnd: handleDragEnd }))));
137
+ react_1.default.createElement(react_native_1.Text, { style: styles.loadingText }, "Loading image..."))) : (react_1.default.createElement(react_1.default.Fragment, null,
138
+ react_1.default.createElement(react_native_perspective_image_cropper_1.default, { height: displaySize.height, width: displaySize.width, image: imageUri, rectangleCoordinates: initialRect, overlayColor: overlayColor, overlayStrokeColor: overlayStrokeColor, handlerColor: handlerColor, enablePanStrict: enablePanStrict, onDragEnd: handleDragEnd }),
139
+ react_1.default.createElement(react_native_1.Image, { source: { uri: imageUri }, style: styles.debugImage, onLoad: () => console.log('[CropEditor] Debug image loaded'), onError: (e) => console.error('[CropEditor] Debug image error:', e.nativeEvent.error) })))));
126
140
  };
127
141
  exports.CropEditor = CropEditor;
128
142
  const styles = react_native_1.StyleSheet.create({
@@ -157,10 +171,14 @@ const styles = react_native_1.StyleSheet.create({
157
171
  fontSize: 12,
158
172
  textAlign: 'center',
159
173
  },
160
- hiddenImage: {
161
- width: 1,
162
- height: 1,
163
- opacity: 0,
174
+ debugImage: {
164
175
  position: 'absolute',
176
+ width: 100,
177
+ height: 100,
178
+ top: 10,
179
+ right: 10,
180
+ opacity: 0.5,
181
+ borderWidth: 2,
182
+ borderColor: 'red',
165
183
  },
166
184
  });
@@ -69,13 +69,13 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
69
69
  const processingCaptureRef = (0, react_1.useRef)(false);
70
70
  const cropInitializedRef = (0, react_1.useRef)(false);
71
71
  const mergedStrings = (0, react_1.useMemo)(() => ({
72
- captureHint: strings?.captureHint ?? 'Align the document within the frame.',
73
- manualHint: strings?.manualHint ?? 'Tap the button below to capture.',
74
- cancel: strings?.cancel ?? 'Cancel',
75
- confirm: strings?.confirm ?? 'Use photo',
76
- retake: strings?.retake ?? 'Retake',
77
- cropTitle: strings?.cropTitle ?? 'Adjust the corners',
78
- processing: strings?.processing ?? 'Processing…',
72
+ captureHint: strings?.captureHint ?? '',
73
+ manualHint: strings?.manualHint ?? '',
74
+ cancel: strings?.cancel ?? '',
75
+ confirm: strings?.confirm ?? '',
76
+ retake: strings?.retake ?? '',
77
+ cropTitle: strings?.cropTitle ?? '',
78
+ processing: strings?.processing ?? '',
79
79
  }), [strings]);
80
80
  (0, react_1.useEffect)(() => {
81
81
  if (!capturedDoc) {
@@ -315,24 +315,24 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
315
315
  return (react_1.default.createElement(react_native_1.View, { style: styles.container },
316
316
  screen === 'scanner' && (react_1.default.createElement(react_native_1.View, { style: styles.flex },
317
317
  react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: !manualCapture, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, showManualCaptureButton: false },
318
- react_1.default.createElement(react_native_1.View, { style: styles.overlay, pointerEvents: "box-none" },
318
+ react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
319
319
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
320
- react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7")),
321
- react_1.default.createElement(react_native_1.View, { style: styles.instructions, pointerEvents: "none" },
322
- react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.captureHint),
323
- react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.manualHint)),
320
+ react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
321
+ (mergedStrings.captureHint || mergedStrings.manualHint) && (react_1.default.createElement(react_native_1.View, { style: styles.instructionsContainer, pointerEvents: "none" },
322
+ react_1.default.createElement(react_native_1.View, { style: styles.instructions },
323
+ mergedStrings.captureHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.captureHint)),
324
+ mergedStrings.manualHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.manualHint))))),
325
+ react_1.default.createElement(react_native_1.View, { style: styles.shutterContainer, pointerEvents: "box-none" },
324
326
  react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.shutterButton, processing && styles.shutterButtonDisabled], onPress: triggerManualCapture, disabled: processing, accessibilityLabel: mergedStrings.manualHint, accessibilityRole: "button" },
325
327
  react_1.default.createElement(react_native_1.View, { style: styles.shutterInner })))))),
326
328
  screen === 'crop' && capturedDoc && (react_1.default.createElement(react_native_1.View, { style: styles.flex },
327
329
  react_1.default.createElement(CropEditor_1.CropEditor, { document: capturedDoc, overlayColor: "rgba(0,0,0,0.6)", overlayStrokeColor: overlayStrokeColor, handlerColor: handlerColor, onCropChange: handleCropChange }),
328
330
  react_1.default.createElement(react_native_1.View, { style: styles.cropFooter },
329
- react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.secondaryButton], onPress: handleRetake },
330
- react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.retake)),
331
- react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.primaryButton], onPress: handleConfirm },
332
- react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.confirm))))),
331
+ react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.secondaryButton], onPress: handleRetake }, mergedStrings.retake && react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.retake)),
332
+ react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.primaryButton], onPress: handleConfirm }, mergedStrings.confirm && react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.confirm))))),
333
333
  processing && (react_1.default.createElement(react_native_1.View, { style: styles.processingOverlay },
334
334
  react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: overlayStrokeColor }),
335
- react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing)))));
335
+ mergedStrings.processing && (react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing))))));
336
336
  };
337
337
  exports.FullDocScanner = FullDocScanner;
338
338
  const styles = react_native_1.StyleSheet.create({
@@ -343,12 +343,27 @@ const styles = react_native_1.StyleSheet.create({
343
343
  flex: {
344
344
  flex: 1,
345
345
  },
346
- overlay: {
347
- ...react_native_1.StyleSheet.absoluteFillObject,
348
- justifyContent: 'space-between',
349
- paddingTop: 48,
350
- paddingBottom: 64,
351
- paddingHorizontal: 24,
346
+ overlayTop: {
347
+ position: 'absolute',
348
+ top: 48,
349
+ right: 24,
350
+ zIndex: 10,
351
+ },
352
+ instructionsContainer: {
353
+ position: 'absolute',
354
+ top: '40%',
355
+ left: 0,
356
+ right: 0,
357
+ alignItems: 'center',
358
+ zIndex: 5,
359
+ },
360
+ shutterContainer: {
361
+ position: 'absolute',
362
+ bottom: 64,
363
+ left: 0,
364
+ right: 0,
365
+ alignItems: 'center',
366
+ zIndex: 10,
352
367
  },
353
368
  closeButton: {
354
369
  width: 40,
@@ -357,7 +372,6 @@ const styles = react_native_1.StyleSheet.create({
357
372
  backgroundColor: 'rgba(0,0,0,0.5)',
358
373
  justifyContent: 'center',
359
374
  alignItems: 'center',
360
- alignSelf: 'flex-end',
361
375
  },
362
376
  closeButtonLabel: {
363
377
  color: '#fff',
@@ -366,7 +380,6 @@ const styles = react_native_1.StyleSheet.create({
366
380
  marginTop: -3,
367
381
  },
368
382
  instructions: {
369
- alignSelf: 'center',
370
383
  backgroundColor: 'rgba(0,0,0,0.55)',
371
384
  borderRadius: 16,
372
385
  paddingHorizontal: 20,
@@ -378,7 +391,6 @@ const styles = react_native_1.StyleSheet.create({
378
391
  textAlign: 'center',
379
392
  },
380
393
  shutterButton: {
381
- alignSelf: 'center',
382
394
  width: 80,
383
395
  height: 80,
384
396
  borderRadius: 40,
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.36.0",
3
+ "version": "3.37.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/danchew90/react-native-rectangle-doc-scanner.git"
10
+ "url": "git+https://github.com/danchew90/react-native-rectangle-doc-scanner.git"
11
11
  },
12
12
  "homepage": "https://github.com/danchew90/react-native-rectangle-doc-scanner",
13
13
  "bugs": {
@@ -120,7 +120,21 @@ export const CropEditor: React.FC<CropEditorProps> = ({
120
120
  onCropChange?.(rect);
121
121
  }, [imageSize, onCropChange]);
122
122
 
123
- const imageUri = `file://${document.path}`;
123
+ // Ensure proper file URI format
124
+ const imageUri = document.path.startsWith('file://')
125
+ ? document.path
126
+ : `file://${document.path}`;
127
+
128
+ const initialRect = getInitialRectangle();
129
+
130
+ console.log('[CropEditor] Rendering with:', {
131
+ imageUri,
132
+ imageSize,
133
+ displaySize,
134
+ initialRect,
135
+ isLoading: isImageLoading,
136
+ hasError: !!loadError,
137
+ });
124
138
 
125
139
  return (
126
140
  <View style={styles.container} onLayout={handleLayout}>
@@ -136,17 +150,26 @@ export const CropEditor: React.FC<CropEditorProps> = ({
136
150
  <Text style={styles.loadingText}>Loading image...</Text>
137
151
  </View>
138
152
  ) : (
139
- <CustomImageCropper
140
- height={displaySize.height}
141
- width={displaySize.width}
142
- image={imageUri}
143
- rectangleCoordinates={getInitialRectangle()}
144
- overlayColor={overlayColor}
145
- overlayStrokeColor={overlayStrokeColor}
146
- handlerColor={handlerColor}
147
- enablePanStrict={enablePanStrict}
148
- onDragEnd={handleDragEnd}
149
- />
153
+ <>
154
+ <CustomImageCropper
155
+ height={displaySize.height}
156
+ width={displaySize.width}
157
+ image={imageUri}
158
+ rectangleCoordinates={initialRect}
159
+ overlayColor={overlayColor}
160
+ overlayStrokeColor={overlayStrokeColor}
161
+ handlerColor={handlerColor}
162
+ enablePanStrict={enablePanStrict}
163
+ onDragEnd={handleDragEnd}
164
+ />
165
+ {/* Debug: Show image in background to verify it loads */}
166
+ <Image
167
+ source={{ uri: imageUri }}
168
+ style={styles.debugImage}
169
+ onLoad={() => console.log('[CropEditor] Debug image loaded')}
170
+ onError={(e) => console.error('[CropEditor] Debug image error:', e.nativeEvent.error)}
171
+ />
172
+ </>
150
173
  )}
151
174
  </View>
152
175
  );
@@ -184,10 +207,14 @@ const styles = StyleSheet.create({
184
207
  fontSize: 12,
185
208
  textAlign: 'center',
186
209
  },
187
- hiddenImage: {
188
- width: 1,
189
- height: 1,
190
- opacity: 0,
210
+ debugImage: {
191
211
  position: 'absolute',
212
+ width: 100,
213
+ height: 100,
214
+ top: 10,
215
+ right: 10,
216
+ opacity: 0.5,
217
+ borderWidth: 2,
218
+ borderColor: 'red',
192
219
  },
193
220
  });
@@ -122,15 +122,15 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
122
122
  const processingCaptureRef = useRef(false);
123
123
  const cropInitializedRef = useRef(false);
124
124
 
125
- const mergedStrings = useMemo<Required<FullDocScannerStrings>>(
125
+ const mergedStrings = useMemo(
126
126
  () => ({
127
- captureHint: strings?.captureHint ?? 'Align the document within the frame.',
128
- manualHint: strings?.manualHint ?? 'Tap the button below to capture.',
129
- cancel: strings?.cancel ?? 'Cancel',
130
- confirm: strings?.confirm ?? 'Use photo',
131
- retake: strings?.retake ?? 'Retake',
132
- cropTitle: strings?.cropTitle ?? 'Adjust the corners',
133
- processing: strings?.processing ?? 'Processing…',
127
+ captureHint: strings?.captureHint ?? '',
128
+ manualHint: strings?.manualHint ?? '',
129
+ cancel: strings?.cancel ?? '',
130
+ confirm: strings?.confirm ?? '',
131
+ retake: strings?.retake ?? '',
132
+ cropTitle: strings?.cropTitle ?? '',
133
+ processing: strings?.processing ?? '',
134
134
  }),
135
135
  [strings],
136
136
  );
@@ -479,7 +479,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
479
479
  onCapture={handleCapture}
480
480
  showManualCaptureButton={false}
481
481
  >
482
- <View style={styles.overlay} pointerEvents="box-none">
482
+ <View style={styles.overlayTop} pointerEvents="box-none">
483
483
  <TouchableOpacity
484
484
  style={styles.closeButton}
485
485
  onPress={handleClose}
@@ -488,10 +488,20 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
488
488
  >
489
489
  <Text style={styles.closeButtonLabel}>×</Text>
490
490
  </TouchableOpacity>
491
- <View style={styles.instructions} pointerEvents="none">
492
- <Text style={styles.captureText}>{mergedStrings.captureHint}</Text>
493
- <Text style={styles.captureText}>{mergedStrings.manualHint}</Text>
491
+ </View>
492
+ {(mergedStrings.captureHint || mergedStrings.manualHint) && (
493
+ <View style={styles.instructionsContainer} pointerEvents="none">
494
+ <View style={styles.instructions}>
495
+ {mergedStrings.captureHint && (
496
+ <Text style={styles.captureText}>{mergedStrings.captureHint}</Text>
497
+ )}
498
+ {mergedStrings.manualHint && (
499
+ <Text style={styles.captureText}>{mergedStrings.manualHint}</Text>
500
+ )}
501
+ </View>
494
502
  </View>
503
+ )}
504
+ <View style={styles.shutterContainer} pointerEvents="box-none">
495
505
  <TouchableOpacity
496
506
  style={[styles.shutterButton, processing && styles.shutterButtonDisabled]}
497
507
  onPress={triggerManualCapture}
@@ -517,10 +527,10 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
517
527
  />
518
528
  <View style={styles.cropFooter}>
519
529
  <TouchableOpacity style={[styles.actionButton, styles.secondaryButton]} onPress={handleRetake}>
520
- <Text style={styles.buttonText}>{mergedStrings.retake}</Text>
530
+ {mergedStrings.retake && <Text style={styles.buttonText}>{mergedStrings.retake}</Text>}
521
531
  </TouchableOpacity>
522
532
  <TouchableOpacity style={[styles.actionButton, styles.primaryButton]} onPress={handleConfirm}>
523
- <Text style={styles.buttonText}>{mergedStrings.confirm}</Text>
533
+ {mergedStrings.confirm && <Text style={styles.buttonText}>{mergedStrings.confirm}</Text>}
524
534
  </TouchableOpacity>
525
535
  </View>
526
536
  </View>
@@ -529,7 +539,9 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
529
539
  {processing && (
530
540
  <View style={styles.processingOverlay}>
531
541
  <ActivityIndicator size="large" color={overlayStrokeColor} />
532
- <Text style={styles.processingText}>{mergedStrings.processing}</Text>
542
+ {mergedStrings.processing && (
543
+ <Text style={styles.processingText}>{mergedStrings.processing}</Text>
544
+ )}
533
545
  </View>
534
546
  )}
535
547
  </View>
@@ -544,12 +556,27 @@ const styles = StyleSheet.create({
544
556
  flex: {
545
557
  flex: 1,
546
558
  },
547
- overlay: {
548
- ...StyleSheet.absoluteFillObject,
549
- justifyContent: 'space-between',
550
- paddingTop: 48,
551
- paddingBottom: 64,
552
- paddingHorizontal: 24,
559
+ overlayTop: {
560
+ position: 'absolute',
561
+ top: 48,
562
+ right: 24,
563
+ zIndex: 10,
564
+ },
565
+ instructionsContainer: {
566
+ position: 'absolute',
567
+ top: '40%',
568
+ left: 0,
569
+ right: 0,
570
+ alignItems: 'center',
571
+ zIndex: 5,
572
+ },
573
+ shutterContainer: {
574
+ position: 'absolute',
575
+ bottom: 64,
576
+ left: 0,
577
+ right: 0,
578
+ alignItems: 'center',
579
+ zIndex: 10,
553
580
  },
554
581
  closeButton: {
555
582
  width: 40,
@@ -558,7 +585,6 @@ const styles = StyleSheet.create({
558
585
  backgroundColor: 'rgba(0,0,0,0.5)',
559
586
  justifyContent: 'center',
560
587
  alignItems: 'center',
561
- alignSelf: 'flex-end',
562
588
  },
563
589
  closeButtonLabel: {
564
590
  color: '#fff',
@@ -567,7 +593,6 @@ const styles = StyleSheet.create({
567
593
  marginTop: -3,
568
594
  },
569
595
  instructions: {
570
- alignSelf: 'center',
571
596
  backgroundColor: 'rgba(0,0,0,0.55)',
572
597
  borderRadius: 16,
573
598
  paddingHorizontal: 20,
@@ -579,7 +604,6 @@ const styles = StyleSheet.create({
579
604
  textAlign: 'center',
580
605
  },
581
606
  shutterButton: {
582
- alignSelf: 'center',
583
607
  width: 80,
584
608
  height: 80,
585
609
  borderRadius: 40,