@sanctum-key/react-native-sdk 1.0.24 → 1.0.26

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 (73) hide show
  1. package/build/package.json +5 -2
  2. package/build/src/components/EnhancedCameraView.d.ts +7 -1
  3. package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
  4. package/build/src/components/EnhancedCameraView.js +88 -30
  5. package/build/src/components/EnhancedCameraView.js.map +1 -1
  6. package/build/src/components/EnhancedCameraView.web.d.ts +5 -1
  7. package/build/src/components/EnhancedCameraView.web.d.ts.map +1 -1
  8. package/build/src/components/EnhancedCameraView.web.js +80 -295
  9. package/build/src/components/EnhancedCameraView.web.js.map +1 -1
  10. package/build/src/components/KYCElements/CameraCapture.js +1 -1
  11. package/build/src/components/KYCElements/CameraCapture.js.map +1 -1
  12. package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
  13. package/build/src/components/KYCElements/CountrySelection.js +38 -218
  14. package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
  15. package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  16. package/build/src/components/KYCElements/CountrySelectionTemplate.js +5 -17
  17. package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  18. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  19. package/build/src/components/KYCElements/IDCardCapture.js +509 -95
  20. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  21. package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  22. package/build/src/components/KYCElements/VerificationProgressTemplate.js +93 -51
  23. package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  24. package/build/src/components/OverLay/type.d.ts +1 -0
  25. package/build/src/components/OverLay/type.d.ts.map +1 -1
  26. package/build/src/components/OverLay/type.js.map +1 -1
  27. package/build/src/components/WebBarcodeScanner.d.ts +9 -0
  28. package/build/src/components/WebBarcodeScanner.d.ts.map +1 -0
  29. package/build/src/components/WebBarcodeScanner.js +152 -0
  30. package/build/src/components/WebBarcodeScanner.js.map +1 -0
  31. package/build/src/config/KYCConfigs.js +2 -2
  32. package/build/src/config/KYCConfigs.js.map +1 -1
  33. package/build/src/config/region_mapping.json +0 -14
  34. package/build/src/modules/api/CardAuthentification.d.ts +2 -0
  35. package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
  36. package/build/src/modules/api/CardAuthentification.js +22 -39
  37. package/build/src/modules/api/CardAuthentification.js.map +1 -1
  38. package/build/src/modules/api/KYCService.d.ts +7 -2
  39. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  40. package/build/src/modules/api/KYCService.js +163 -57
  41. package/build/src/modules/api/KYCService.js.map +1 -1
  42. package/build/src/types/KYC.types.d.ts +1 -0
  43. package/build/src/types/KYC.types.d.ts.map +1 -1
  44. package/build/src/types/KYC.types.js.map +1 -1
  45. package/build/src/utils/aamvaParser.d.ts +62 -0
  46. package/build/src/utils/aamvaParser.d.ts.map +1 -0
  47. package/build/src/utils/aamvaParser.js +91 -0
  48. package/build/src/utils/aamvaParser.js.map +1 -0
  49. package/build/src/utils/cropByObb.d.ts.map +1 -1
  50. package/build/src/utils/cropByObb.js +4 -3
  51. package/build/src/utils/cropByObb.js.map +1 -1
  52. package/build/src/web/WebKYCEntry.d.ts +1 -1
  53. package/build/src/web/WebKYCEntry.d.ts.map +1 -1
  54. package/build/src/web/WebKYCEntry.js +105 -239
  55. package/build/src/web/WebKYCEntry.js.map +1 -1
  56. package/package.json +5 -2
  57. package/src/components/EnhancedCameraView.tsx +116 -42
  58. package/src/components/EnhancedCameraView.web.tsx +98 -338
  59. package/src/components/KYCElements/CameraCapture.tsx +1 -1
  60. package/src/components/KYCElements/CountrySelection.tsx +60 -240
  61. package/src/components/KYCElements/CountrySelectionTemplate.tsx +7 -20
  62. package/src/components/KYCElements/IDCardCapture.tsx +672 -151
  63. package/src/components/KYCElements/VerificationProgressTemplate.tsx +112 -65
  64. package/src/components/OverLay/type.ts +1 -1
  65. package/src/components/WebBarcodeScanner.tsx +273 -0
  66. package/src/config/KYCConfigs.ts +2 -2
  67. package/src/config/region_mapping.json +0 -14
  68. package/src/modules/api/CardAuthentification.ts +41 -56
  69. package/src/modules/api/KYCService.ts +236 -82
  70. package/src/types/KYC.types.ts +1 -0
  71. package/src/utils/aamvaParser.ts +102 -0
  72. package/src/utils/cropByObb.ts +5 -3
  73. package/src/web/WebKYCEntry.tsx +125 -301
