@mleonard9/vin-scanner 1.3.0 → 1.4.2

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.
Files changed (70) hide show
  1. package/README.md +123 -38
  2. package/android/src/main/java/com/visioncamerabarcodescanner/VisionCameraBarcodeScannerModule.kt +26 -17
  3. package/lib/commonjs/ManualVinInput.js +146 -0
  4. package/lib/commonjs/ManualVinInput.js.map +1 -0
  5. package/lib/commonjs/PendingVinBanner.js +120 -0
  6. package/lib/commonjs/PendingVinBanner.js.map +1 -0
  7. package/lib/commonjs/TextVinPrompt.js +132 -0
  8. package/lib/commonjs/TextVinPrompt.js.map +1 -0
  9. package/lib/commonjs/haptics.js +36 -0
  10. package/lib/commonjs/haptics.js.map +1 -0
  11. package/lib/commonjs/index.js +184 -13
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/scanBarcodes.js.map +1 -1
  14. package/lib/commonjs/scanText.js.map +1 -1
  15. package/lib/commonjs/useVinScanner.js +164 -6
  16. package/lib/commonjs/useVinScanner.js.map +1 -1
  17. package/lib/commonjs/vinUtils.js +26 -12
  18. package/lib/commonjs/vinUtils.js.map +1 -1
  19. package/lib/module/ManualVinInput.js +138 -0
  20. package/lib/module/ManualVinInput.js.map +1 -0
  21. package/lib/module/PendingVinBanner.js +112 -0
  22. package/lib/module/PendingVinBanner.js.map +1 -0
  23. package/lib/module/TextVinPrompt.js +124 -0
  24. package/lib/module/TextVinPrompt.js.map +1 -0
  25. package/lib/module/haptics.js +27 -0
  26. package/lib/module/haptics.js.map +1 -0
  27. package/lib/module/index.js +171 -12
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/scanBarcodes.js.map +1 -1
  30. package/lib/module/scanText.js.map +1 -1
  31. package/lib/module/useVinScanner.js +165 -7
  32. package/lib/module/useVinScanner.js.map +1 -1
  33. package/lib/module/vinUtils.js +26 -12
  34. package/lib/module/vinUtils.js.map +1 -1
  35. package/lib/typescript/src/ManualVinInput.d.ts +11 -0
  36. package/lib/typescript/src/ManualVinInput.d.ts.map +1 -0
  37. package/lib/typescript/src/PendingVinBanner.d.ts +17 -0
  38. package/lib/typescript/src/PendingVinBanner.d.ts.map +1 -0
  39. package/lib/typescript/src/TextVinPrompt.d.ts +20 -0
  40. package/lib/typescript/src/TextVinPrompt.d.ts.map +1 -0
  41. package/lib/typescript/src/haptics.d.ts +4 -0
  42. package/lib/typescript/src/haptics.d.ts.map +1 -0
  43. package/lib/typescript/src/index.d.ts +3 -1
  44. package/lib/typescript/src/index.d.ts.map +1 -1
  45. package/lib/typescript/src/scanBarcodes.d.ts.map +1 -1
  46. package/lib/typescript/src/scanText.d.ts.map +1 -1
  47. package/lib/typescript/src/types.d.ts +46 -7
  48. package/lib/typescript/src/types.d.ts.map +1 -1
  49. package/lib/typescript/src/useVinScanner.d.ts +3 -1
  50. package/lib/typescript/src/useVinScanner.d.ts.map +1 -1
  51. package/lib/typescript/src/vinUtils.d.ts +7 -2
  52. package/lib/typescript/src/vinUtils.d.ts.map +1 -1
  53. package/package.json +5 -3
  54. package/src/ManualVinInput.tsx +184 -0
  55. package/src/PendingVinBanner.tsx +127 -0
  56. package/src/TextVinPrompt.tsx +147 -0
  57. package/src/haptics.ts +29 -0
  58. package/src/index.tsx +219 -22
  59. package/src/scanBarcodes.ts +5 -1
  60. package/src/scanText.ts +5 -1
  61. package/src/types.ts +55 -11
  62. package/src/useVinScanner.ts +209 -19
  63. package/src/vinUtils.ts +141 -82
  64. package/lib/commonjs/VinScannerOverlay.js +0 -60
  65. package/lib/commonjs/VinScannerOverlay.js.map +0 -1
  66. package/lib/module/VinScannerOverlay.js +0 -53
  67. package/lib/module/VinScannerOverlay.js.map +0 -1
  68. package/lib/typescript/src/VinScannerOverlay.d.ts +0 -14
  69. package/lib/typescript/src/VinScannerOverlay.d.ts.map +0 -1
  70. package/src/VinScannerOverlay.tsx +0 -55
