@cleanuidev/react-native-scanner 1.0.0-beta.2 → 1.0.0-beta.3

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/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  # 📱 React Native Scanner
4
4
 
5
- **A powerful, native barcode and QR code scanner for React Native**
5
+ **A powerful, native barcode and QR code scanner for React Native with configurable target area scanning**
6
6
 
7
- ![React Native Barcode Scanner Demo - QR Code and Barcode Scanning with Focus Area](./preview.gif)
7
+ ![React Native Barcode Scanner Demo - QR Code and Barcode Scanning with Target Area](./preview.gif)
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/@cleanuidev/react-native-scanner?label=beta&color=blue)](https://www.npmjs.com/package/@cleanuidev/react-native-scanner)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -26,10 +26,10 @@
26
26
  | Feature | Description |
27
27
  |:------:|:-----------|
28
28
  | 🚀 **Native Performance** | Built with CameraX & ML Kit (Android) and AVFoundation & Vision (iOS) for optimal performance |
29
- | 🎯 **Focus Area** | Configurable focus area with optional overlay for precise scanning |
29
+ | 🎯 **Target Area Scanning** | Scan barcodes within configurable target areas for precise detection |
30
30
  | 🔦 **Torch Control** | Built-in flashlight/torch control |
31
31
  | 📊 **Multiple Formats** | Support for QR codes, Code128, Code39, EAN, UPC, and more |
32
- | 🎨 **Customizable** | Configurable focus area colors, barcode frame visualization, and scanning behavior |
32
+ | 🎨 **Customizable** | Configurable target area colors, barcode frame visualization, and scanning behavior |
33
33
  | 📱 **Cross Platform** | Android & iOS support (new Fabric architecture) |
34
34
 
35
35
  </div>
@@ -129,7 +129,7 @@ const styles = StyleSheet.create({
129
129
  });
130
130
  ```
131
131
 
132
- ### Scanner with Focus Area
132
+ ### Scanner with Target Area
133
133
 
134
134
  ```tsx
135
135
  import React, { useState } from 'react';
@@ -139,12 +139,12 @@ import ScannerView, { BarcodeFormat } from '@cleanuidev/react-native-scanner';
139
139
  export default function FocusAreaScanner() {
140
140
  const [torchEnabled, setTorchEnabled] = useState(false);
141
141
 
142
- // Focus area configuration
142
+ // Target area configuration
143
143
  const focusAreaConfig = {
144
- enabled: true, // Only scan barcodes within the focus area
145
- showOverlay: true, // Show the focus area overlay
146
- size: 300, // Size of the focus area (square)
147
- color: '#00FF00', // Color of the focus area border
144
+ enabled: true, // Only scan barcodes within the target area
145
+ showOverlay: true, // Show overlay outside the target area
146
+ size: 300, // Size of the target area (square)
147
+ color: '#00FF00', // Color of the target area border
148
148
  };
149
149
 
150
150
  // Barcode frames configuration
@@ -198,7 +198,7 @@ export default function FocusAreaScanner() {
198
198
  | Prop | Type | Default | Description |
199
199
  |------|------|---------|-------------|
200
200
  | `barcodeTypes` | `BarcodeFormat[]` | `[BarcodeFormat.QR_CODE]` | Array of barcode formats to scan |
201
- | `focusArea` | `FocusAreaConfig` | - | Focus area configuration |
201
+ | `focusArea` | `FocusAreaConfig` | - | Target area configuration for precise scanning |
202
202
  | `barcodeFrames` | `BarcodeFramesConfig` | - | Barcode frame visualization configuration |
203
203
  | `torch` | `boolean` | `false` | Enable/disable torch/flashlight |
204
204
  | `zoom` | `number` | `1.0` | Camera zoom level |
@@ -213,10 +213,10 @@ export default function FocusAreaScanner() {
213
213
 
214
214
  ```tsx
215
215
  type FocusAreaConfig = {
216
- enabled?: boolean; // Whether to restrict scanning to focus area only
217
- size?: FrameSize; // Size of the focus area
218
- color?: string; // Color of focus area border
219
- showOverlay?: boolean; // Whether to draw the focus area overlay
216
+ enabled?: boolean; // Whether to restrict scanning to target area only
217
+ size?: FrameSize; // Size of the target area
218
+ color?: string; // Color of target area border
219
+ showOverlay?: boolean; // Whether to draw overlay outside the target area
220
220
  };
221
221
  ```
222
222
 
@@ -226,7 +226,7 @@ type FocusAreaConfig = {
226
226
  type BarcodeFramesConfig = {
227
227
  enabled?: boolean; // Whether to draw frames around detected barcodes
228
228
  color?: string; // Color of barcode frames
229
- onlyInFocusArea?: boolean; // Only show frames for barcodes in focus area
229
+ onlyInFocusArea?: boolean; // Only show frames for barcodes in target area
230
230
  };
231
231
  ```
232
232
 
@@ -311,16 +311,16 @@ BarcodeFormat.ITF // ITF (Interleaved 2 of 5)
311
311
  }
312
312
  ```
313
313
 
314
- ## Focus Area Configuration
314
+ ## Target Area Configuration
315
315
 
316
- The focus area feature provides precise control over where barcodes are scanned:
316
+ The target area feature provides precise control over where barcodes are scanned:
317
317
 
318
- ### Basic Focus Area
318
+ ### Basic Target Area
319
319
 
320
320
  ```tsx
321
321
  <ScannerView
322
322
  focusArea={{
323
- showOverlay: true, // Show visual overlay
323
+ showOverlay: true, // Show overlay outside the target area
324
324
  size: 300, // 300x300 pixel square
325
325
  color: '#00FF00', // Green border
326
326
  }}
@@ -328,33 +328,64 @@ The focus area feature provides precise control over where barcodes are scanned:
328
328
  />
329
329
  ```
330
330
 
331
- ### Focus Area with Restricted Scanning
331
+ ### Target Area with Restricted Scanning
332
332
 
333
333
  ```tsx
334
334
  <ScannerView
335
335
  focusArea={{
336
- enabled: true, // Only scan within focus area
337
- showOverlay: true, // Show visual overlay
336
+ enabled: true, // Only scan within target area
337
+ showOverlay: true, // Show overlay outside the target area
338
338
  size: 300, // 300x300 pixel square
339
339
  color: '#00FF00', // Green border
340
340
  }}
341
- // Only scans within the focus area
341
+ // Only scans within the target area
342
342
  />
343
343
  ```
344
344
 
345
- ### Rectangular Focus Area
345
+ ### Rectangular Target Area
346
346
 
347
347
  ```tsx
348
348
  <ScannerView
349
349
  focusArea={{
350
350
  enabled: true,
351
351
  showOverlay: true,
352
- size: { width: 300, height: 200 }, // Rectangular focus area
352
+ size: { width: 300, height: 200 }, // Rectangular target area
353
353
  color: '#00FF00',
354
354
  }}
355
355
  />
356
356
  ```
357
357
 
358
+ ### Positioning Target Area with Coordinates
359
+
360
+ You can position the target area anywhere on the screen using percentage-based coordinates (0-100):
361
+
362
+ ```tsx
363
+ <ScannerView
364
+ focusArea={{
365
+ enabled: true,
366
+ showOverlay: true,
367
+ size: 300,
368
+ position: { x: 50, y: 50 }, // Center position (default)
369
+ color: '#00FF00',
370
+ }}
371
+ />
372
+ ```
373
+
374
+ **Example: Position target area at top center**
375
+
376
+ ```tsx
377
+ <ScannerView
378
+ focusArea={{
379
+ enabled: true,
380
+ showOverlay: true,
381
+ size: 250,
382
+ position: { x: 50, y: 25 }, // Top center
383
+ color: '#00FF00',
384
+ }}
385
+ onBarcodeScanned={handleBarcodeScanned}
386
+ />
387
+ ```
388
+
358
389
  ## Barcode Frame Visualization
359
390
 
360
391
  The scanner can display visual frames around detected barcodes to help users see what's being scanned:
@@ -371,7 +402,7 @@ The scanner can display visual frames around detected barcodes to help users see
371
402
  />
372
403
  ```
373
404
 
374
- ### Show Frames Only in Focus Area
405
+ ### Show Frames Only in Target Area
375
406
 
376
407
  ```tsx
377
408
  <ScannerView
@@ -383,7 +414,7 @@ The scanner can display visual frames around detected barcodes to help users see
383
414
  barcodeFrames={{
384
415
  enabled: true,
385
416
  color: '#FF0000',
386
- onlyInFocusArea: true, // Only show frames for barcodes in focus area
417
+ onlyInFocusArea: true, // Only show frames for barcodes in target area
387
418
  }}
388
419
  />
389
420
  ```
@@ -567,6 +598,19 @@ For bug reports, feature requests, and general questions:
567
598
  - 📝 [Open an issue](https://github.com/cleanui-dev/react-native-scanner/issues) on GitHub
568
599
  - 💬 Use GitHub Discussions for questions and community help
569
600
 
601
+ ### Support the Maintainer
602
+
603
+ If you find this library useful, consider supporting the maintainer/developer directly through donations:
604
+
605
+ - 💰 [Donate via PayPal](https://paypal.me/rahulgwebdev) - Support the maintainer directly and help keep this project maintained and improved
606
+ - ⭐ Star the repository - Show your appreciation and help others discover this library
607
+
608
+ **Your donations help:**
609
+ - 🐛 Maintain and fix bugs
610
+ - ✨ Add new features and improvements
611
+ - 📚 Keep documentation up to date
612
+ - ⚡ Ensure long-term sustainability of the project
613
+
570
614
  ### Commercial Support & Consulting
571
615
 
572
616
  Need professional help with implementation, custom development, or enterprise support?
@@ -222,6 +222,7 @@ class ScannerView : FrameLayout {
222
222
 
223
223
  if (!hasCameraPermission()) {
224
224
  Log.e(TAG, "Camera permission not granted")
225
+ emitOnScannerError("Camera permission not granted", "CAMERA_PERMISSION_DENIED")
225
226
  return
226
227
  }
227
228
 
@@ -331,8 +332,16 @@ class ScannerView : FrameLayout {
331
332
  // Set up auto-focus on frame center (if focus area is enabled)
332
333
  setupAutoFocusOnFrame()
333
334
 
335
+ // Emit onLoad event after camera is successfully started
336
+ emitOnLoadEvent(success = true)
337
+
334
338
  } catch (exc: Exception) {
335
339
  Log.e(TAG, "Use case binding failed", exc)
340
+ // Emit onScannerError event for camera initialization failure
341
+ emitOnScannerError(
342
+ error = exc.message ?: "Camera binding failed",
343
+ code = "CAMERA_INITIALIZATION_FAILED"
344
+ )
336
345
  }
337
346
  }
338
347
 
@@ -450,12 +459,14 @@ class ScannerView : FrameLayout {
450
459
  // Debounce: Prevent rapid duplicate emissions
451
460
  // If we've emitted recently (within debounce interval), skip this emission
452
461
  // This prevents multiple alerts when pauseScanning is set but detection callbacks are still in flight
462
+ Log.d(TAG, "📊 Debounce check: interval=${barcodeEmissionDebounceInterval}ms, timeSinceLast=${timeSinceLastEmission}ms")
453
463
  if (timeSinceLastEmission < barcodeEmissionDebounceInterval) {
454
- Log.d(TAG, "⏭️ Skipping barcode emission (debounced, last emission was ${timeSinceLastEmission}ms ago)")
464
+ Log.d(TAG, "⏭️ Skipping barcode emission (debounced, last emission was ${timeSinceLastEmission}ms ago, interval=${barcodeEmissionDebounceInterval}ms)")
455
465
  return@addOnSuccessListener
456
466
  }
457
467
 
458
468
  lastBarcodeEmissionTime = currentTime
469
+ Log.d(TAG, "✅ Emitting barcode (interval=${barcodeEmissionDebounceInterval}ms, timeSinceLast=${timeSinceLastEmission}ms)")
459
470
 
460
471
  // Create array of barcode events
461
472
  val barcodeEvents = Arguments.createArray()
@@ -502,6 +513,11 @@ class ScannerView : FrameLayout {
502
513
  }
503
514
  }
504
515
  .addOnFailureListener { e ->
516
+ // Emit onScannerError event for barcode detection failure
517
+ emitOnScannerError(
518
+ error = e.message ?: "Barcode detection failed",
519
+ code = "BARCODE_DETECTION_FAILED"
520
+ )
505
521
  Log.e(TAG, "Barcode scanning failed", e)
506
522
  }
507
523
  .addOnCompleteListener {
@@ -613,8 +629,48 @@ class ScannerView : FrameLayout {
613
629
 
614
630
  fun setBarcodeEmissionInterval(intervalSeconds: Double) {
615
631
  // Convert seconds to milliseconds, ensure non-negative
632
+ val previousInterval = barcodeEmissionDebounceInterval
633
+ Log.d(TAG, "📊 [ScannerView] setBarcodeEmissionInterval called with: ${intervalSeconds}s")
616
634
  barcodeEmissionDebounceInterval = max(0, (intervalSeconds * 1000).toLong())
617
- Log.d(TAG, "Barcode emission interval set to: ${barcodeEmissionDebounceInterval}ms")
635
+ Log.d(TAG, "📊 ScannerView.setBarcodeEmissionInterval: ${intervalSeconds}s -> ${barcodeEmissionDebounceInterval}ms (was ${previousInterval}ms)")
636
+
637
+ if (barcodeEmissionDebounceInterval == 0L) {
638
+ Log.d(TAG, "📊 ⚠️ Debouncing DISABLED (interval = 0ms)")
639
+ } else {
640
+ Log.d(TAG, "📊 ✅ Debouncing ENABLED (interval = ${barcodeEmissionDebounceInterval}ms)")
641
+ }
642
+ }
643
+
644
+ private fun emitOnLoadEvent(success: Boolean, error: String? = null) {
645
+ val ctx = reactContext
646
+ if (ctx is ThemedReactContext) {
647
+ ctx.runOnUiQueueThread {
648
+ val eventData = Arguments.createMap().apply {
649
+ putBoolean("success", success)
650
+ if (error != null) {
651
+ putString("error", error)
652
+ }
653
+ }
654
+ ctx.getJSModule(RCTEventEmitter::class.java)
655
+ .receiveEvent(this@ScannerView.id, "onLoad", eventData)
656
+ Log.d(TAG, "✅ onLoad event emitted: success=$success, error=$error")
657
+ }
658
+ }
659
+ }
660
+
661
+ private fun emitOnScannerError(error: String, code: String) {
662
+ val ctx = reactContext
663
+ if (ctx is ThemedReactContext) {
664
+ ctx.runOnUiQueueThread {
665
+ val eventData = Arguments.createMap().apply {
666
+ putString("error", error)
667
+ putString("code", code)
668
+ }
669
+ ctx.getJSModule(RCTEventEmitter::class.java)
670
+ .receiveEvent(this@ScannerView.id, "onScannerError", eventData)
671
+ Log.d(TAG, "✅ onScannerError event emitted: code=$code, error=$error")
672
+ }
673
+ }
618
674
  }
619
675
 
620
676
  fun setBarcodeScanStrategy(strategy: String) {
@@ -6,12 +6,20 @@ import com.facebook.react.bridge.*
6
6
  import com.facebook.react.module.annotations.ReactModule
7
7
  import com.facebook.react.uimanager.SimpleViewManager
8
8
  import com.facebook.react.uimanager.ThemedReactContext
9
+ import com.facebook.react.uimanager.ViewManagerDelegate
9
10
  import com.facebook.react.uimanager.annotations.ReactProp
10
11
  import com.facebook.react.uimanager.events.RCTModernEventEmitter
12
+ import com.facebook.react.viewmanagers.ScannerViewManagerInterface
13
+ import com.facebook.react.viewmanagers.ScannerViewManagerDelegate
11
14
 
12
15
  @ReactModule(name = ScannerViewManager.NAME)
13
- class ScannerViewManager : SimpleViewManager<ScannerView>() {
16
+ class ScannerViewManager : SimpleViewManager<ScannerView>(),
17
+ ScannerViewManagerInterface<ScannerView> {
18
+ private val mDelegate: ViewManagerDelegate<ScannerView> = ScannerViewManagerDelegate(this)
14
19
 
20
+ override fun getDelegate(): ViewManagerDelegate<ScannerView> {
21
+ return mDelegate
22
+ }
15
23
  override fun getName(): String {
16
24
  return NAME
17
25
  }
@@ -22,7 +30,7 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
22
30
 
23
31
  // Barcode configuration
24
32
  @ReactProp(name = "barcodeTypes")
25
- fun setBarcodeTypes(view: ScannerView?, types: ReadableArray?) {
33
+ override fun setBarcodeTypes(view: ScannerView?, types: ReadableArray?) {
26
34
  if (types != null) {
27
35
  val typeList = mutableListOf<String>()
28
36
  for (i in 0 until types.size()) {
@@ -36,33 +44,33 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
36
44
 
37
45
  // Focus area configuration
38
46
  @ReactProp(name = "focusArea")
39
- fun setFocusArea(view: ScannerView?, focusArea: ReadableMap?) {
47
+ override fun setFocusArea(view: ScannerView?, focusArea: ReadableMap?) {
40
48
  if (focusArea != null) {
41
- val enabled = focusArea.getBoolean("enabled") ?: false
42
- val showOverlay = focusArea.getBoolean("showOverlay") ?: false
49
+ val enabled = focusArea.getBoolean("enabled")
50
+ val showOverlay = focusArea.getBoolean("showOverlay")
43
51
  val borderColor = focusArea.getString("borderColor")
44
52
  val tintColor = focusArea.getString("tintColor")
45
53
  val size = focusArea.getDynamic("size")
46
54
  val position = focusArea.getMap("position")
47
-
55
+
48
56
  // Set focus area properties
49
57
  view?.setFocusAreaEnabled(enabled)
50
58
  view?.setEnableFrame(showOverlay)
51
-
59
+
52
60
  if (borderColor != null) {
53
61
  view?.setBorderColor(borderColor)
54
62
  }
55
-
63
+
56
64
  if (tintColor != null) {
57
65
  view?.setTintColor(tintColor)
58
66
  }
59
-
67
+
60
68
  if (position != null) {
61
69
  val x = position.getDouble("x").toFloat()
62
70
  val y = position.getDouble("y").toFloat()
63
71
  view?.setPosition(x, y)
64
72
  }
65
-
73
+
66
74
  if (size != null) {
67
75
  val frameSize: FrameSize = when {
68
76
  size.type == ReadableType.Number -> FrameSize.Square(size.asInt())
@@ -76,40 +84,40 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
76
84
  }
77
85
  view?.setFrameSize(frameSize)
78
86
  }
79
-
87
+
80
88
  Log.d("ScannerViewManager", "Focus area configured: enabled=$enabled, showOverlay=$showOverlay, borderColor=$borderColor, tintColor=$tintColor, position=$position")
81
89
  }
82
90
  }
83
91
 
84
92
  // Barcode frames configuration
85
93
  @ReactProp(name = "barcodeFrames")
86
- fun setBarcodeFrames(view: ScannerView?, barcodeFrames: ReadableMap?) {
94
+ override fun setBarcodeFrames(view: ScannerView?, barcodeFrames: ReadableMap?) {
87
95
  if (barcodeFrames != null) {
88
96
  val enabled = barcodeFrames.getBoolean("enabled") ?: false
89
97
  val color = barcodeFrames.getString("color")
90
98
  val onlyInFocusArea = barcodeFrames.getBoolean("onlyInFocusArea") ?: false
91
-
99
+
92
100
  // Set barcode frames properties
93
101
  view?.setBarcodeFramesEnabled(enabled)
94
102
  view?.setShowBarcodeFramesOnlyInFrame(onlyInFocusArea)
95
-
103
+
96
104
  if (color != null) {
97
105
  view?.setBarcodeFramesColor(color)
98
106
  }
99
-
107
+
100
108
  Log.d("ScannerViewManager", "Barcode frames configured: enabled=$enabled, onlyInFocusArea=$onlyInFocusArea, color=$color")
101
109
  }
102
110
  }
103
111
 
104
112
  // Torch control
105
113
  @ReactProp(name = "torch")
106
- fun setTorch(view: ScannerView?, enabled: Boolean?) {
107
- view?.setTorch(enabled ?: false)
114
+ override fun setTorch(view: ScannerView, value: Boolean) {
115
+ view.setTorch(value)
108
116
  }
109
117
 
110
118
  // Event handlers
111
119
  @ReactProp(name = "onBarcodeScanned")
112
- fun setOnBarcodeScanned(view: ScannerView?, onBarcodeScanned: Boolean?) {
120
+ fun setOnBarcodeScanned(view: ScannerView?, onBarcodeScanned: Boolean?) {
113
121
  // This prop is used to register the event handler
114
122
  // The actual event emission happens in ScannerView.processImage()
115
123
  Log.d("ScannerViewManager", "onBarcodeScanned event handler registered")
@@ -128,33 +136,49 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
128
136
  }
129
137
 
130
138
  @ReactProp(name = "zoom")
131
- fun setZoom(view: ScannerView?, zoom: Double) {
139
+ override fun setZoom(view: ScannerView?, zoom: Double) {
132
140
  view?.setZoom(zoom.toFloat())
133
141
  }
134
142
 
135
143
  @ReactProp(name = "pauseScanning")
136
- fun setPauseScanning(view: ScannerView?, pause: Boolean?) {
137
- if (pause == true) {
138
- view?.pauseScanning()
144
+ override fun setPauseScanning(view: ScannerView, value: Boolean) {
145
+ if (value) {
146
+ view.pauseScanning()
139
147
  } else {
140
- view?.resumeScanning()
148
+ view.resumeScanning()
141
149
  }
142
150
  }
143
151
 
144
152
  @ReactProp(name = "barcodeScanStrategy")
145
- fun setBarcodeScanStrategy(view: ScannerView?, strategy: String?) {
153
+ override fun setBarcodeScanStrategy(view: ScannerView?, strategy: String?) {
146
154
  view?.setBarcodeScanStrategy(strategy ?: "ALL")
147
155
  }
148
156
 
149
157
  @ReactProp(name = "keepScreenOn")
150
- fun setKeepScreenOn(view: ScannerView?, keepOn: Boolean?) {
151
- view?.setKeepScreenOnEnabled(keepOn ?: true)
158
+ override fun setKeepScreenOn(view: ScannerView, value: Boolean) {
159
+ view.setKeepScreenOnEnabled(value)
152
160
  }
153
161
 
154
162
  @ReactProp(name = "barcodeEmissionInterval")
155
- fun setBarcodeEmissionInterval(view: ScannerView?, interval: Double) {
156
- // Use 0.5 as default if interval is 0 or negative (React Native may pass 0 for undefined)
157
- val actualInterval = if (interval > 0) interval else 0.5
163
+ override fun setBarcodeEmissionInterval(view: ScannerView?, interval: Double) {
164
+ Log.d("ScannerViewManager", "📊 [@ReactProp] barcodeEmissionInterval received: $interval")
165
+
166
+ // WithDefault<Double, 0.5> in TypeScript means codegen handles the default automatically
167
+ // If negative, clamp to 0 (minimum value)
168
+ // If 0, disable debouncing
169
+ // Otherwise, use the provided value (0 or positive)
170
+ val actualInterval = if (interval < 0) {
171
+ Log.d("ScannerViewManager", "📊 Clamping negative interval ($interval) to 0.0 (minimum)")
172
+ 0.0 // Negative values clamped to 0 (minimum)
173
+ } else {
174
+ if (interval == 0.0) {
175
+ Log.d("ScannerViewManager", "📊 Using interval: ${interval}s (explicitly set to 0, will disable debouncing)")
176
+ } else {
177
+ Log.d("ScannerViewManager", "📊 Using interval: ${interval}s")
178
+ }
179
+ interval // Use provided value (0 or positive)
180
+ }
181
+ Log.d("ScannerViewManager", "📊 Final interval to set: ${actualInterval}s")
158
182
  view?.setBarcodeEmissionInterval(actualInterval)
159
183
  }
160
184
 
@@ -169,7 +193,16 @@ class ScannerViewManager : SimpleViewManager<ScannerView>() {
169
193
  "bubbled" to "onBarcodeScanned"
170
194
  )
171
195
  )
172
- // Add more events here if needed
196
+ map["onLoad"] = mapOf(
197
+ "phasedRegistrationNames" to mapOf(
198
+ "bubbled" to "onLoad"
199
+ )
200
+ )
201
+ map["onScannerError"] = mapOf(
202
+ "phasedRegistrationNames" to mapOf(
203
+ "bubbled" to "onScannerError"
204
+ )
205
+ )
173
206
  return map
174
207
  }
175
208
  }
@@ -263,7 +263,11 @@ using namespace facebook::react;
263
263
 
264
264
  // Barcode emission interval
265
265
  if (oldViewProps.barcodeEmissionInterval != newViewProps.barcodeEmissionInterval) {
266
- NSNumber *intervalValue = @(newViewProps.barcodeEmissionInterval);
266
+ // Handle negative values (clamp to 0)
267
+ double interval = newViewProps.barcodeEmissionInterval;
268
+ double actualInterval = interval < 0 ? 0.0 : interval;
269
+
270
+ NSNumber *intervalValue = @(actualInterval);
267
271
  if ([_scannerImpl respondsToSelector:@selector(setBarcodeEmissionInterval:)]) {
268
272
  [_scannerImpl performSelector:@selector(setBarcodeEmissionInterval:) withObject:intervalValue];
269
273
  }
@@ -6,6 +6,7 @@ import {
6
6
  import type {
7
7
  DirectEventHandler,
8
8
  Double,
9
+ WithDefault,
9
10
  } from 'react-native/Libraries/Types/CodegenTypesNamespace';
10
11
 
11
12
  // Define codegen types locally (no longer exported from react-native in 0.83)
@@ -111,7 +112,7 @@ export interface NativeProps extends ViewProps {
111
112
  * Prevents rapid duplicate detections. Set to 0 to disable debouncing.
112
113
  * @default 0.5
113
114
  */
114
- barcodeEmissionInterval?: Double;
115
+ barcodeEmissionInterval?: WithDefault<Double, 0.5>;
115
116
 
116
117
  onBarcodeScanned?: DirectEventHandler<BarcodeScannedEventPayload>;
117
118
  onScannerError?: DirectEventHandler<ScannerErrorEventPayload>;
@@ -1,5 +1,5 @@
1
1
  import { type ViewProps, type NativeSyntheticEvent } from 'react-native';
2
- import type { DirectEventHandler, Double } from 'react-native/Libraries/Types/CodegenTypesNamespace';
2
+ import type { DirectEventHandler, Double, WithDefault } from 'react-native/Libraries/Types/CodegenTypesNamespace';
3
3
  export interface BarcodeScannedEventPayload {
4
4
  barcodes: {
5
5
  data: string;
@@ -81,7 +81,7 @@ export interface NativeProps extends ViewProps {
81
81
  * Prevents rapid duplicate detections. Set to 0 to disable debouncing.
82
82
  * @default 0.5
83
83
  */
84
- barcodeEmissionInterval?: Double;
84
+ barcodeEmissionInterval?: WithDefault<Double, 0.5>;
85
85
  onBarcodeScanned?: DirectEventHandler<BarcodeScannedEventPayload>;
86
86
  onScannerError?: DirectEventHandler<ScannerErrorEventPayload>;
87
87
  onLoad?: DirectEventHandler<OnLoadEventPayload>;
@@ -1 +1 @@
1
- {"version":3,"file":"ScannerViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/ScannerViewNativeComponent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ScannerViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/ScannerViewNativeComponent.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cleanuidev/react-native-scanner",
3
- "version": "1.0.0-beta.2",
4
- "description": "scanner",
3
+ "version": "1.0.0-beta.3",
4
+ "description": "High-performance native barcode and QR code scanner for React Native. Scan barcodes in configurable target areas for precise detection. Built with CameraX & ML Kit (Android) and AVFoundation & Vision (iOS).",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
7
7
  "exports": {
@@ -45,7 +45,31 @@
45
45
  "keywords": [
46
46
  "react-native",
47
47
  "ios",
48
- "android"
48
+ "android",
49
+ "barcode-scanner",
50
+ "qr-code-scanner",
51
+ "barcode",
52
+ "qr-code",
53
+ "qrcode",
54
+ "scanner",
55
+ "camera",
56
+ "camerax",
57
+ "ml-kit",
58
+ "avfoundation",
59
+ "vision",
60
+ "react-native-scanner",
61
+ "barcode-detection",
62
+ "qr-detection",
63
+ "mobile-scanner",
64
+ "native-scanner",
65
+ "fabric",
66
+ "new architecture",
67
+ "focus area",
68
+ "region scanning",
69
+ "frame scanning",
70
+ "area scanning",
71
+ "targeted-scanning",
72
+ "precise-scanning"
49
73
  ],
50
74
  "repository": {
51
75
  "type": "git",
@@ -6,6 +6,7 @@ import {
6
6
  import type {
7
7
  DirectEventHandler,
8
8
  Double,
9
+ WithDefault,
9
10
  } from 'react-native/Libraries/Types/CodegenTypesNamespace';
10
11
 
11
12
  // Define codegen types locally (no longer exported from react-native in 0.83)
@@ -111,7 +112,7 @@ export interface NativeProps extends ViewProps {
111
112
  * Prevents rapid duplicate detections. Set to 0 to disable debouncing.
112
113
  * @default 0.5
113
114
  */
114
- barcodeEmissionInterval?: Double;
115
+ barcodeEmissionInterval?: WithDefault<Double, 0.5>;
115
116
 
116
117
  onBarcodeScanned?: DirectEventHandler<BarcodeScannedEventPayload>;
117
118
  onScannerError?: DirectEventHandler<ScannerErrorEventPayload>;