@@ -1,9 +1,13 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { View, StyleSheet, TouchableOpacity, Text, Platform } from 'react-native';
3
3
  import { useI18n } from '../hooks/useI18n';
4
- export const EnhancedCameraView = ({ instructions = 'Position yourself in the frame and tap the capture button', showCamera, cameraType: initialCameraType = 'front', style, onCapture, onError, onClose, enableFlash = false, enableHdr = false, quality = 'high', showCaptureButton = true, showSwitchCamera = true, overlayComponent, bbox, canFlip = true, enableVideo = false, isRecording = false, onVideoRecordingStart, onVideoRecordingStop, videoDuration = 10, onSilentCapture, silentCaptureResult, captureStabilizationDelayMs = 2500, }) => {
4
+ // 🚨 Import the WebBarcodeScanner we built earlier
5
+ import { WebBarcodeScanner } from './WebBarcodeScanner';
6
+ export const EnhancedCameraView = ({ instructions = 'Position yourself in the frame and tap the capture button', showCamera, cameraType: initialCameraType = 'front', style, onCapture, onError, onClose, enableFlash = false, enableHdr = false, quality = 'high', showCaptureButton = true, showSwitchCamera = true, overlayComponent, bbox, canFlip = true, enableVideo = false, isRecording = false, onVideoRecordingStart, onVideoRecordingStop, videoDuration = 10, onSilentCapture, silentCaptureResult, captureStabilizationDelayMs = 2500,
7
+ // 🚨 New props for barcode support
8
+ isScanningBarcode = false, onBarcodeScanned, }) => {
5
9
  const { t } = useI18n();
6
- // Vérification de plateforme - ce composant est uniquement pour le web
10
+ // Platform check
7
11
  if (Platform.OS !== 'web') {
8
12
  console.warn('EnhancedCameraView.web.tsx should only be used on web platform');
9
13
  return null;
@@ -13,19 +17,22 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
13
17
  const [cameraType, setCameraType] = useState(initialCameraType);
14
18
  const [hasPermission, setHasPermission] = useState(false);
15
19
  const [isInitialized, setIsInitialized] = useState(false);
16
- const [flash, setFlash] = useState('off');
20
+ // const [flash, setFlash] = useState<'off' | 'on' | 'auto'>('off');
17
21
  const [stream, setStream] = useState(null);
18
- const [isRecordingVideo, setIsRecordingVideo] = useState(false);
19
- const [mediaRecorder, setMediaRecorder] = useState(null);
20
- const [recordedChunks, setRecordedChunks] = useState([]);
21
- console.log('cameraType', cameraType, recordedChunks);
22
- // Check permissions on component mount
22
+ // const [isRecordingVideo, setIsRecordingVideo] = useState(false);
23
+ // const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
24
+ // const [recordedChunks, setRecordedChunks] = useState<Blob[]>([]);
25
+ // 🚨 New Refs for Barcode Logic
26
+ const isProcessingRef = useRef(silentCaptureResult?.isAnalyzing || false);
27
+ const scannedBarcodeRef = useRef(null);
28
+ useEffect(() => {
29
+ isProcessingRef.current = silentCaptureResult?.isAnalyzing || false;
30
+ }, [silentCaptureResult?.isAnalyzing]);
23
31
  useEffect(() => {
24
32
  if (showCamera) {
25
33
  checkPermissions();
26
34
  }
27
35
  }, [showCamera]);
28
- // Cleanup stream on unmount
29
36
  useEffect(() => {
30
37
  return () => {
31
38
  if (stream) {
@@ -33,13 +40,11 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
33
40
  }
34
41
  };
35
42
  }, [stream]);
36
- // Build video constraints for quality (min + ideal improve Android/Samsung web quality; higher ideal for documents)
37
43
  const getVideoConstraints = useCallback(() => {
38
44
  const isHigh = quality === 'high';
39
45
  const isMedium = quality === 'medium';
40
46
  return {
41
47
  facingMode: cameraType === 'front' ? 'user' : 'environment',
42
- // min forces Android Chrome to use at least this resolution (avoids 640x480 default)
43
48
  width: {
44
49
  min: isHigh ? 1280 : isMedium ? 960 : 640,
45
50
  ideal: isHigh ? 2560 : isMedium ? 1280 : 640,
@@ -56,12 +61,11 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
56
61
  onError?.({ message: 'Camera not supported in this browser' });
57
62
  return;
58
63
  }
59
- // Use same constraints as startCamera so Android Chrome doesn't cache low resolution (e.g. 640x480)
60
- const stream = await navigator.mediaDevices.getUserMedia({
64
+ const tempStream = await navigator.mediaDevices.getUserMedia({
61
65
  video: getVideoConstraints(),
62
66
  audio: enableVideo,
63
67
  });
64
- stream.getTracks().forEach(track => track.stop());
68
+ tempStream.getTracks().forEach(track => track.stop());
65
69
  setHasPermission(true);
66
70
  await startCamera();
67
71
  }
@@ -85,7 +89,6 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
85
89
  }
86
90
  catch (err) {
87
91
  const name = err instanceof Error ? err.name : '';
88
- // On some Android devices, min constraints can fail; fallback to ideal only
89
92
  if (name === 'OverconstrainedError') {
90
93
  const fallbackConstraints = {
91
94
  video: {
@@ -104,7 +107,9 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
104
107
  setStream(newStream);
105
108
  if (videoRef.current) {
106
109
  videoRef.current.srcObject = newStream;
110
+ // 🚨 CRUCIAL FIX: Wait for the video to actually have metadata before saying it's initialized
107
111
  videoRef.current.onloadedmetadata = () => {
112
+ console.log('✅ [WEB ENGINE] Camera stream loaded metadata. Initializing.');
108
113
  setIsInitialized(true);
109
114
  };
110
115
  }
@@ -114,46 +119,33 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
114
119
  onError?.({ message: 'Failed to start camera' });
115
120
  }
116
121
  };
117
- const onInitialized = useCallback(() => {
118
- console.log('Camera initialized!');
119
- setIsInitialized(true);
120
- }, []);
121
- const onCameraError = useCallback((error) => {
122
- console.error('Camera error:', error);
123
- onError?.({ message: error.message || 'Camera error occurred' });
124
- }, [onError]);
125
- console.log('isInitialized', onInitialized, onCameraError);
126
- const capturePhoto = useCallback(async () => {
127
- try {
128
- onCapture && onCapture({
129
- success: true
130
- });
131
- }
132
- catch (error) {
133
- console.error('Error taking photo:', error);
134
- onCapture?.({
135
- success: false,
136
- error: error instanceof Error ? error.message : 'Failed to capture photo',
137
- });
138
- }
139
- }, [isInitialized, onCapture, onError]);
122
+ // const capturePhoto = useCallback(async () => {
123
+ // try {
124
+ // onCapture && onCapture({ success: true });
125
+ // } catch (error) {
126
+ // console.error('Error taking photo:', error);
127
+ // onCapture?.({
128
+ // success: false,
129
+ // error: error instanceof Error ? error.message : 'Failed to capture photo',
130
+ // });
131
+ // }
132
+ // }, [isInitialized, onCapture, onError]);
140
133
  const captureSilentPhoto = useCallback(async () => {
141
134
  try {
135
+ // During barcode phase, we still need to take a photo to give
136
+ // handleSilentCapture the image path for pendingCAImage.
137
+ // IDCardCapture gates further processing via scanPhase state.
142
138
  if (!videoRef.current || !canvasRef.current || !isInitialized) {
143
- onError?.({ message: 'Camera not ready' });
144
- return;
139
+ return; // Fail silently, no need to throw errors in a loop
145
140
  }
146
141
  const video = videoRef.current;
147
142
  const canvas = canvasRef.current;
148
143
  const context = canvas.getContext('2d');
149
144
  if (!context) {
150
- onError?.({ message: 'Canvas context not available' });
151
145
  return;
152
146
  }
153
- // Set canvas dimensions to match video
154
147
  canvas.width = video.videoWidth;
155
148
  canvas.height = video.videoHeight;
156
- // For front camera: draw flipped so captured image matches non-mirrored preview (no mirror confusion)
157
149
  if (cameraType === 'front') {
158
150
  context.save();
159
151
  context.translate(canvas.width, 0);
@@ -164,22 +156,13 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
164
156
  else {
165
157
  context.drawImage(video, 0, 0);
166
158
  }
167
- // Convert to base64 (0.95 for document/ID capture clarity; backend can exploit text better)
168
159
  const imageDataUrl = canvas.toDataURL('image/jpeg', 0.95);
169
- onSilentCapture?.({
170
- success: true,
171
- path: imageDataUrl,
172
- });
160
+ onSilentCapture?.({ success: true, path: imageDataUrl, barcode: null });
173
161
  }
174
162
  catch (error) {
175
- console.error('Error taking photo:', error);
176
- onCapture?.({
177
- success: false,
178
- error: error instanceof Error ? error.message : 'Failed to capture photo',
179
- });
163
+ console.error('Error taking silent photo:', error);
180
164
  }
181
- }, [isInitialized, cameraType, onError, onSilentCapture]);
182
- // Stabilization delay then auto-capture every 5s; stop as soon as capture is validated (no more new captures)
165
+ }, [isInitialized, cameraType, onSilentCapture, isScanningBarcode]);
183
166
  useEffect(() => {
184
167
  if (!showCamera || !isInitialized || silentCaptureResult?.success) {
185
168
  return;
@@ -197,85 +180,28 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
197
180
  clearInterval(intervalId);
198
181
  };
199
182
  }, [showCamera, isInitialized, captureStabilizationDelayMs, captureSilentPhoto, silentCaptureResult?.success]);
200
- const startVideoRecording = useCallback(async () => {
201
- try {
202
- if (!stream || !isInitialized) {
203
- onError?.({ message: 'Camera not ready' });
204
- return;
205
- }
206
- const chunks = [];
207
- setRecordedChunks(chunks);
208
- const recorder = new MediaRecorder(stream, {
209
- mimeType: 'video/webm;codecs=vp9',
210
- });
211
- recorder.ondataavailable = (event) => {
212
- if (event.data.size > 0) {
213
- chunks.push(event.data);
214
- }
215
- };
216
- recorder.onstop = () => {
217
- const blob = new Blob(chunks, { type: 'video/webm' });
218
- const url = URL.createObjectURL(blob);
219
- onVideoRecordingStop?.({
220
- success: true,
221
- path: url,
222
- });
223
- setRecordedChunks([]);
224
- setIsRecordingVideo(false);
225
- };
226
- recorder.onerror = (event) => {
227
- console.error('Recording error:', event);
228
- onVideoRecordingStop?.({
229
- success: false,
230
- error: 'Failed to record video',
231
- });
232
- setIsRecordingVideo(false);
233
- };
234
- setMediaRecorder(recorder);
235
- recorder.start();
236
- setIsRecordingVideo(true);
237
- onVideoRecordingStart?.();
238
- // Auto-stop after videoDuration seconds
239
- setTimeout(() => {
240
- if (recorder.state === 'recording') {
241
- recorder.stop();
242
- }
243
- }, videoDuration * 1000);
183
+ // 🚨 Memoized Callback for Barcode Decoding
184
+ const handleWebBarcodeScanned = useCallback((value) => {
185
+ console.log(`🎉 [WEB SCANNER] SUCCESS! Decoded value:`, value);
186
+ if (!isProcessingRef.current && value !== scannedBarcodeRef.current) {
187
+ scannedBarcodeRef.current = value;
188
+ onBarcodeScanned?.(value);
244
189
  }
245
- catch (error) {
246
- console.error('Error starting video recording:', error);
247
- onVideoRecordingStop?.({
248
- success: false,
249
- error: error instanceof Error ? error.message : 'Failed to start video recording',
250
- });
251
- }
252
- }, [isInitialized, stream, videoDuration, onVideoRecordingStart, onVideoRecordingStop, onError]);
253
- const stopVideoRecording = useCallback(async () => {
254
- try {
255
- if (mediaRecorder && mediaRecorder.state === 'recording') {
256
- mediaRecorder.stop();
257
- }
258
- }
259
- catch (error) {
260
- console.error('Error stopping video recording:', error);
261
- onError?.({ message: 'Failed to stop video recording' });
262
- }
263
- }, [mediaRecorder, onError]);
190
+ }, [onBarcodeScanned]);
191
+ // Video recording logic...
192
+ // const startVideoRecording = useCallback(async () => {
193
+ // /* ... Keep original logic ... */
194
+ // }, [isInitialized, stream, videoDuration, onVideoRecordingStart, onVideoRecordingStop, onError]);
195
+ // const stopVideoRecording = useCallback(async () => {
196
+ // /* ... Keep original logic ... */
197
+ // }, [mediaRecorder, onError]);
264
198
  const switchCamera = useCallback(async () => {
265
199
  setCameraType(current => current === 'front' ? 'back' : 'front');
266
- // Restart camera with new facing mode
267
200
  await startCamera();
268
201
  }, [cameraType]);
269
- const toggleFlash = useCallback(() => {
270
- setFlash(current => {
271
- switch (current) {
272
- case 'off': return 'on';
273
- case 'on': return 'auto';
274
- case 'auto': return 'off';
275
- default: return 'off';
276
- }
277
- });
278
- }, []);
202
+ // const toggleFlash = useCallback(() => {
203
+ // /* ... Keep original logic ... */
204
+ // }, []);
279
205
  if (!hasPermission) {
280
206
  return (<View style={[styles.container, style]}>
281
207
  <Text style={styles.permissionMessage}>
@@ -287,7 +213,6 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
287
213
  return <View style={[styles.container, style]}/>;
288
214
  }
289
215
  return (<View style={[styles.container, style]}>
290
- {/* Video element; no mirror for front camera so preview matches final photo and doesn't confuse users */}
291
216
  <video ref={videoRef} style={{
292
217
  position: 'absolute',
293
218
  width: '100%',
@@ -295,25 +220,19 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
295
220
  objectFit: 'cover',
296
221
  transform: cameraType === 'front' ? 'scaleX(-1)' : undefined,
297
222
  }} autoPlay playsInline muted/>
298
-
299
- {/* Hidden canvas for photo capture */}
300
223
  <canvas ref={canvasRef} style={{
301
224
  position: 'absolute',
302
225
  left: '-9999px',
303
226
  top: '-9999px',
304
227
  }}/>
305
228
 
306
- {/* Instructions */}
307
- {/* {instructions && (
308
- <View style={styles.instructionsOverlay}>
309
- <Text style={styles.instructions}>{instructions}</Text>
310
- </View>
311
- )} */}
229
+ {isScanningBarcode && isInitialized && (<WebBarcodeScanner videoRef={videoRef} onBarcodeScanned={handleWebBarcodeScanned}
230
+ // Use silentCaptureResult.isAnalyzing (state) not the ref so
231
+ // React re-renders with the correct active value
232
+ active={isScanningBarcode && isInitialized && !(silentCaptureResult?.isAnalyzing ?? false)}/>)}
312
233
 
313
- {/* Custom overlay component */}
314
234
  {overlayComponent}
315
235
 
316
- {/* Bounding box overlay */}
317
236
  {bbox && (<View style={styles.bboxOverlay}>
318
237
  <View style={[
319
238
  styles.bbox,
@@ -325,45 +244,15 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
325
244
  borderColor: bbox.borderColor || '#2DBD60',
326
245
  borderWidth: bbox.borderWidth || 3,
327
246
  borderRadius: bbox.cornerRadius || 8,
328
- }
247
+ },
329
248
  ]}/>
330
249
  </View>)}
331
250
 
332
- {/* Analyzing indicator - Same as mobile */}
333
251
  {silentCaptureResult?.isAnalyzing && (<View style={styles.analyzingContainer}>
334
252
  <Text style={styles.analyzingText}>{t('camera.analyzing')}</Text>
335
253
  </View>)}
336
254
 
337
- {/* Camera controls */}
338
255
  <View style={styles.controlsContainer}>
339
- {/* Flash button */}
340
- {enableFlash && (<TouchableOpacity style={styles.controlButton} onPress={toggleFlash}>
341
- <Text style={styles.controlButtonText}>
342
- {flash === 'off' ? '⚡' : flash === 'on' ? '⚡️' : '✨'}
343
- </Text>
344
- </TouchableOpacity>)}
345
-
346
- {/* Capture button */}
347
- {showCaptureButton && !enableVideo && silentCaptureResult?.success && (<TouchableOpacity style={styles.captureButton} onPress={capturePhoto} disabled={!isInitialized}>
348
- <View style={[
349
- styles.captureButtonInner,
350
- !isInitialized && styles.captureButtonDisabled
351
- ]}/>
352
- </TouchableOpacity>)}
353
-
354
- {/* Video recording button */}
355
- {showCaptureButton && enableVideo && (<TouchableOpacity style={[
356
- styles.captureButton,
357
- isRecordingVideo && styles.recordingButton
358
- ]} onPress={isRecordingVideo ? stopVideoRecording : startVideoRecording} disabled={!isInitialized}>
359
- <View style={[
360
- styles.captureButtonInner,
361
- !isInitialized && styles.captureButtonDisabled,
362
- isRecordingVideo && styles.recordingButtonInner
363
- ]}/>
364
- </TouchableOpacity>)}
365
-
366
- {/* Switch camera button */}
367
256
  {showSwitchCamera && canFlip && (<TouchableOpacity style={styles.controlButton} onPress={switchCamera}>
368
257
  <Text style={styles.controlButtonText}>🔄</Text>
369
258
  </TouchableOpacity>)}
@@ -371,129 +260,25 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
371
260
  </View>);
372
261
  };
373
262
  const styles = StyleSheet.create({
374
- container: {
375
- flex: 1,
376
- backgroundColor: 'black',
377
- },
378
- instructionsOverlay: {
379
- position: 'absolute',
380
- top: 60,
381
- left: 20,
382
- right: 20,
383
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
384
- padding: 15,
385
- borderRadius: 10,
386
- zIndex: 1,
387
- },
388
- instructions: {
389
- color: 'white',
390
- fontSize: 16,
391
- textAlign: 'center',
392
- fontWeight: '500',
393
- },
394
- closeButton: {
395
- position: 'absolute',
396
- top: 50,
397
- right: 20,
398
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
399
- width: 40,
400
- height: 40,
401
- borderRadius: 20,
402
- justifyContent: 'center',
403
- alignItems: 'center',
404
- zIndex: 2,
405
- },
406
- closeButtonText: {
407
- color: 'white',
408
- fontSize: 20,
409
- fontWeight: 'bold',
410
- },
411
- controlsContainer: {
412
- position: 'absolute',
413
- bottom: 40,
414
- left: 0,
415
- right: 0,
416
- flexDirection: 'row',
417
- justifyContent: 'space-around',
418
- alignItems: 'center',
419
- paddingHorizontal: 40,
420
- zIndex: 1,
421
- },
422
- controlButton: {
423
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
424
- width: 50,
425
- height: 50,
426
- borderRadius: 25,
427
- justifyContent: 'center',
428
- alignItems: 'center',
429
- },
430
- controlButtonText: {
431
- fontSize: 24,
432
- },
433
- captureButton: {
434
- backgroundColor: 'rgba(255, 255, 255, 0.3)',
435
- width: 80,
436
- height: 80,
437
- borderRadius: 40,
438
- justifyContent: 'center',
439
- alignItems: 'center',
440
- borderWidth: 3,
441
- borderColor: 'white',
442
- },
443
- captureButtonInner: {
444
- backgroundColor: 'white',
445
- width: 60,
446
- height: 60,
447
- borderRadius: 30,
448
- },
449
- captureButtonDisabled: {
450
- backgroundColor: 'rgba(255, 255, 255, 0.5)',
451
- },
452
- recordingButton: {
453
- backgroundColor: 'rgba(255, 59, 48, 0.3)',
454
- borderColor: '#FF3B30',
455
- },
456
- recordingButtonInner: {
457
- backgroundColor: '#FF3B30',
458
- },
459
- permissionMessage: {
460
- color: 'white',
461
- fontSize: 16,
462
- textAlign: 'center',
463
- margin: 20,
464
- },
465
- errorMessage: {
466
- color: 'red',
467
- fontSize: 16,
468
- textAlign: 'center',
469
- margin: 20,
470
- },
471
- bboxOverlay: {
472
- position: 'absolute',
473
- top: 0,
474
- left: 0,
475
- right: 0,
476
- bottom: 0,
477
- pointerEvents: 'none',
478
- },
479
- bbox: {
480
- position: 'absolute',
481
- borderStyle: 'solid',
482
- backgroundColor: 'transparent',
483
- },
484
- analyzingContainer: {
485
- position: 'absolute',
486
- bottom: 100,
487
- alignSelf: 'center',
488
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
489
- padding: 10,
490
- borderRadius: 10,
491
- zIndex: 1000,
492
- },
493
- analyzingText: {
494
- color: 'white',
495
- fontSize: 16,
496
- fontWeight: 'bold',
497
- },
263
+ // ... Keep all your original styles exactly as they are
264
+ container: { flex: 1, backgroundColor: 'black' },
265
+ instructionsOverlay: { position: 'absolute', top: 60, left: 20, right: 20, backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 15, borderRadius: 10, zIndex: 1 },
266
+ instructions: { color: 'white', fontSize: 16, textAlign: 'center', fontWeight: '500' },
267
+ closeButton: { position: 'absolute', top: 50, right: 20, backgroundColor: 'rgba(0, 0, 0, 0.7)', width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', zIndex: 2 },
268
+ closeButtonText: { color: 'white', fontSize: 20, fontWeight: 'bold' },
269
+ controlsContainer: { position: 'absolute', bottom: 40, left: 0, right: 0, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', paddingHorizontal: 40, zIndex: 1 },
270
+ controlButton: { backgroundColor: 'rgba(0, 0, 0, 0.7)', width: 50, height: 50, borderRadius: 25, justifyContent: 'center', alignItems: 'center' },
271
+ controlButtonText: { fontSize: 24 },
272
+ captureButton: { backgroundColor: 'rgba(255, 255, 255, 0.3)', width: 80, height: 80, borderRadius: 40, justifyContent: 'center', alignItems: 'center', borderWidth: 3, borderColor: 'white' },
273
+ captureButtonInner: { backgroundColor: 'white', width: 60, height: 60, borderRadius: 30 },
274
+ captureButtonDisabled: { backgroundColor: 'rgba(255, 255, 255, 0.5)' },
275
+ recordingButton: { backgroundColor: 'rgba(255, 59, 48, 0.3)', borderColor: '#FF3B30' },
276
+ recordingButtonInner: { backgroundColor: '#FF3B30' },
277
+ permissionMessage: { color: 'white', fontSize: 16, textAlign: 'center', margin: 20 },
278
+ errorMessage: { color: 'red', fontSize: 16, textAlign: 'center', margin: 20 },
279
+ bboxOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, pointerEvents: 'none' },
280
+ bbox: { position: 'absolute', borderStyle: 'solid', backgroundColor: 'transparent' },
281
+ analyzingContainer: { position: 'absolute', bottom: 100, alignSelf: 'center', backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 10, borderRadius: 10, zIndex: 1000 },
282
+ analyzingText: { color: 'white', fontSize: 16, fontWeight: 'bold' },
498
283
  });
499
284
  //# sourceMappingURL=EnhancedCameraView.web.js.map