package/README.md CHANGED
@@ -12,6 +12,8 @@ High-performance VIN detection for React Native powered by Google ML Kit barcode
12
12
 
13
13
  - `react-native-vision-camera` >= 3.9.0
14
14
  - `react-native-worklets-core` >= 0.4.0
15
+ - `react-native-gesture-handler` >= 2.0.0 (for tap-to-focus)
16
+ - `react-native-reanimated` >= 3.0.0 (for tap-to-focus)
15
17
  - iOS 13+ / Android 21+
16
18
 
17
19
  ## Installation
@@ -21,6 +23,9 @@ yarn add @mleonard9/vin-scanner
21
23
  # or
22
24
  npm install @mleonard9/vin-scanner
23
25
 
26
+ # Optional (for haptic cues)
27
+ # yarn add react-native-haptic-feedback
28
+
24
29
  # iOS
25
30
  cd ios && pod install
26
31
  ```
@@ -73,49 +78,45 @@ export function VinScannerExample(): JSX.Element {
73
78
 
74
79
  Every frame, the camera runs ML Kit barcode + text recognition, extracts 17-character VIN candidates, validates them (checksum included), and routes a payload to `callback`.
75
80
 
76
- ## Advanced Features
81
+ ## Camera Gestures
82
+
83
+ The VIN Scanner camera includes built-in support for intuitive camera controls:
84
+
85
+ ### Pinch to Zoom
77
86
 
78
- ### AR Overlay with Confidence Scoring
87
+ Pinch-to-zoom is **enabled by default**. Simply pinch on the camera view to zoom in and out. The zoom gesture is natively implemented by `react-native-vision-camera` for optimal performance.
79
88
 
80
- The package includes an optional AR overlay component that renders real-time bounding boxes around detected VINs, color-coded by confidence score.
89
+ ### Tap to Focus
90
+
91
+ Tap anywhere on the camera view to focus at that point. This feature requires `react-native-gesture-handler` and `react-native-reanimated`:
81
92
 
82
93
  **Installation:**
83
94
 
84
95
  ```sh
85
- yarn add @shopify/react-native-skia
96
+ yarn add react-native-gesture-handler react-native-reanimated
86
97
  # or
87
- npm install @shopify/react-native-skia
98
+ npm install react-native-gesture-handler react-native-reanimated
99
+
100
+ # iOS
101
+ cd ios && pod install
88
102
  ```
89
103
 
90
- **Usage:**
104
+ **Note:** These dependencies are likely already installed if you're using React Navigation or other common React Native libraries.
91
105
 
92
- ```tsx
93
- import { VinScannerOverlay } from '@mleonard9/vin-scanner';
94
-
95
- export function VinScannerWithOverlay() {
96
- const [candidates, setCandidates] = useState<VinCandidate[]>([]);
97
-
98
- const { frameProcessor } = useVinScanner({
99
- onResult: (detectedCandidates) => {
100
- setCandidates(detectedCandidates);
101
- },
102
- });
106
+ The tap-to-focus functionality works automatically once these dependencies are installed. Simply tap on the camera view where you want to focus, and the camera will adjust both auto-focus (AF) and auto-exposure (AE) for that point.
103
107
 
104
- return (
105
- <View style={StyleSheet.absoluteFill}>
106
- <Camera
107
- device={device}
108
- frameProcessor={frameProcessor}
109
- style={StyleSheet.absoluteFill}
110
- />
111
- <VinScannerOverlay
112
- candidates={candidates}
113
- colors={{ high: '#00FF00', medium: '#FFFF00', low: '#FF0000' }}
114
- />
115
- </View>
116
- );
117
- }
118
- ```
108
+ **How it works:**
109
+ - Tap on a VIN to focus precisely on that area
110
+ - The camera adjusts focus and exposure automatically
111
+ - Works seamlessly with the pinch-to-zoom gesture
112
+ - No additional configuration required
113
+
114
+
115
+ ## Advanced Features
116
+
117
+ ### AR Overlay (deprecated)
118
+
119
+ The Skia-based overlay component has been removed while alignment issues are addressed. Default barcode formats are tuned for VIN labels (`code-39`, `code-128`, `pdf-417`) with an automatic fallback to all formats after sustained misses. No Skia install is required.
119
120
 
120
121
  **Confidence Scoring:**
121
122
 
@@ -220,16 +221,101 @@ The `candidates` array contains every potential VIN found in the frame. `firstCa
220
221
  | `options.barcode.formats` | `BarcodeFormat[]` | Restrict ML Kit formats (`'code-39'`, `'code-128'`, `'pdf-417'`, etc.) | `['all']` |
221
222
  | `options.text.enabled` | boolean | Enable text recognition | `true` |
222
223
  | `options.text.language` | `'latin' \| 'chinese' \| 'devanagari' \| 'japanese' \| 'korean'` | ML Kit language pack | `'latin'` |
224
+ | `options.text.requireConfirmation` | boolean | When true, text VINs are held until you confirm; barcodes still emit immediately | `false` |
225
+ | `options.text.pendingTtlMs` | number | Auto-dismiss pending text VINs after this many ms (when `requireConfirmation` is true) | `5000` |
223
226
  | `options.detection.textScanInterval` | number | Run text recognition every Nth frame (1 = every frame) | `3` |
224
227
  | `options.detection.maxFrameRate` | number | Max FPS budget for frame processing (drops surplus frames to avoid blocking) | `30` |
225
228
  | `options.detection.forceOrientation` | `'portrait' \| 'portrait-upside-down' \| 'landscape-left' \| 'landscape-right'` | Forces ML Kit to interpret every frame using the given orientation (useful when the UI is locked to portrait but the sensor reports landscape) | `null` |
226
229
  | `options.detection.scanRegion` | `ScanRegion` | Restrict ML Kit processing to a specific region of the frame (normalized coordinates 0.0-1.0). Significantly improves performance by ignoring irrelevant areas. | `{ x: 0.15, y: 0.15, width: 0.7, height: 0.7 }` |
227
- | `options.detection.enableFrameQualityCheck` | boolean | Enable intelligent frame quality checks to skip blurry or dark frames, improving accuracy | `true` |
230
+ | `options.detection.enableFrameQualityCheck` | boolean | Deprecated; when false it disables `minLuma`/`minSharpness` gates | `true` |
231
+ | `options.detection.minLuma` | number | Minimum mean luma (0–255) required to process a frame; skips too-dark frames | `30` |
232
+ | `options.detection.minSharpness` | number | Minimum sharpness metric required; skips blurry frames | `12` |
233
+ | `options.detection.minConfidence` | number | Minimum candidate confidence required before emitting | `0.6` |
234
+ | `options.detection.barcodeFallbackAfter` | number | Frames without barcode hits before scanning all formats | `45` |
228
235
  | `options.duplicateDebounceMs` | number | Time in milliseconds to suppress duplicate VIN callbacks for the same value | `1500` |
229
- | `options.showOverlay` | boolean | Enable AR overlay (requires `@shopify/react-native-skia`) | `false` |
230
- | `options.overlayColors` | `OverlayColors` | Custom colors for AR overlay: `{ high, medium, low }` | `{ high: '#00FF00', medium: '#FFFF00', low: '#FF0000' }` |
231
- | `options.cameraSettings` | `CameraSettings` | Camera configuration: `{ fps, lowLightBoost, videoStabilizationMode }` | `{ fps: 30, lowLightBoost: true, videoStabilizationMode: 'off' }` |
236
+ | `options.showOverlay` | boolean | Deprecated; overlay component removed | `false` |
237
+ | `options.overlayColors` | `OverlayColors` | Deprecated; overlay component removed | `{ high: '#00FF00', medium: '#FFFF00', low: '#FF0000' }` |
238
+ | `options.cameraSettings` | `CameraSettings` | Camera configuration: `{ fps (clamped 24–30), lowLightBoost, videoStabilizationMode }` | `{ fps: 24, lowLightBoost: true, videoStabilizationMode: 'cinematic' }` |
232
239
  | `options.onResult` | `(candidates, event) => void` | Convenience callback when using `useVinScanner`; receives all candidates and the raw event | `undefined` |
240
+ | `options.onTextPending` | `(pending) => void` | Invoked when `text.requireConfirmation` is true and text VINs are detected | `undefined` |
241
+ | `options.haptics` | boolean | Enable built-in haptic cues (requires `react-native-haptic-feedback` installed) | `true` |
242
+
243
+ ### Behaviors & defaults
244
+ - Barcode-first: barcodes emit immediately; text VINs can require confirmation.
245
+ - Session dedupe: VINs are not re-emitted within a scan session (in addition to time-based debounce).
246
+ - Quality gate: frames below `minLuma` or `minSharpness` are skipped.
247
+ - Confidence gate: candidates below `minConfidence` are dropped.
248
+ - Barcode formats: defaults to `code-39`, `code-128`, `pdf-417` with automatic fallback to all formats after `barcodeFallbackAfter` empty frames.
249
+ - Camera hints: FPS clamped to 24–30 and `videoStabilizationMode` defaults to `cinematic` to keep headroom and reduce jitter.
250
+
251
+ ### Text confirmation UI (barcode = instant, text = tap-to-confirm)
252
+
253
+ ```tsx
254
+ import { useState } from 'react';
255
+ import { Camera, useCameraDevice } from 'react-native-vision-camera';
256
+ import { useVinScanner, TextVinPrompt, VinCandidate } from '@mleonard9/vin-scanner';
257
+
258
+ export function ConfirmingScanner() {
259
+ const device = useCameraDevice('back');
260
+ const [pending, setPending] = useState<VinCandidate[]>([]);
261
+
262
+ const { frameProcessor, pendingTextCandidates, confirmTextCandidate } = useVinScanner({
263
+ text: { requireConfirmation: true },
264
+ onTextPending: setPending,
265
+ onResult: (candidates) => {
266
+ // barcode VINs (or confirmed text VINs) arrive here
267
+ console.log('confirmed VINs', candidates.map((c) => c.value));
268
+ },
269
+ });
270
+
271
+ return (
272
+ <>
273
+ {device && (
274
+ <Camera style={{ flex: 1 }} device={device} frameProcessor={frameProcessor} isActive />
275
+ )}
276
+ <TextVinPrompt
277
+ visible={pendingTextCandidates.length > 0}
278
+ candidates={pendingTextCandidates}
279
+ buttonLabel=\"Book It\"
280
+ buttonColor=\"#0A84FF\"
281
+ onConfirm={(candidate) => confirmTextCandidate(candidate.value)}
282
+ onDismiss={() => setPending([])}
283
+ />
284
+ </>
285
+ );
286
+ }
287
+ ```
288
+
289
+ ### Manual VIN keypad with checksum guard
290
+
291
+ ```tsx
292
+ import { ManualVinInput } from '@mleonard9/vin-scanner';
293
+
294
+ export function ManualEntry({ onSubmit }: { onSubmit: (vin: string) => void }) {
295
+ return (
296
+ <ManualVinInput
297
+ buttonLabel=\"Book It\"
298
+ buttonColor=\"#0A84FF\"
299
+ onSubmit={onSubmit}
300
+ />
301
+ );
302
+ }
303
+ ```
304
+
305
+ ### Pending banner (alternative to modal)
306
+
307
+ ```tsx
308
+ import { PendingVinBanner } from '@mleonard9/vin-scanner';
309
+
310
+ <PendingVinBanner
311
+ visible={pendingTextCandidates.length > 0}
312
+ candidates={pendingTextCandidates}
313
+ buttonLabel=\"Book It\"
314
+ buttonColor=\"#0A84FF\"
315
+ onConfirm={(candidate) => confirmTextCandidate(candidate.value)}
316
+ onDismiss={() => setPending([])}
317
+ />;
318
+ ```
233
319
 
234
320
  ### Performance
235
321
 
@@ -242,7 +328,7 @@ Phase 1 optimizations dramatically improve scanning performance through native R
242
328
  | ROI + text interval (3 frames) | ~45ms | **75% faster** |
243
329
  | ROI + quality check + throttle | ~30ms | **83% faster** |
244
330
 
245
- **Default configuration** uses ROI scanning (`scanRegion: { x: 0.15, y: 0.15, width: 0.7, height: 0.7 }`), text scan interval of 3, and frame quality checks enabled. This provides excellent accuracy while maintaining real-time performance on mid-range devices.
331
+ **Default configuration** uses ROI scanning (`scanRegion: { x: 0.15, y: 0.15, width: 0.7, height: 0.7 }`) and a text scan interval of 3. This provides excellent accuracy while maintaining real-time performance on mid-range devices.
246
332
 
247
333
  **Tip:** For challenging lighting or distance scenarios, set `textScanInterval: 1` to scan every frame at the cost of higher CPU usage.
248
334
 
@@ -302,4 +388,3 @@ npm publish --access public
302
388
  ```
303
389
 
304
390
  Ensure the authenticated npm user has access to the `@mleonard9` scope.
305
-
@@ -48,24 +48,33 @@ class VisionCameraBarcodeScannerModule(
48
48
 
49
49
  private fun buildScannerOptions(effective: Map<String, Any>): BarcodeScannerOptions {
50
50
  val builder = BarcodeScannerOptions.Builder()
51
- when {
52
- effective["code-128"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODE_128)
53
- effective["code-39"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODE_39)
54
- effective["code-93"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODE_93)
55
- effective["codabar"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODABAR)
56
- effective["ean-13"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_EAN_13)
57
- effective["ean-8"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_EAN_8)
58
- effective["itf"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_ITF)
59
- effective["upc-e"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_UPC_E)
60
- effective["upc-a"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_UPC_A)
61
- effective["qr"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_QR_CODE)
62
- effective["pdf-417"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_PDF417)
63
- effective["aztec"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_AZTEC)
64
- effective["data-matrix"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_DATA_MATRIX)
65
- effective["all"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_ALL_FORMATS)
66
- else -> builder.setBarcodeFormats(FORMAT_ALL_FORMATS)
51
+
52
+ var mask = 0
53
+ fun maybeAdd(enabled: Boolean, format: Int) {
54
+ if (enabled) mask = mask or format
55
+ }
56
+
57
+ // Allow multiple formats at once; fall back to ALL when none specified.
58
+ maybeAdd(effective["all"].toString().toBoolean(), FORMAT_ALL_FORMATS)
59
+ maybeAdd(effective["code-128"].toString().toBoolean(), FORMAT_CODE_128)
60
+ maybeAdd(effective["code-39"].toString().toBoolean(), FORMAT_CODE_39)
61
+ maybeAdd(effective["code-93"].toString().toBoolean(), FORMAT_CODE_93)
62
+ maybeAdd(effective["codabar"].toString().toBoolean(), FORMAT_CODABAR)
63
+ maybeAdd(effective["ean-13"].toString().toBoolean(), FORMAT_EAN_13)
64
+ maybeAdd(effective["ean-8"].toString().toBoolean(), FORMAT_EAN_8)
65
+ maybeAdd(effective["itf"].toString().toBoolean(), FORMAT_ITF)
66
+ maybeAdd(effective["upc-e"].toString().toBoolean(), FORMAT_UPC_E)
67
+ maybeAdd(effective["upc-a"].toString().toBoolean(), FORMAT_UPC_A)
68
+ maybeAdd(effective["qr"].toString().toBoolean(), FORMAT_QR_CODE)
69
+ maybeAdd(effective["pdf-417"].toString().toBoolean(), FORMAT_PDF417)
70
+ maybeAdd(effective["aztec"].toString().toBoolean(), FORMAT_AZTEC)
71
+ maybeAdd(effective["data-matrix"].toString().toBoolean(), FORMAT_DATA_MATRIX)
72
+
73
+ if (mask == 0) {
74
+ mask = FORMAT_ALL_FORMATS
67
75
  }
68
- return builder.build()
76
+
77
+ return builder.setBarcodeFormats(mask).build()
69
78
  }
70
79
 
71
80
  private fun orientationToDegrees(orientation: String?): Int? {
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ManualVinInput = ManualVinInput;
7
+ exports.default = void 0;
8
+ var _react = _interopRequireWildcard(require("react"));
9
+ var _reactNative = require("react-native");
10
+ var _vinUtils = require("./vinUtils");
11
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
+ const VIN_CHARS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
13
+ const DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
14
+ function ManualVinInput({
15
+ initialValue = '',
16
+ onSubmit,
17
+ buttonLabel = 'Use VIN',
18
+ buttonColor = '#0A84FF',
19
+ placeholder = 'Enter VIN (17 chars)'
20
+ }) {
21
+ const [value, setValue] = (0, _react.useState)(initialValue.toUpperCase());
22
+ const isValid = (0, _react.useMemo)(() => (0, _vinUtils.isValidVin)(value), [value]);
23
+ const showError = value.length >= 17 && !isValid;
24
+ const handlePress = ch => {
25
+ setValue(prev => (prev + ch).slice(0, 17).toUpperCase());
26
+ };
27
+ const handleBackspace = () => {
28
+ setValue(prev => prev.slice(0, -1));
29
+ };
30
+ const handleSubmit = () => {
31
+ if (isValid && onSubmit) {
32
+ onSubmit(value);
33
+ }
34
+ };
35
+ return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
36
+ style: styles.container
37
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.TextInput, {
38
+ value: value,
39
+ onChangeText: txt => setValue(txt.replace(/[^A-HJ-NPR-Z0-9]/gi, '').slice(0, 17).toUpperCase()),
40
+ style: [styles.input, showError && styles.errorInput],
41
+ placeholder: placeholder,
42
+ autoCapitalize: "characters",
43
+ autoCorrect: false
44
+ }), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
45
+ style: styles.row
46
+ }, VIN_CHARS.map(c => /*#__PURE__*/_react.default.createElement(Key, {
47
+ key: c,
48
+ label: c,
49
+ onPress: () => handlePress(c)
50
+ }))), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
51
+ style: styles.row
52
+ }, DIGITS.map(c => /*#__PURE__*/_react.default.createElement(Key, {
53
+ key: c,
54
+ label: c,
55
+ onPress: () => handlePress(c)
56
+ })), /*#__PURE__*/_react.default.createElement(Key, {
57
+ label: "\u232B",
58
+ onPress: handleBackspace,
59
+ wide: true
60
+ })), /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
61
+ style: [styles.submit, {
62
+ backgroundColor: buttonColor
63
+ }],
64
+ disabled: !isValid,
65
+ onPress: handleSubmit
66
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
67
+ style: styles.submitText
68
+ }, buttonLabel)), showError && /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
69
+ style: styles.errorText
70
+ }, "Checksum invalid"));
71
+ }
72
+ function Key({
73
+ label,
74
+ onPress,
75
+ wide
76
+ }) {
77
+ return /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
78
+ onPress: onPress,
79
+ style: [styles.key, wide && styles.keyWide]
80
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
81
+ style: styles.keyText
82
+ }, label));
83
+ }
84
+ const styles = _reactNative.StyleSheet.create({
85
+ container: {
86
+ width: '100%',
87
+ padding: 12,
88
+ backgroundColor: '#0D0D0D',
89
+ borderRadius: 12
90
+ },
91
+ input: {
92
+ backgroundColor: '#111827',
93
+ color: 'white',
94
+ paddingHorizontal: 12,
95
+ paddingVertical: 10,
96
+ borderRadius: 8,
97
+ fontSize: 16,
98
+ letterSpacing: 1,
99
+ borderWidth: 1,
100
+ borderColor: '#1F2937',
101
+ marginBottom: 10
102
+ },
103
+ errorInput: {
104
+ borderColor: '#EF4444'
105
+ },
106
+ row: {
107
+ flexDirection: 'row',
108
+ flexWrap: 'wrap',
109
+ gap: 6,
110
+ marginBottom: 8
111
+ },
112
+ key: {
113
+ paddingVertical: 10,
114
+ paddingHorizontal: 12,
115
+ backgroundColor: '#1F2937',
116
+ borderRadius: 8,
117
+ minWidth: 42,
118
+ alignItems: 'center'
119
+ },
120
+ keyWide: {
121
+ minWidth: 64
122
+ },
123
+ keyText: {
124
+ color: 'white',
125
+ fontSize: 14,
126
+ fontWeight: '700'
127
+ },
128
+ submit: {
129
+ marginTop: 8,
130
+ paddingVertical: 12,
131
+ borderRadius: 10,
132
+ alignItems: 'center'
133
+ },
134
+ submitText: {
135
+ color: 'white',
136
+ fontSize: 16,
137
+ fontWeight: '700'
138
+ },
139
+ errorText: {
140
+ color: '#F87171',
141
+ marginTop: 6,
142
+ fontSize: 13
143
+ }
144
+ });
145
+ var _default = exports.default = ManualVinInput;
146
+ //# sourceMappingURL=ManualVinInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_vinUtils","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","VIN_CHARS","DIGITS","ManualVinInput","initialValue","onSubmit","buttonLabel","buttonColor","placeholder","value","setValue","useState","toUpperCase","isValid","useMemo","isValidVin","showError","length","handlePress","ch","prev","slice","handleBackspace","handleSubmit","createElement","View","style","styles","container","TextInput","onChangeText","txt","replace","input","errorInput","autoCapitalize","autoCorrect","row","map","c","Key","key","label","onPress","wide","Pressable","submit","backgroundColor","disabled","Text","submitText","errorText","keyWide","keyText","StyleSheet","create","width","padding","borderRadius","color","paddingHorizontal","paddingVertical","fontSize","letterSpacing","borderWidth","borderColor","marginBottom","flexDirection","flexWrap","gap","minWidth","alignItems","fontWeight","marginTop","_default","exports"],"sourceRoot":"../../src","sources":["ManualVinInput.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PendingVinBanner = PendingVinBanner;
7
+ exports.default = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactNative = require("react-native");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ /**
12
+ * Compact bottom banner for pending text VINs.
13
+ * Works well together with `text.requireConfirmation`.
14
+ */
15
+ function PendingVinBanner({
16
+ visible,
17
+ candidates,
18
+ onConfirm,
19
+ onDismiss,
20
+ buttonLabel = 'Use VIN',
21
+ buttonColor = '#0A84FF'
22
+ }) {
23
+ const anim = _react.default.useRef(new _reactNative.Animated.Value(0)).current;
24
+ _react.default.useEffect(() => {
25
+ _reactNative.Animated.timing(anim, {
26
+ toValue: visible ? 1 : 0,
27
+ duration: 220,
28
+ useNativeDriver: true
29
+ }).start();
30
+ }, [visible, anim]);
31
+ const translateY = anim.interpolate({
32
+ inputRange: [0, 1],
33
+ outputRange: [160, 0]
34
+ });
35
+ if (!candidates.length) return null;
36
+ return /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {
37
+ pointerEvents: visible ? 'auto' : 'none',
38
+ style: [styles.container, {
39
+ transform: [{
40
+ translateY
41
+ }],
42
+ opacity: anim
43
+ }]
44
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
45
+ style: styles.header
46
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
47
+ style: styles.label
48
+ }, candidates.length > 1 ? `${candidates.length} VINs detected` : 'VIN detected'), onDismiss && /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
49
+ onPress: onDismiss,
50
+ hitSlop: 12,
51
+ style: styles.dismiss
52
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
53
+ style: styles.dismissText
54
+ }, "Dismiss"))), candidates.map(vin => /*#__PURE__*/_react.default.createElement(_reactNative.View, {
55
+ key: vin.value,
56
+ style: styles.row
57
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
58
+ style: styles.vin
59
+ }, vin.value), /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, {
60
+ onPress: () => onConfirm(vin),
61
+ style: [styles.button, {
62
+ backgroundColor: buttonColor
63
+ }]
64
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
65
+ style: styles.buttonText
66
+ }, buttonLabel)))));
67
+ }
68
+ const styles = _reactNative.StyleSheet.create({
69
+ container: {
70
+ position: 'absolute',
71
+ left: 16,
72
+ right: 16,
73
+ bottom: 40,
74
+ backgroundColor: 'rgba(0,0,0,0.9)',
75
+ borderRadius: 16,
76
+ padding: 14,
77
+ gap: 10
78
+ },
79
+ header: {
80
+ flexDirection: 'row',
81
+ alignItems: 'center',
82
+ justifyContent: 'space-between'
83
+ },
84
+ label: {
85
+ color: '#E5E7EB',
86
+ fontSize: 14,
87
+ fontWeight: '700'
88
+ },
89
+ dismiss: {
90
+ padding: 4
91
+ },
92
+ dismissText: {
93
+ color: '#9CA3AF',
94
+ fontSize: 12
95
+ },
96
+ row: {
97
+ flexDirection: 'row',
98
+ alignItems: 'center',
99
+ justifyContent: 'space-between',
100
+ gap: 10
101
+ },
102
+ vin: {
103
+ flex: 1,
104
+ color: 'white',
105
+ fontSize: 16,
106
+ letterSpacing: 1
107
+ },
108
+ button: {
109
+ paddingHorizontal: 14,
110
+ paddingVertical: 10,
111
+ borderRadius: 10
112
+ },
113
+ buttonText: {
114
+ color: 'white',
115
+ fontSize: 14,
116
+ fontWeight: '700'
117
+ }
118
+ });
119
+ var _default = exports.default = PendingVinBanner;
120
+ //# sourceMappingURL=PendingVinBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","PendingVinBanner","visible","candidates","onConfirm","onDismiss","buttonLabel","buttonColor","anim","React","useRef","Animated","Value","current","useEffect","timing","toValue","duration","useNativeDriver","start","translateY","interpolate","inputRange","outputRange","length","createElement","View","pointerEvents","style","styles","container","transform","opacity","header","Text","label","Pressable","onPress","hitSlop","dismiss","dismissText","map","vin","key","value","row","button","backgroundColor","buttonText","StyleSheet","create","position","left","right","bottom","borderRadius","padding","gap","flexDirection","alignItems","justifyContent","color","fontSize","fontWeight","flex","letterSpacing","paddingHorizontal","paddingVertical","_default","exports"],"sourceRoot":"../../src","sources":["PendingVinBanner.tsx"],"mappings":"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","ignoreList":[]}