datakeen-session-react 1.1.194-rc.0 → 1.1.194-rc.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.
@@ -1 +1 @@
1
- {"version":3,"file":"CameraMask.js","sources":["../../../../../src/components/id-check/CameraMask.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport type { CameraFacingMode } from \"../../types/camera\";\n\ninterface CameraMaskProps {\n isDetecting: boolean;\n isPortrait?: boolean;\n facingMode?: CameraFacingMode;\n isCountingDown?: boolean;\n countdown?: number;\n maskType?: \"id\" | \"document\";\n documentDetected?: boolean;\n onMaskRectChange?: (\n rect:\n | {\n left: number;\n top: number;\n width: number;\n height: number;\n }\n | null\n ) => void;\n}\n\nconst COUNTDOWN_DURATION = 3; // seconds\n\nconst CameraMask: React.FC<CameraMaskProps> = ({\n isPortrait = false,\n facingMode = \"environment\",\n isCountingDown = false,\n countdown = 0,\n maskType = \"id\",\n documentDetected = false,\n onMaskRectChange,\n}) => {\n const [videoOrientation, setVideoOrientation] = useState<boolean | null>(\n null\n );\n const { t } = useI18n();\n const maskRef = useRef<HTMLDivElement>(null);\n\n // Détecter l'orientation réelle de la vidéo pour synchroniser avec Photo.tsx\n useEffect(() => {\n const checkVideoOrientation = () => {\n const videoElement = document.querySelector(\"video\");\n if (\n videoElement &&\n videoElement.videoWidth > 0 &&\n videoElement.videoHeight > 0\n ) {\n const videoIsPortrait =\n videoElement.videoHeight > videoElement.videoWidth;\n setVideoOrientation(videoIsPortrait);\n }\n };\n\n // Vérifier immédiatement\n checkVideoOrientation();\n\n // Vérifier périodiquement en cas de changement\n const interval = setInterval(checkVideoOrientation, 1000);\n\n return () => clearInterval(interval);\n }, []);\n\n // Utiliser l'orientation de la vidéo si disponible, sinon fallback sur l'orientation de l'écran\n const effectiveIsPortrait =\n videoOrientation !== null ? videoOrientation : isPortrait;\n\n // Calculate the progress of the animation (0 to 1) over COUNTDOWN_DURATION seconds\n const progress = isCountingDown\n ? Math.min(1, (COUNTDOWN_DURATION - countdown) / COUNTDOWN_DURATION)\n : 0;\n\n useLayoutEffect(() => {\n if (!onMaskRectChange) {\n return;\n }\n\n const notify = () => {\n if (!maskRef.current) {\n onMaskRectChange(null);\n console.debug(\"[CameraMask] maskRef unavailable\");\n return;\n }\n\n const rect = maskRef.current.getBoundingClientRect();\n onMaskRectChange({\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n console.debug(\"[CameraMask] mask rect updated\", {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n };\n\n requestAnimationFrame(notify);\n\n const handleResize = () => requestAnimationFrame(notify);\n window.addEventListener(\"resize\", handleResize);\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\" && maskRef.current) {\n resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(notify);\n });\n resizeObserver.observe(maskRef.current);\n }\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n resizeObserver?.disconnect();\n };\n }, [onMaskRectChange, effectiveIsPortrait, facingMode]);\n\n return (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n <div\n className={`\n relative\n ${maskType === \"document\" ? \"aspect-[1/1.41]\" : \"aspect-3/2\"}\n ${facingMode === \"user\" ? \"transform scale-x-[-1]\" : \"\"}\n transition-all duration-300 ease-in-out\n `}\n style={{\n boxShadow: \"0 0 0 9999px rgba(0, 0, 0, 0.75)\",\n borderRadius: \"8px\",\n width: maskType === \"document\" ? (effectiveIsPortrait ? \"85%\" : \"60%\") : (effectiveIsPortrait ? \"95%\" : \"85%\"),\n }}\n data-mask={maskType === \"document\" ? \"document-frame\" : \"id-frame\"}\n ref={maskRef}\n >\n {/* Base border - white dashed by default, green solid once a document is detected */}\n <div\n data-testid=\"camera-mask-border\"\n className=\"absolute inset-0 transition-colors duration-300 ease-in-out\"\n style={{\n borderWidth: \"3px\",\n borderColor: documentDetected ? \"#11E5C5\" : \"#ffffff\",\n borderStyle: documentDetected ? \"solid\" : \"dashed\",\n borderRadius: \"8px\",\n }}\n />\n\n {/* Document detected badge - icon + text, not color-only */}\n {documentDetected && (\n <div\n data-testid=\"document-detected-badge\"\n className=\"absolute -top-9 left-1/2 -translate-x-1/2 flex items-center gap-1 bg-[#11E5C5] text-white text-xs font-semibold px-2 py-1 rounded-full whitespace-nowrap\"\n >\n <span aria-hidden=\"true\">✓</span>\n <span>\n {t(\"id_check.camera.document_detected\", \"Document détecté\")}\n </span>\n </div>\n )}\n\n {/* Animated blue border overlay */}\n {isCountingDown && (\n <svg\n className=\"absolute inset-0 w-full h-full\"\n style={{\n borderRadius: \"8px\",\n }}\n >\n <rect\n x=\"1.5\"\n y=\"1.5\"\n width={`calc(100% - 3px)`}\n height={`calc(100% - 3px)`}\n fill=\"none\"\n stroke=\"#11E5C5\"\n strokeWidth=\"3\"\n strokeDasharray=\"100\"\n strokeDashoffset={100 - progress * 100}\n pathLength=\"100\"\n rx=\"6\"\n ry=\"6\"\n style={{\n transition: \"stroke-dashoffset 0.1s linear\",\n }}\n />\n </svg>\n )}\n\n {/* Countdown display */}\n {isCountingDown && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"bg-black bg-opacity-50 text-white px-4 py-2 rounded-full text-lg font-bold\">\n {Math.ceil(countdown)}\n </div>\n </div>\n )}\n\n {/* Indicateur d'orientation pour debug */}\n {(typeof process !== \"undefined\" && process.env && process.env.NODE_ENV === \"development\") && (\n <div className=\"absolute -top-8 left-0 text-white text-xs bg-black bg-opacity-50 px-2 py-1 rounded\">\n {effectiveIsPortrait ? t(\"id_check.orientation.portrait\", \"Portrait\") : t(\"id_check.orientation.landscape\", \"Landscape\")}\n {videoOrientation !== null ? ` (${t(\"id_check.orientation.video_suffix\", \"Video\")})` : ` (${t(\"id_check.orientation.screen_suffix\", \"Screen\")})`}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default CameraMask;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"CameraMask.js","sources":["../../../../../src/components/id-check/CameraMask.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport type { CameraFacingMode } from \"../../types/camera\";\nimport type { DocumentDetectionHint } from \"../../services/documentEdgeDetectionService\";\n\ninterface CameraMaskProps {\n isDetecting: boolean;\n isPortrait?: boolean;\n facingMode?: CameraFacingMode;\n isCountingDown?: boolean;\n countdown?: number;\n maskType?: \"id\" | \"document\";\n documentDetected?: boolean;\n qualityHint?: DocumentDetectionHint;\n onMaskRectChange?: (\n rect:\n | {\n left: number;\n top: number;\n width: number;\n height: number;\n }\n | null\n ) => void;\n}\n\nconst COUNTDOWN_DURATION = 3; // seconds\n\nconst CameraMask: React.FC<CameraMaskProps> = ({\n isPortrait = false,\n facingMode = \"environment\",\n isCountingDown = false,\n countdown = 0,\n maskType = \"id\",\n documentDetected = false,\n qualityHint,\n onMaskRectChange,\n}) => {\n const [videoOrientation, setVideoOrientation] = useState<boolean | null>(\n null\n );\n const { t } = useI18n();\n const maskRef = useRef<HTMLDivElement>(null);\n\n // Détecter l'orientation réelle de la vidéo pour synchroniser avec Photo.tsx\n useEffect(() => {\n const checkVideoOrientation = () => {\n const videoElement = document.querySelector(\"video\");\n if (\n videoElement &&\n videoElement.videoWidth > 0 &&\n videoElement.videoHeight > 0\n ) {\n const videoIsPortrait =\n videoElement.videoHeight > videoElement.videoWidth;\n setVideoOrientation(videoIsPortrait);\n }\n };\n\n // Vérifier immédiatement\n checkVideoOrientation();\n\n // Vérifier périodiquement en cas de changement\n const interval = setInterval(checkVideoOrientation, 1000);\n\n return () => clearInterval(interval);\n }, []);\n\n // Utiliser l'orientation de la vidéo si disponible, sinon fallback sur l'orientation de l'écran\n const effectiveIsPortrait =\n videoOrientation !== null ? videoOrientation : isPortrait;\n\n // Calculate the progress of the animation (0 to 1) over COUNTDOWN_DURATION seconds\n const progress = isCountingDown\n ? Math.min(1, (COUNTDOWN_DURATION - countdown) / COUNTDOWN_DURATION)\n : 0;\n\n useLayoutEffect(() => {\n if (!onMaskRectChange) {\n return;\n }\n\n const notify = () => {\n if (!maskRef.current) {\n onMaskRectChange(null);\n console.debug(\"[CameraMask] maskRef unavailable\");\n return;\n }\n\n const rect = maskRef.current.getBoundingClientRect();\n onMaskRectChange({\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n console.debug(\"[CameraMask] mask rect updated\", {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n });\n };\n\n requestAnimationFrame(notify);\n\n const handleResize = () => requestAnimationFrame(notify);\n window.addEventListener(\"resize\", handleResize);\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\" && maskRef.current) {\n resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(notify);\n });\n resizeObserver.observe(maskRef.current);\n }\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n resizeObserver?.disconnect();\n };\n }, [onMaskRectChange, effectiveIsPortrait, facingMode]);\n\n return (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n <div\n className={`\n relative\n ${maskType === \"document\" ? \"aspect-[1/1.41]\" : \"aspect-3/2\"}\n ${facingMode === \"user\" ? \"transform scale-x-[-1]\" : \"\"}\n transition-all duration-300 ease-in-out\n `}\n style={{\n boxShadow: \"0 0 0 9999px rgba(0, 0, 0, 0.75)\",\n borderRadius: \"8px\",\n width: maskType === \"document\" ? (effectiveIsPortrait ? \"85%\" : \"60%\") : (effectiveIsPortrait ? \"95%\" : \"85%\"),\n }}\n data-mask={maskType === \"document\" ? \"document-frame\" : \"id-frame\"}\n ref={maskRef}\n >\n {/* Base border - white dashed by default, amber dashed on a fixable\n quality issue (too dark / too much glare), green solid once a\n document is detected. Never conveys a blocked state — always\n informative, never a gate. */}\n <div\n data-testid=\"camera-mask-border\"\n className=\"absolute inset-0 transition-colors duration-300 ease-in-out\"\n style={{\n borderWidth: \"3px\",\n borderColor: documentDetected\n ? \"#11E5C5\"\n : qualityHint === \"too_dark\" || qualityHint === \"too_bright\"\n ? \"#F59E0B\"\n : \"#ffffff\",\n borderStyle: documentDetected ? \"solid\" : \"dashed\",\n borderRadius: \"8px\",\n }}\n />\n\n {/* Document detected badge - icon + text, not color-only */}\n {documentDetected && (\n <div\n data-testid=\"document-detected-badge\"\n className=\"absolute -top-9 left-1/2 -translate-x-1/2 flex items-center gap-1 bg-[#11E5C5] text-white text-xs font-semibold px-2 py-1 rounded-full whitespace-nowrap\"\n >\n <span aria-hidden=\"true\">✓</span>\n <span>\n {t(\"id_check.camera.document_detected\", \"Document détecté\")}\n </span>\n </div>\n )}\n\n {/* Animated blue border overlay */}\n {isCountingDown && (\n <svg\n className=\"absolute inset-0 w-full h-full\"\n style={{\n borderRadius: \"8px\",\n }}\n >\n <rect\n x=\"1.5\"\n y=\"1.5\"\n width={`calc(100% - 3px)`}\n height={`calc(100% - 3px)`}\n fill=\"none\"\n stroke=\"#11E5C5\"\n strokeWidth=\"3\"\n strokeDasharray=\"100\"\n strokeDashoffset={100 - progress * 100}\n pathLength=\"100\"\n rx=\"6\"\n ry=\"6\"\n style={{\n transition: \"stroke-dashoffset 0.1s linear\",\n }}\n />\n </svg>\n )}\n\n {/* Countdown display */}\n {isCountingDown && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"bg-black bg-opacity-50 text-white px-4 py-2 rounded-full text-lg font-bold\">\n {Math.ceil(countdown)}\n </div>\n </div>\n )}\n\n {/* Indicateur d'orientation pour debug */}\n {(typeof process !== \"undefined\" && process.env && process.env.NODE_ENV === \"development\") && (\n <div className=\"absolute -top-8 left-0 text-white text-xs bg-black bg-opacity-50 px-2 py-1 rounded\">\n {effectiveIsPortrait ? t(\"id_check.orientation.portrait\", \"Portrait\") : t(\"id_check.orientation.landscape\", \"Landscape\")}\n {videoOrientation !== null ? ` (${t(\"id_check.orientation.video_suffix\", \"Video\")})` : ` (${t(\"id_check.orientation.screen_suffix\", \"Screen\")})`}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default CameraMask;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { __awaiter, __generator } from '../../node_modules/tslib/tslib.es6.js';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
  import { useRef, useState, useCallback, useEffect } from 'react';
4
4
  import { cameraService } from '../../services/cameraService.js';
5
- import { documentDetectionService } from '../../services/documentDetectionService.js';
5
+ import { documentEdgeDetectionService } from '../../services/documentEdgeDetectionService.js';
6
6
  import CameraError from './CameraError.js';
7
7
  import CameraMask from './CameraMask.js';
8
8
  import OrientationToggle from './OrientationToggle.js';
@@ -20,11 +20,14 @@ var Photo = function (_a) {
20
20
  var _h = useState(false), isCountingDown = _h[0], setIsCountingDown = _h[1];
21
21
  var _j = useState(0), countdown = _j[0], setCountdown = _j[1];
22
22
  var _k = useState(false), documentDetected = _k[0], setDocumentDetected = _k[1];
23
- var _l = useState(null), captureError = _l[0], setCaptureError = _l[1];
24
- var _m = useState(false), showCaptureFlash = _m[0], setShowCaptureFlash = _m[1];
23
+ var _l = useState(undefined), qualityHint = _l[0], setQualityHint = _l[1];
24
+ var _m = useState(true), isInitializing = _m[0], setIsInitializing = _m[1];
25
+ var _o = useState(false), isProcessing = _o[0], setIsProcessing = _o[1];
26
+ var _p = useState(null), captureError = _p[0], setCaptureError = _p[1];
27
+ var _q = useState(false), showCaptureFlash = _q[0], setShowCaptureFlash = _q[1];
25
28
  var t = useI18n().t;
26
- var _o = useState(null); _o[0]; var setLastCaptureMeta = _o[1];
27
- var _p = useState(null), maskRect = _p[0], setMaskRect = _p[1];
29
+ var _r = useState(null); _r[0]; var setLastCaptureMeta = _r[1];
30
+ var _s = useState(null), maskRect = _s[0], setMaskRect = _s[1];
28
31
  var countdownIntervalRef = useRef(null);
29
32
  var detectionHandlerRef = useRef(null);
30
33
  var flashTimeoutRef = useRef(null);
@@ -63,7 +66,7 @@ var Photo = function (_a) {
63
66
  detectionHandlerRef.current.stop();
64
67
  detectionHandlerRef.current = null;
65
68
  }
66
- documentDetectionService.stopDocumentDetection();
69
+ documentEdgeDetectionService.stopDocumentDetection();
67
70
  }, []);
68
71
  var captureDocument = useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
69
72
  var video, cropArea, videoRect, videoAspect, displayAspect, displayedWidth, displayedHeight, offsetX, offsetY, scaleX, scaleY, cropX, cropY, cropWidth, cropHeight, result, error_1;
@@ -125,6 +128,13 @@ var Photo = function (_a) {
125
128
  }
126
129
  setCaptureError(null);
127
130
  setIsDetecting(false);
131
+ // Reste vrai jusqu'au démontage du composant (changement d'étape côté
132
+ // DocumentCheck) en cas de succès : le traitement post-capture côté
133
+ // parent (redimensionnement, conversion) continue pendant que ce
134
+ // composant est encore affiché, donc l'overlay doit rester visible
135
+ // jusqu'à ce que l'écran change réellement — jamais un écran figé sans
136
+ // feedback.
137
+ setIsProcessing(true);
128
138
  triggerCaptureFeedback();
129
139
  _a.label = 1;
130
140
  case 1:
@@ -133,6 +143,9 @@ var Photo = function (_a) {
133
143
  facingMode: facingMode,
134
144
  format: "jpeg",
135
145
  jpegQuality: 0.95,
146
+ // Copy the current video frame synchronously: takePhoto() can delay the
147
+ // shutter (or fall back to a later frame after an asynchronous failure).
148
+ preferImageCapture: false,
136
149
  })];
137
150
  case 2:
138
151
  result = _a.sent();
@@ -152,6 +165,7 @@ var Photo = function (_a) {
152
165
  console.error("Document capture failed", error_1);
153
166
  setCaptureError(t("id_check.photo.capture_failed", "La capture a échoué. Veuillez réessayer."));
154
167
  setIsDetecting(true);
168
+ setIsProcessing(false);
155
169
  throw error_1;
156
170
  case 4: return [2 /*return*/];
157
171
  }
@@ -179,11 +193,16 @@ var Photo = function (_a) {
179
193
  }, 100);
180
194
  }, [captureDocument, isCountingDown]);
181
195
  var handleDetectionChange = useCallback(function (result) {
182
- setDocumentDetected(result.hasDocument);
196
+ // isStable (pas juste hasDocument) pilote le feedback visuel et
197
+ // l'auto-capture pour éviter le clignotement : une frame isolée où le
198
+ // document "apparaît" ne suffit pas, il faut plusieurs détections
199
+ // consécutives cohérentes.
200
+ setDocumentDetected(result.hasDocument && result.isStable);
201
+ setQualityHint(result.hint);
183
202
  if (!automaticCapture) {
184
203
  return;
185
204
  }
186
- if (result.hasDocument) {
205
+ if (result.hasDocument && result.isStable) {
187
206
  startCountdown();
188
207
  }
189
208
  else {
@@ -202,6 +221,7 @@ var Photo = function (_a) {
202
221
  switch (_a.label) {
203
222
  case 0:
204
223
  setCameraError(null);
224
+ setIsInitializing(true);
205
225
  return [4 /*yield*/, cameraService.startCamera(videoRef.current, {
206
226
  facingMode: facingMode,
207
227
  idealResolution: { width: 4096, height: 3072 },
@@ -211,6 +231,7 @@ var Photo = function (_a) {
211
231
  result = _a.sent();
212
232
  if (isCancelled)
213
233
  return [2 /*return*/];
234
+ setIsInitializing(false);
214
235
  if (result.success) {
215
236
  setLastCaptureMeta(null);
216
237
  // Detection also runs in manual mode: it only drives the visual
@@ -245,8 +266,8 @@ var Photo = function (_a) {
245
266
  return;
246
267
  }
247
268
  var cancelled = false;
248
- documentDetectionService
249
- .startDocumentDetection(videoRef.current, function (result) {
269
+ documentEdgeDetectionService
270
+ .startDocumentDetection(videoRef.current, null, function (result) {
250
271
  if (!cancelled) {
251
272
  handleDetectionChange(result);
252
273
  }
@@ -279,6 +300,7 @@ var Photo = function (_a) {
279
300
  cancelCaptureTimer();
280
301
  setCaptureError(null);
281
302
  setIsDetecting(false);
303
+ setIsInitializing(true);
282
304
  stopDetection();
283
305
  cameraService.stopCamera();
284
306
  cameraService
@@ -288,6 +310,7 @@ var Photo = function (_a) {
288
310
  preferImageCapture: true,
289
311
  })
290
312
  .then(function (result) {
313
+ setIsInitializing(false);
291
314
  if (result.success) {
292
315
  setIsDetecting(true);
293
316
  }
@@ -297,22 +320,30 @@ var Photo = function (_a) {
297
320
  });
298
321
  };
299
322
  var handleManualCapture = function () {
323
+ if (isProcessing) {
324
+ return;
325
+ }
300
326
  clearCountdown();
301
327
  captureDocument().catch(function () {
302
328
  // captureDocument already logs and sets error state
303
329
  });
304
330
  };
331
+ var statusMessage = qualityHint === "too_dark"
332
+ ? t("id_check.photo.hint.too_dark", "Trop sombre, cherchez plus de lumière")
333
+ : qualityHint === "too_bright"
334
+ ? t("id_check.photo.hint.too_bright", "Trop de reflets, évitez la lumière directe")
335
+ : automaticCapture
336
+ ? t("id_check.photo.automatic_instruction", "Capture automatique active ou appuyez sur le bouton")
337
+ : t("id_check.photo.manual_instruction", "Appuyez sur le bouton pour capturer");
305
338
  return (jsxs("div", { className: "flex flex-col", style: {
306
339
  position: isMobile ? "fixed" : "relative",
307
340
  inset: isMobile ? 0 : "auto",
308
341
  zIndex: isMobile ? 50 : "auto",
309
342
  height: "100%",
310
343
  width: "100%",
311
- }, children: [jsx("div", { className: "flex-1 relative overflow-hidden bg-black", children: cameraError ? (jsx("div", { className: "flex items-center justify-center h-full px-4 py-6", children: jsx(CameraError, { errorMessage: cameraError, onRetry: handleRetry }) })) : (jsxs(Fragment, { children: [jsx("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true, className: "absolute inset-0 w-full h-full object-cover z-0 bg-black ".concat(facingMode === "user" ? "scale-x-[-1]" : "") }), jsx("div", { className: "absolute top-4 left-1/2 transform -translate-x-1/2 z-50", children: jsx("span", { className: "text-white z-50 text-sm font-semibold drop-shadow-lg", children: automaticCapture ? (jsx("span", { className: "animate-pulse", children: t("id_check.photo.mode_autocapture", "Autocapture activée") })) : (jsx("span", { className: "bg-orange-500 px-2 py-1 rounded hidden", children: t("id_check.photo.mode_manual", "Mode manuel") })) }) }), jsx(CameraMask, { isDetecting: isDetecting, isPortrait: isPortrait, facingMode: facingMode, isCountingDown: isCountingDown, countdown: countdown, maskType: maskType, documentDetected: documentDetected, onMaskRectChange: setMaskRect }), jsx("div", { className: "absolute bottom-20 left-0 right-0 z-20 pointer-events-none", children: jsx("div", { className: "text-center px-4", children: jsx("div", { className: "bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block", children: t("id_check.photo.position_document", "Posez le document à plat ou tenez-le dans le cadre") }) }) }), jsx(OrientationToggle, { onCameraToggle: toggleCamera }), showCaptureFlash && (jsx("div", { "data-testid": "capture-flash", className: "absolute inset-0 z-40 bg-white pointer-events-none animate-pulse" }))] })) }), jsx("div", { className: "relative z-20 bg-black bg-opacity-80 p-4", children: jsxs("div", { className: "flex flex-col items-center space-y-4", children: [jsx("button", { onClick: handleManualCapture, className: "w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all duration-150 bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer ".concat(showCaptureFlash ? "scale-90 ring-4 ring-[#11E5C5]" : ""), children: jsx("div", { className: "w-8 h-8 bg-white rounded-full" }) }), jsxs("div", { className: "text-white text-center text-sm", children: [jsxs("div", { className: "flex items-center justify-center space-x-2", children: [jsx("div", { className: "w-2 h-2 rounded-full ".concat(automaticCapture
344
+ }, children: [jsx("div", { className: "flex-1 relative overflow-hidden bg-black", children: cameraError ? (jsx("div", { className: "flex items-center justify-center h-full px-4 py-6", children: jsx(CameraError, { errorMessage: cameraError, onRetry: handleRetry }) })) : (jsxs(Fragment, { children: [isInitializing && (jsxs("div", { "data-testid": "camera-initializing", className: "absolute inset-0 z-30 flex flex-col items-center justify-center gap-3 bg-black", children: [jsx("div", { className: "w-10 h-10 border-4 border-white border-t-transparent rounded-full animate-spin" }), jsx("span", { className: "text-white text-sm", children: t("id_check.photo.initializing", "Ouverture de la caméra…") })] })), isProcessing && (jsxs("div", { "data-testid": "camera-processing", className: "absolute inset-0 z-30 flex flex-col items-center justify-center gap-3 bg-black bg-opacity-70", children: [jsx("div", { className: "w-10 h-10 border-4 border-white border-t-transparent rounded-full animate-spin" }), jsx("span", { className: "text-white text-sm", children: t("id_check.photo.processing", "Traitement de l'image…") })] })), jsx("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true, className: "absolute inset-0 w-full h-full object-cover z-0 bg-black ".concat(facingMode === "user" ? "scale-x-[-1]" : "") }), jsx("div", { className: "absolute top-4 left-1/2 transform -translate-x-1/2 z-50", children: jsx("span", { className: "text-white z-50 text-sm font-semibold drop-shadow-lg", children: automaticCapture ? (jsx("span", { className: "animate-pulse", children: t("id_check.photo.mode_autocapture", "Autocapture activée") })) : (jsx("span", { className: "bg-orange-500 px-2 py-1 rounded hidden", children: t("id_check.photo.mode_manual", "Mode manuel") })) }) }), jsx(CameraMask, { isDetecting: isDetecting, isPortrait: isPortrait, facingMode: facingMode, isCountingDown: isCountingDown, countdown: countdown, maskType: maskType, documentDetected: documentDetected, qualityHint: qualityHint, onMaskRectChange: setMaskRect }), jsx("div", { className: "absolute bottom-20 left-0 right-0 z-20 pointer-events-none", children: jsx("div", { className: "text-center px-4", children: jsx("div", { className: "bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block", children: t("id_check.photo.position_document", "Posez le document à plat ou tenez-le dans le cadre") }) }) }), jsx(OrientationToggle, { onCameraToggle: toggleCamera }), showCaptureFlash && (jsx("div", { "data-testid": "capture-flash", className: "absolute inset-0 z-40 bg-white pointer-events-none animate-pulse" }))] })) }), jsx("div", { className: "relative z-20 bg-black bg-opacity-80 p-4", children: jsxs("div", { className: "flex flex-col items-center space-y-4", children: [jsx("button", { onClick: handleManualCapture, className: "w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all duration-150 bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer ".concat(showCaptureFlash ? "scale-90 ring-4 ring-[#11E5C5]" : ""), children: jsx("div", { className: "w-8 h-8 bg-white rounded-full" }) }), jsxs("div", { className: "text-white text-center text-sm", children: [jsxs("div", { className: "flex items-center justify-center space-x-2", children: [jsx("div", { className: "w-2 h-2 rounded-full ".concat(automaticCapture
312
345
  ? "bg-[#11E5C5] animate-pulse"
313
- : "bg-orange-500") }), jsx("span", { children: automaticCapture
314
- ? t("id_check.photo.automatic_instruction", "Capture automatique active ou appuyez sur le bouton")
315
- : t("id_check.photo.manual_instruction", "Appuyez sur le bouton pour capturer") })] }), captureError && (jsx("p", { className: "text-red-400 text-xs mt-2 text-center", children: captureError }))] })] }) })] }));
346
+ : "bg-orange-500") }), jsx("span", { children: statusMessage })] }), captureError && (jsx("p", { className: "text-red-400 text-xs mt-2 text-center", children: captureError }))] })] }) })] }));
316
347
  };
317
348
 
318
349
  export { Photo as default };
@@ -1 +1 @@
1
- {"version":3,"file":"Photo.js","sources":["../../../../../src/components/id-check/Photo.tsx"],"sourcesContent":["import { useRef, useState, useEffect, useCallback } from \"react\";\nimport type { CameraFacingMode } from \"../../types/camera\";\nimport {\n cameraService,\n type CaptureDocumentResult,\n} from \"../../services/cameraService\";\nimport {\n documentDetectionService,\n type DocumentDetectionResult,\n} from \"../../services/documentDetectionService\";\nimport CameraError from \"./CameraError\";\nimport CameraMask from \"./CameraMask\";\nimport OrientationToggle from \"./OrientationToggle\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport useIsMobile from \"../../hooks/useIsMobile\";\n\ninterface PhotoProps {\n onCapture: (image: string) => void;\n automaticCapture?: boolean; // Controls whether automatic capture is enabled\n maskType?: \"id\" | \"document\";\n}\n\nconst Photo: React.FC<PhotoProps> = ({\n onCapture,\n automaticCapture = false,\n maskType = \"id\",\n}) => {\n const isMobile = useIsMobile(768);\n const videoRef = useRef<HTMLVideoElement>(null);\n const [isDetecting, setIsDetecting] = useState(false);\n const [facingMode, setFacingMode] = useState<CameraFacingMode>(\"environment\");\n const [cameraError, setCameraError] = useState<string | null>(null);\n const [isPortrait, setIsPortrait] = useState(\n window.matchMedia(\"(orientation: portrait)\").matches\n );\n const [isCountingDown, setIsCountingDown] = useState(false);\n const [countdown, setCountdown] = useState(0);\n const [documentDetected, setDocumentDetected] = useState(false);\n const [captureError, setCaptureError] = useState<string | null>(null);\n const [showCaptureFlash, setShowCaptureFlash] = useState(false);\n const { t } = useI18n();\n const [lastCaptureMeta, setLastCaptureMeta] =\n useState<CaptureDocumentResult | null>(null);\n const [maskRect, setMaskRect] = useState<{\n left: number;\n top: number;\n width: number;\n height: number;\n } | null>(null);\n\n const countdownIntervalRef = useRef<number | null>(null);\n const detectionHandlerRef = useRef<{ stop: () => void } | null>(null);\n const flashTimeoutRef = useRef<number | null>(null);\n\n const CAPTURE_FLASH_DURATION_MS = 300;\n\n const triggerCaptureFeedback = useCallback(() => {\n if (flashTimeoutRef.current) {\n clearTimeout(flashTimeoutRef.current);\n }\n setShowCaptureFlash(true);\n flashTimeoutRef.current = window.setTimeout(() => {\n setShowCaptureFlash(false);\n flashTimeoutRef.current = null;\n }, CAPTURE_FLASH_DURATION_MS);\n }, []);\n\n const CAPTURE_COUNTDOWN_SECONDS = 3;\n\n const clearCountdown = useCallback(() => {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n setCountdown(0);\n }, []);\n\n useEffect(() => {\n const handleOrientationChange = () => {\n setIsPortrait(window.matchMedia(\"(orientation: portrait)\").matches);\n };\n\n const mediaQuery = window.matchMedia(\"(orientation: portrait)\");\n mediaQuery.addEventListener(\"change\", handleOrientationChange);\n\n return () => {\n mediaQuery.removeEventListener(\"change\", handleOrientationChange);\n };\n }, []);\n\n const stopDetection = useCallback(() => {\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n documentDetectionService.stopDocumentDetection();\n }, []);\n\n const captureDocument = useCallback(async () => {\n if (!videoRef.current) {\n throw new Error(t(\"id_check.photo.errors.video_unavailable\", \"Le flux vidéo n'est pas disponible\"));\n }\n\n const video = videoRef.current;\n if (!video.videoWidth || !video.videoHeight) {\n throw new Error(\n t(\n \"id_check.photo.errors.video_dimensions_unavailable\",\n \"Dimensions vidéo indisponibles pour la capture\"\n )\n );\n }\n\n // Calculate crop area from mask if available\n let cropArea = null;\n if (maskRect) {\n const videoRect = video.getBoundingClientRect();\n\n // Calculate the actual displayed video dimensions accounting for object-fit: contain\n // Calculate the actual displayed video dimensions accounting for object-fit: cover\n const videoAspect = video.videoWidth / video.videoHeight;\n const displayAspect = videoRect.width / videoRect.height;\n\n let displayedWidth, displayedHeight, offsetX, offsetY;\n\n if (videoAspect > displayAspect) {\n // Video is wider than container - scaled to match height, sides cropped\n displayedHeight = videoRect.height;\n displayedWidth = videoRect.height * videoAspect;\n offsetY = 0;\n offsetX = (videoRect.width - displayedWidth) / 2;\n } else {\n // Video is taller than container - scaled to match width, top/bottom cropped\n displayedWidth = videoRect.width;\n displayedHeight = videoRect.width / videoAspect;\n offsetX = 0;\n offsetY = (videoRect.height - displayedHeight) / 2;\n }\n\n // Calculate the scale between actual displayed video and real video dimensions\n const scaleX = video.videoWidth / displayedWidth;\n const scaleY = video.videoHeight / displayedHeight;\n\n // Convert mask coordinates from screen space to video space\n // Account for video element offset and displayed video offset\n const cropX = (maskRect.left - videoRect.left - offsetX) * scaleX;\n const cropY = (maskRect.top - videoRect.top - offsetY) * scaleY;\n const cropWidth = maskRect.width * scaleX;\n const cropHeight = maskRect.height * scaleY;\n\n // Ensure crop area is within video bounds\n cropArea = {\n x: Math.max(0, Math.round(cropX)),\n y: Math.max(0, Math.round(cropY)),\n width: Math.min(video.videoWidth - Math.max(0, cropX), Math.round(cropWidth)),\n height: Math.min(video.videoHeight - Math.max(0, cropY), Math.round(cropHeight)),\n };\n\n console.debug(\"[Photo] Calculated crop area from mask\", {\n maskRect,\n videoRect: { left: videoRect.left, top: videoRect.top, width: videoRect.width, height: videoRect.height },\n videoDimensions: { width: video.videoWidth, height: video.videoHeight },\n displayedDimensions: { width: displayedWidth, height: displayedHeight },\n offset: { x: offsetX, y: offsetY },\n scale: { x: scaleX, y: scaleY },\n cropArea,\n });\n } else {\n console.debug(\"[Photo] No mask rect available, capturing full frame\");\n }\n\n setCaptureError(null);\n setIsDetecting(false);\n triggerCaptureFeedback();\n\n try {\n const result = await cameraService.captureDocument(video, cropArea, {\n facingMode,\n format: \"jpeg\",\n jpegQuality: 0.95,\n });\n\n setLastCaptureMeta(result);\n stopDetection();\n setDocumentDetected(false);\n\n console.debug(\"Document captured\", {\n method: result.method,\n analysis: result.analysis,\n source: result.sourceDimensions,\n crop: result.cropDimensions,\n });\n\n onCapture(result.dataUrl);\n } catch (error) {\n console.error(\"Document capture failed\", error);\n setCaptureError(t(\"id_check.photo.capture_failed\", \"La capture a échoué. Veuillez réessayer.\"));\n setIsDetecting(true);\n throw error;\n }\n }, [facingMode, onCapture, stopDetection, maskRect, t, triggerCaptureFeedback]);\n\n const startCountdown = useCallback(() => {\n if (isCountingDown) return;\n\n setIsCountingDown(true);\n setCountdown(CAPTURE_COUNTDOWN_SECONDS);\n\n let timeLeft = CAPTURE_COUNTDOWN_SECONDS;\n countdownIntervalRef.current = window.setInterval(() => {\n timeLeft = Math.max(0, timeLeft - 0.1);\n setCountdown(parseFloat(timeLeft.toFixed(1)));\n\n if (timeLeft <= 0.1) {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n\n captureDocument().catch(() => {\n // Error is handled inside captureDocument, but keep the promise chain quiet\n });\n }\n }, 100);\n }, [captureDocument, isCountingDown]);\n\n const handleDetectionChange = useCallback(\n (result: DocumentDetectionResult) => {\n setDocumentDetected(result.hasDocument);\n\n if (!automaticCapture) {\n return;\n }\n\n if (result.hasDocument) {\n startCountdown();\n } else {\n clearCountdown();\n }\n },\n [automaticCapture, clearCountdown, startCountdown]\n );\n\n const cancelCaptureTimer = useCallback(() => {\n clearCountdown();\n setDocumentDetected(false);\n }, [clearCountdown]);\n\n useEffect(() => {\n let isCancelled = false;\n\n const initCamera = async () => {\n setCameraError(null);\n const result = await cameraService.startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n });\n\n if (isCancelled) return;\n\n if (result.success) {\n setLastCaptureMeta(null);\n // Detection also runs in manual mode: it only drives the visual\n // feedback on the mask (documentDetected), it never starts the\n // auto-capture countdown unless automaticCapture is true (see\n // handleDetectionChange).\n setIsDetecting(true);\n } else if (result.error) {\n setCameraError(result.error);\n setIsDetecting(false);\n }\n };\n\n initCamera();\n\n return () => {\n isCancelled = true;\n clearCountdown();\n stopDetection();\n cameraService.stopCamera();\n setIsDetecting(false);\n if (flashTimeoutRef.current) {\n clearTimeout(flashTimeoutRef.current);\n flashTimeoutRef.current = null;\n }\n };\n }, [facingMode, clearCountdown, stopDetection]);\n\n useEffect(() => {\n if (!isDetecting || !videoRef.current) {\n return;\n }\n\n let cancelled = false;\n\n documentDetectionService\n .startDocumentDetection(videoRef.current, (result) => {\n if (!cancelled) {\n handleDetectionChange(result);\n }\n })\n .then((handler) => {\n if (!cancelled) {\n detectionHandlerRef.current = handler;\n }\n })\n .catch((error) => {\n console.error(\"[DocumentDetection] Unable to start automatic capture:\", error);\n if (!cancelled) {\n setIsDetecting(false);\n }\n });\n\n return () => {\n cancelled = true;\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n };\n }, [handleDetectionChange, isDetecting]);\n\n const toggleCamera = () => {\n setFacingMode((prev) => (prev === \"environment\" ? \"user\" : \"environment\"));\n cancelCaptureTimer();\n };\n\n const handleRetry = () => {\n setCameraError(null);\n cancelCaptureTimer();\n setCaptureError(null);\n setIsDetecting(false);\n stopDetection();\n cameraService.stopCamera();\n\n cameraService\n .startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n })\n .then((result) => {\n if (result.success) {\n setIsDetecting(true);\n } else if (result.error) {\n setCameraError(result.error);\n }\n });\n };\n const handleManualCapture = () => {\n clearCountdown();\n captureDocument().catch(() => {\n // captureDocument already logs and sets error state\n });\n };\n\n return (\n <div\n className=\"flex flex-col\"\n style={{\n position: isMobile ? \"fixed\" : \"relative\",\n inset: isMobile ? 0 : \"auto\",\n zIndex: isMobile ? 50 : \"auto\",\n height: \"100%\",\n width: \"100%\",\n }}\n >\n {/* Camera content area */}\n <div className=\"flex-1 relative overflow-hidden bg-black\">\n {cameraError ? (\n <div className=\"flex items-center justify-center h-full px-4 py-6\">\n <CameraError errorMessage={cameraError} onRetry={handleRetry} />\n </div>\n ) : (\n <>\n {/* Livestream of the camera*/}\n <video\n ref={videoRef}\n autoPlay\n playsInline\n muted\n className={`absolute inset-0 w-full h-full object-cover z-0 bg-black ${facingMode === \"user\" ? \"scale-x-[-1]\" : \"\"\n }`}\n />\n {/* Capture mode indicator */}\n <div className=\"absolute top-4 left-1/2 transform -translate-x-1/2 z-50\">\n <span className=\"text-white z-50 text-sm font-semibold drop-shadow-lg\">\n {automaticCapture ? (\n <span className=\"animate-pulse\">{t(\"id_check.photo.mode_autocapture\", \"Autocapture activée\")}</span>\n ) : (\n <span className=\"bg-orange-500 px-2 py-1 rounded hidden\">{t(\"id_check.photo.mode_manual\", \"Mode manuel\")}</span>\n )}\n </span>\n </div>\n {/* Mask */}\n <CameraMask\n isDetecting={isDetecting}\n isPortrait={isPortrait}\n facingMode={facingMode}\n isCountingDown={isCountingDown}\n countdown={countdown}\n maskType={maskType}\n documentDetected={documentDetected}\n onMaskRectChange={setMaskRect}\n />\n {/* Manual capture instructions */}\n <div className=\"absolute bottom-20 left-0 right-0 z-20 pointer-events-none\">\n <div className=\"text-center px-4\">\n <div className=\"bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block\">\n {t(\"id_check.photo.position_document\", \"Posez le document à plat ou tenez-le dans le cadre\")}\n </div>\n </div>\n </div>\n {/* Button to change orientation */}\n <OrientationToggle onCameraToggle={toggleCamera} />\n {/* Capture confirmation flash - fires for manual and auto capture alike */}\n {showCaptureFlash && (\n <div\n data-testid=\"capture-flash\"\n className=\"absolute inset-0 z-40 bg-white pointer-events-none animate-pulse\"\n />\n )}\n </>\n )}\n </div>\n\n {/* Controls at the bottom */}\n <div className=\"relative z-20 bg-black bg-opacity-80 p-4\">\n <div className=\"flex flex-col items-center space-y-4\">\n {/* Manual capture button - always available */}\n <button\n onClick={handleManualCapture}\n className={`w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all duration-150 bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer ${showCaptureFlash ? \"scale-90 ring-4 ring-[#11E5C5]\" : \"\"\n }`}\n >\n <div className=\"w-8 h-8 bg-white rounded-full\"></div>\n </button>\n\n {/* Status message */}\n <div className=\"text-white text-center text-sm\">\n <div className=\"flex items-center justify-center space-x-2\">\n <div\n className={`w-2 h-2 rounded-full ${automaticCapture\n ? \"bg-[#11E5C5] animate-pulse\"\n : \"bg-orange-500\"\n }`}\n ></div>\n <span>\n {automaticCapture\n ? t(\n \"id_check.photo.automatic_instruction\",\n \"Capture automatique active ou appuyez sur le bouton\"\n )\n : t(\n \"id_check.photo.manual_instruction\",\n \"Appuyez sur le bouton pour capturer\"\n )}\n </span>\n </div>\n {captureError && (\n <p className=\"text-red-400 text-xs mt-2 text-center\">\n {captureError}\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default Photo;\n"],"names":["_jsxs","_jsx","_Fragment"],"mappings":";;;;;;;;;;;AAsBA,IAAM,KAAK,GAAyB,UAAC,EAIpC,EAAA;AAHC,IAAA,IAAA,SAAS,GAAA,EAAA,CAAA,SAAA,EACT,EAAA,GAAA,EAAA,CAAA,gBAAwB,EAAxB,gBAAgB,GAAA,EAAA,KAAA,MAAA,GAAG,KAAK,GAAA,EAAA,EACxB,EAAA,GAAA,EAAA,CAAA,QAAe,EAAf,QAAQ,GAAA,EAAA,KAAA,MAAA,GAAG,IAAI,GAAA,EAAA;AAEf,IAAA,IAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC;AACjC,IAAA,IAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC;IACzC,IAAA,EAAA,GAAgC,QAAQ,CAAC,KAAK,CAAC,EAA9C,WAAW,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,cAAc,GAAA,EAAA,CAAA,CAAA,CAAmB;IAC/C,IAAA,EAAA,GAA8B,QAAQ,CAAmB,aAAa,CAAC,EAAtE,UAAU,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,aAAa,GAAA,EAAA,CAAA,CAAA,CAA6C;IACvE,IAAA,EAAA,GAAgC,QAAQ,CAAgB,IAAI,CAAC,EAA5D,WAAW,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,cAAc,GAAA,EAAA,CAAA,CAAA,CAAiC;AAC7D,IAAA,IAAA,KAA8B,QAAQ,CAC1C,MAAM,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC,OAAO,CACrD,EAFM,UAAU,QAAA,EAAE,aAAa,QAE/B;IACK,IAAA,EAAA,GAAsC,QAAQ,CAAC,KAAK,CAAC,EAApD,cAAc,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,iBAAiB,GAAA,EAAA,CAAA,CAAA,CAAmB;IACrD,IAAA,EAAA,GAA4B,QAAQ,CAAC,CAAC,CAAC,EAAtC,SAAS,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,YAAY,GAAA,EAAA,CAAA,CAAA,CAAe;IACvC,IAAA,EAAA,GAA0C,QAAQ,CAAC,KAAK,CAAC,EAAxD,gBAAgB,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,mBAAmB,GAAA,EAAA,CAAA,CAAA,CAAmB;IACzD,IAAA,EAAA,GAAkC,QAAQ,CAAgB,IAAI,CAAC,EAA9D,YAAY,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,eAAe,GAAA,EAAA,CAAA,CAAA,CAAiC;IAC/D,IAAA,EAAA,GAA0C,QAAQ,CAAC,KAAK,CAAC,EAAxD,gBAAgB,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,mBAAmB,GAAA,EAAA,CAAA,CAAA,CAAmB;AACvD,IAAA,IAAA,CAAC,GAAK,OAAO,EAAE,EAAd;IACH,IAAA,EAAA,GACJ,QAAQ,CAA+B,IAAI,CAAC,CAAA,CADxB,EAAA,CAAA,CAAA,CAAA,CAAA,KAAE,kBAAkB,GAAA,EAAA,CAAA,CAAA;IAEpC,IAAA,EAAA,GAA0B,QAAQ,CAK9B,IAAI,CAAC,EALR,QAAQ,GAAA,EAAA,CAAA,CAAA,CAAA,EAAE,WAAW,GAAA,EAAA,CAAA,CAAA,CAKb;AAEf,IAAA,IAAM,oBAAoB,GAAG,MAAM,CAAgB,IAAI,CAAC;AACxD,IAAA,IAAM,mBAAmB,GAAG,MAAM,CAA8B,IAAI,CAAC;AACrE,IAAA,IAAM,eAAe,GAAG,MAAM,CAAgB,IAAI,CAAC;IAEnD,IAAM,yBAAyB,GAAG,GAAG;IAErC,IAAM,sBAAsB,GAAG,WAAW,CAAC,YAAA;AACzC,QAAA,IAAI,eAAe,CAAC,OAAO,EAAE;AAC3B,YAAA,YAAY,CAAC,eAAe,CAAC,OAAO,CAAC;QACvC;QACA,mBAAmB,CAAC,IAAI,CAAC;AACzB,QAAA,eAAe,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,YAAA;YAC1C,mBAAmB,CAAC,KAAK,CAAC;AAC1B,YAAA,eAAe,CAAC,OAAO,GAAG,IAAI;QAChC,CAAC,EAAE,yBAAyB,CAAC;IAC/B,CAAC,EAAE,EAAE,CAAC;IAEN,IAAM,yBAAyB,GAAG,CAAC;IAEnC,IAAM,cAAc,GAAG,WAAW,CAAC,YAAA;AACjC,QAAA,IAAI,oBAAoB,CAAC,OAAO,EAAE;AAChC,YAAA,aAAa,CAAC,oBAAoB,CAAC,OAAO,CAAC;AAC3C,YAAA,oBAAoB,CAAC,OAAO,GAAG,IAAI;QACrC;QACA,iBAAiB,CAAC,KAAK,CAAC;QACxB,YAAY,CAAC,CAAC,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,SAAS,CAAC,YAAA;AACR,QAAA,IAAM,uBAAuB,GAAG,YAAA;YAC9B,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC,OAAO,CAAC;AACrE,QAAA,CAAC;QAED,IAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,yBAAyB,CAAC;AAC/D,QAAA,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,uBAAuB,CAAC;QAE9D,OAAO,YAAA;AACL,YAAA,UAAU,CAAC,mBAAmB,CAAC,QAAQ,EAAE,uBAAuB,CAAC;AACnE,QAAA,CAAC;IACH,CAAC,EAAE,EAAE,CAAC;IAEN,IAAM,aAAa,GAAG,WAAW,CAAC,YAAA;AAChC,QAAA,IAAI,mBAAmB,CAAC,OAAO,EAAE;AAC/B,YAAA,mBAAmB,CAAC,OAAO,CAAC,IAAI,EAAE;AAClC,YAAA,mBAAmB,CAAC,OAAO,GAAG,IAAI;QACpC;QACA,wBAAwB,CAAC,qBAAqB,EAAE;IAClD,CAAC,EAAE,EAAE,CAAC;IAEN,IAAM,eAAe,GAAG,WAAW,CAAC,YAAA,EAAA,OAAA,SAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;AAClC,oBAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;wBACrB,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,yCAAyC,EAAE,oCAAoC,CAAC,CAAC;oBACrG;AAEM,oBAAA,KAAK,GAAG,QAAQ,CAAC,OAAO;oBAC9B,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;wBAC3C,MAAM,IAAI,KAAK,CACb,CAAC,CACC,oDAAoD,EACpD,gDAAgD,CACjD,CACF;oBACH;oBAGI,QAAQ,GAAG,IAAI;oBACnB,IAAI,QAAQ,EAAE;AACN,wBAAA,SAAS,GAAG,KAAK,CAAC,qBAAqB,EAAE;wBAIzC,WAAW,GAAG,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,WAAW;wBAClD,aAAa,GAAG,SAAS,CAAC,KAAK,GAAG,SAAS,CAAC,MAAM;wBAEpD,cAAc,GAAA,MAAA,EAAE,eAAe,GAAA,MAAA,EAAE,OAAO,GAAA,MAAA,EAAE,OAAO,GAAA,MAAA;AAErD,wBAAA,IAAI,WAAW,GAAG,aAAa,EAAE;;AAE/B,4BAAA,eAAe,GAAG,SAAS,CAAC,MAAM;AAClC,4BAAA,cAAc,GAAG,SAAS,CAAC,MAAM,GAAG,WAAW;4BAC/C,OAAO,GAAG,CAAC;4BACX,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,cAAc,IAAI,CAAC;wBAClD;6BAAO;;AAEL,4BAAA,cAAc,GAAG,SAAS,CAAC,KAAK;AAChC,4BAAA,eAAe,GAAG,SAAS,CAAC,KAAK,GAAG,WAAW;4BAC/C,OAAO,GAAG,CAAC;4BACX,OAAO,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,eAAe,IAAI,CAAC;wBACpD;AAGM,wBAAA,MAAM,GAAG,KAAK,CAAC,UAAU,GAAG,cAAc;AAC1C,wBAAA,MAAM,GAAG,KAAK,CAAC,WAAW,GAAG,eAAe;AAI5C,wBAAA,KAAK,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,GAAG,OAAO,IAAI,MAAM;AAC3D,wBAAA,KAAK,GAAG,CAAC,QAAQ,CAAC,GAAG,GAAG,SAAS,CAAC,GAAG,GAAG,OAAO,IAAI,MAAM;AACzD,wBAAA,SAAS,GAAG,QAAQ,CAAC,KAAK,GAAG,MAAM;AACnC,wBAAA,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,MAAM;;AAG3C,wBAAA,QAAQ,GAAG;AACT,4BAAA,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACjC,4BAAA,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;4BACjC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;4BAC7E,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;yBACjF;AAED,wBAAA,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE;AACtD,4BAAA,QAAQ,EAAA,QAAA;4BACR,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE;AACzG,4BAAA,eAAe,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,WAAW,EAAE;4BACvE,mBAAmB,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE;4BACvE,MAAM,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE;4BAClC,KAAK,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE;AAC/B,4BAAA,QAAQ,EAAA,QAAA;AACT,yBAAA,CAAC;oBACJ;yBAAO;AACL,wBAAA,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC;oBACvE;oBAEA,eAAe,CAAC,IAAI,CAAC;oBACrB,cAAc,CAAC,KAAK,CAAC;AACrB,oBAAA,sBAAsB,EAAE;;;;AAGP,oBAAA,OAAA,CAAA,CAAA,YAAM,aAAa,CAAC,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE;AAClE,4BAAA,UAAU,EAAA,UAAA;AACV,4BAAA,MAAM,EAAE,MAAM;AACd,4BAAA,WAAW,EAAE,IAAI;AAClB,yBAAA,CAAC,CAAA;;AAJI,oBAAA,MAAM,GAAG,EAAA,CAAA,IAAA,EAIb;oBAEF,kBAAkB,CAAC,MAAM,CAAC;AAC1B,oBAAA,aAAa,EAAE;oBACf,mBAAmB,CAAC,KAAK,CAAC;AAE1B,oBAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE;wBACjC,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,MAAM,EAAE,MAAM,CAAC,gBAAgB;wBAC/B,IAAI,EAAE,MAAM,CAAC,cAAc;AAC5B,qBAAA,CAAC;AAEF,oBAAA,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;;;;AAEzB,oBAAA,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,OAAK,CAAC;oBAC/C,eAAe,CAAC,CAAC,CAAC,+BAA+B,EAAE,0CAA0C,CAAC,CAAC;oBAC/F,cAAc,CAAC,IAAI,CAAC;AACpB,oBAAA,MAAM,OAAK;;;;AAEd,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,EAAE,sBAAsB,CAAC,CAAC;IAE/E,IAAM,cAAc,GAAG,WAAW,CAAC,YAAA;AACjC,QAAA,IAAI,cAAc;YAAE;QAEpB,iBAAiB,CAAC,IAAI,CAAC;QACvB,YAAY,CAAC,yBAAyB,CAAC;QAEvC,IAAI,QAAQ,GAAG,yBAAyB;AACxC,QAAA,oBAAoB,CAAC,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,YAAA;YAChD,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC;YACtC,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7C,YAAA,IAAI,QAAQ,IAAI,GAAG,EAAE;AACnB,gBAAA,IAAI,oBAAoB,CAAC,OAAO,EAAE;AAChC,oBAAA,aAAa,CAAC,oBAAoB,CAAC,OAAO,CAAC;AAC3C,oBAAA,oBAAoB,CAAC,OAAO,GAAG,IAAI;gBACrC;gBACA,iBAAiB,CAAC,KAAK,CAAC;gBAExB,eAAe,EAAE,CAAC,KAAK,CAAC,YAAA;;AAExB,gBAAA,CAAC,CAAC;YACJ;QACF,CAAC,EAAE,GAAG,CAAC;AACT,IAAA,CAAC,EAAE,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC;AAErC,IAAA,IAAM,qBAAqB,GAAG,WAAW,CACvC,UAAC,MAA+B,EAAA;AAC9B,QAAA,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC;QAEvC,IAAI,CAAC,gBAAgB,EAAE;YACrB;QACF;AAEA,QAAA,IAAI,MAAM,CAAC,WAAW,EAAE;AACtB,YAAA,cAAc,EAAE;QAClB;aAAO;AACL,YAAA,cAAc,EAAE;QAClB;IACF,CAAC,EACD,CAAC,gBAAgB,EAAE,cAAc,EAAE,cAAc,CAAC,CACnD;IAED,IAAM,kBAAkB,GAAG,WAAW,CAAC,YAAA;AACrC,QAAA,cAAc,EAAE;QAChB,mBAAmB,CAAC,KAAK,CAAC;AAC5B,IAAA,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;AAEpB,IAAA,SAAS,CAAC,YAAA;QACR,IAAI,WAAW,GAAG,KAAK;AAEvB,QAAA,IAAM,UAAU,GAAG,YAAA,EAAA,OAAA,SAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,YAAA;;;;;wBACjB,cAAc,CAAC,IAAI,CAAC;AACL,wBAAA,OAAA,CAAA,CAAA,YAAM,aAAa,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE;AAC/D,gCAAA,UAAU,EAAA,UAAA;gCACV,eAAe,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;AAC9C,gCAAA,kBAAkB,EAAE,IAAI;AACzB,6BAAA,CAAC,CAAA;;AAJI,wBAAA,MAAM,GAAG,EAAA,CAAA,IAAA,EAIb;AAEF,wBAAA,IAAI,WAAW;4BAAE,OAAA,CAAA,CAAA,YAAA;AAEjB,wBAAA,IAAI,MAAM,CAAC,OAAO,EAAE;4BAClB,kBAAkB,CAAC,IAAI,CAAC;;;;;4BAKxB,cAAc,CAAC,IAAI,CAAC;wBACtB;AAAO,6BAAA,IAAI,MAAM,CAAC,KAAK,EAAE;AACvB,4BAAA,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC;4BAC5B,cAAc,CAAC,KAAK,CAAC;wBACvB;;;;aACD;AAED,QAAA,UAAU,EAAE;QAEZ,OAAO,YAAA;YACL,WAAW,GAAG,IAAI;AAClB,YAAA,cAAc,EAAE;AAChB,YAAA,aAAa,EAAE;YACf,aAAa,CAAC,UAAU,EAAE;YAC1B,cAAc,CAAC,KAAK,CAAC;AACrB,YAAA,IAAI,eAAe,CAAC,OAAO,EAAE;AAC3B,gBAAA,YAAY,CAAC,eAAe,CAAC,OAAO,CAAC;AACrC,gBAAA,eAAe,CAAC,OAAO,GAAG,IAAI;YAChC;AACF,QAAA,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,aAAa,CAAC,CAAC;AAE/C,IAAA,SAAS,CAAC,YAAA;QACR,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;YACrC;QACF;QAEA,IAAI,SAAS,GAAG,KAAK;QAErB;AACG,aAAA,sBAAsB,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAC,MAAM,EAAA;YAC/C,IAAI,CAAC,SAAS,EAAE;gBACd,qBAAqB,CAAC,MAAM,CAAC;YAC/B;AACF,QAAA,CAAC;aACA,IAAI,CAAC,UAAC,OAAO,EAAA;YACZ,IAAI,CAAC,SAAS,EAAE;AACd,gBAAA,mBAAmB,CAAC,OAAO,GAAG,OAAO;YACvC;AACF,QAAA,CAAC;aACA,KAAK,CAAC,UAAC,KAAK,EAAA;AACX,YAAA,OAAO,CAAC,KAAK,CAAC,wDAAwD,EAAE,KAAK,CAAC;YAC9E,IAAI,CAAC,SAAS,EAAE;gBACd,cAAc,CAAC,KAAK,CAAC;YACvB;AACF,QAAA,CAAC,CAAC;QAEJ,OAAO,YAAA;YACL,SAAS,GAAG,IAAI;AAChB,YAAA,IAAI,mBAAmB,CAAC,OAAO,EAAE;AAC/B,gBAAA,mBAAmB,CAAC,OAAO,CAAC,IAAI,EAAE;AAClC,gBAAA,mBAAmB,CAAC,OAAO,GAAG,IAAI;YACpC;AACF,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC;AAExC,IAAA,IAAM,YAAY,GAAG,YAAA;QACnB,aAAa,CAAC,UAAC,IAAI,EAAA,EAAK,QAAC,IAAI,KAAK,aAAa,GAAG,MAAM,GAAG,aAAa,EAAC,CAAjD,CAAiD,CAAC;AAC1E,QAAA,kBAAkB,EAAE;AACtB,IAAA,CAAC;AAED,IAAA,IAAM,WAAW,GAAG,YAAA;QAClB,cAAc,CAAC,IAAI,CAAC;AACpB,QAAA,kBAAkB,EAAE;QACpB,eAAe,CAAC,IAAI,CAAC;QACrB,cAAc,CAAC,KAAK,CAAC;AACrB,QAAA,aAAa,EAAE;QACf,aAAa,CAAC,UAAU,EAAE;QAE1B;AACG,aAAA,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE;AAC7B,YAAA,UAAU,EAAA,UAAA;YACV,eAAe,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;AAC9C,YAAA,kBAAkB,EAAE,IAAI;SACzB;aACA,IAAI,CAAC,UAAC,MAAM,EAAA;AACX,YAAA,IAAI,MAAM,CAAC,OAAO,EAAE;gBAClB,cAAc,CAAC,IAAI,CAAC;YACtB;AAAO,iBAAA,IAAI,MAAM,CAAC,KAAK,EAAE;AACvB,gBAAA,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC;YAC9B;AACF,QAAA,CAAC,CAAC;AACN,IAAA,CAAC;AACD,IAAA,IAAM,mBAAmB,GAAG,YAAA;AAC1B,QAAA,cAAc,EAAE;QAChB,eAAe,EAAE,CAAC,KAAK,CAAC,YAAA;;AAExB,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC;AAED,IAAA,QACEA,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,eAAe,EACzB,KAAK,EAAE;YACL,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU;YACzC,KAAK,EAAE,QAAQ,GAAG,CAAC,GAAG,MAAM;YAC5B,MAAM,EAAE,QAAQ,GAAG,EAAE,GAAG,MAAM;AAC9B,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,KAAK,EAAE,MAAM;SACd,EAAA,QAAA,EAAA,CAGDC,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,0CAA0C,EAAA,QAAA,EACtD,WAAW,IACVA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mDAAmD,EAAA,QAAA,EAChEA,GAAA,CAAC,WAAW,EAAA,EAAC,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAA,CAAI,EAAA,CAC5D,KAEND,IAAA,CAAAE,QAAA,EAAA,EAAA,QAAA,EAAA,CAEED,GAAA,CAAA,OAAA,EAAA,EACE,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAA,IAAA,EACR,WAAW,EAAA,IAAA,EACX,KAAK,EAAA,IAAA,EACL,SAAS,EAAE,2DAAA,CAAA,MAAA,CAA4D,UAAU,KAAK,MAAM,GAAG,cAAc,GAAG,EAAE,CAC9G,GACJ,EAEFA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,0DAA0D,EAAA,QAAA,EACvEA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,sDAAsD,EAAA,QAAA,EACnE,gBAAgB,IACfA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,eAAe,EAAA,QAAA,EAAE,CAAC,CAAC,iCAAiC,EAAE,qBAAqB,CAAC,EAAA,CAAQ,KAEpGA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,wCAAwC,EAAA,QAAA,EAAE,CAAC,CAAC,4BAA4B,EAAE,aAAa,CAAC,EAAA,CAAQ,CACjH,EAAA,CACI,EAAA,CACH,EAENA,GAAA,CAAC,UAAU,EAAA,EACT,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,gBAAgB,EAAE,gBAAgB,EAClC,gBAAgB,EAAE,WAAW,EAAA,CAC7B,EAEFA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4DAA4D,EAAA,QAAA,EACzEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,kBAAkB,EAAA,QAAA,EAC/BA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,6EAA6E,EAAA,QAAA,EACzF,CAAC,CAAC,kCAAkC,EAAE,oDAAoD,CAAC,EAAA,CACxF,EAAA,CACF,EAAA,CACF,EAENA,GAAA,CAAC,iBAAiB,EAAA,EAAC,cAAc,EAAE,YAAY,EAAA,CAAI,EAElD,gBAAgB,KACfA,GAAA,CAAA,KAAA,EAAA,EAAA,aAAA,EACc,eAAe,EAC3B,SAAS,EAAC,kEAAkE,EAAA,CAC5E,CACH,CAAA,EAAA,CACA,CACJ,EAAA,CACG,EAGNA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,0CAA0C,EAAA,QAAA,EACvDD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sCAAsC,EAAA,QAAA,EAAA,CAEnDC,GAAA,CAAA,QAAA,EAAA,EACE,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAE,6KAAA,CAAA,MAAA,CAA8K,gBAAgB,GAAG,gCAAgC,GAAG,EAAE,CAC7O,EAAA,QAAA,EAEJA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,+BAA+B,EAAA,CAAO,EAAA,CAC9C,EAGTD,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,gCAAgC,EAAA,QAAA,EAAA,CAC7CA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4CAA4C,EAAA,QAAA,EAAA,CACzDC,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,uBAAA,CAAA,MAAA,CAAwB;AACjC,kDAAE;AACF,kDAAE,eAAe,CACf,EAAA,CACC,EACPA,wBACG;AACC,kDAAE,CAAC,CACD,sCAAsC,EACtC,qDAAqD;kDAErD,CAAC,CACD,mCAAmC,EACnC,qCAAqC,CACtC,EAAA,CACE,CAAA,EAAA,CACH,EACL,YAAY,KACXA,WAAG,SAAS,EAAC,uCAAuC,EAAA,QAAA,EACjD,YAAY,EAAA,CACX,CACL,CAAA,EAAA,CACG,CAAA,EAAA,CACF,EAAA,CACF,CAAA,EAAA,CACF;AAEV;;;;"}
1
+ {"version":3,"file":"Photo.js","sources":["../../../../../src/components/id-check/Photo.tsx"],"sourcesContent":["import { useRef, useState, useEffect, useCallback } from \"react\";\nimport type { CameraFacingMode } from \"../../types/camera\";\nimport {\n cameraService,\n type CaptureDocumentResult,\n} from \"../../services/cameraService\";\nimport {\n documentEdgeDetectionService,\n type DocumentDetectionResult,\n type DocumentDetectionHint,\n} from \"../../services/documentEdgeDetectionService\";\nimport CameraError from \"./CameraError\";\nimport CameraMask from \"./CameraMask\";\nimport OrientationToggle from \"./OrientationToggle\";\nimport { useI18n } from \"../../hooks/useI18n\";\nimport useIsMobile from \"../../hooks/useIsMobile\";\n\ninterface PhotoProps {\n onCapture: (image: string) => void;\n automaticCapture?: boolean; // Controls whether automatic capture is enabled\n maskType?: \"id\" | \"document\";\n}\n\nconst Photo: React.FC<PhotoProps> = ({\n onCapture,\n automaticCapture = false,\n maskType = \"id\",\n}) => {\n const isMobile = useIsMobile(768);\n const videoRef = useRef<HTMLVideoElement>(null);\n const [isDetecting, setIsDetecting] = useState(false);\n const [facingMode, setFacingMode] = useState<CameraFacingMode>(\"environment\");\n const [cameraError, setCameraError] = useState<string | null>(null);\n const [isPortrait, setIsPortrait] = useState(\n window.matchMedia(\"(orientation: portrait)\").matches\n );\n const [isCountingDown, setIsCountingDown] = useState(false);\n const [countdown, setCountdown] = useState(0);\n const [documentDetected, setDocumentDetected] = useState(false);\n const [qualityHint, setQualityHint] = useState<DocumentDetectionHint | undefined>(undefined);\n const [isInitializing, setIsInitializing] = useState(true);\n const [isProcessing, setIsProcessing] = useState(false);\n const [captureError, setCaptureError] = useState<string | null>(null);\n const [showCaptureFlash, setShowCaptureFlash] = useState(false);\n const { t } = useI18n();\n const [lastCaptureMeta, setLastCaptureMeta] =\n useState<CaptureDocumentResult | null>(null);\n const [maskRect, setMaskRect] = useState<{\n left: number;\n top: number;\n width: number;\n height: number;\n } | null>(null);\n\n const countdownIntervalRef = useRef<number | null>(null);\n const detectionHandlerRef = useRef<{ stop: () => void } | null>(null);\n const flashTimeoutRef = useRef<number | null>(null);\n\n const CAPTURE_FLASH_DURATION_MS = 300;\n\n const triggerCaptureFeedback = useCallback(() => {\n if (flashTimeoutRef.current) {\n clearTimeout(flashTimeoutRef.current);\n }\n setShowCaptureFlash(true);\n flashTimeoutRef.current = window.setTimeout(() => {\n setShowCaptureFlash(false);\n flashTimeoutRef.current = null;\n }, CAPTURE_FLASH_DURATION_MS);\n }, []);\n\n const CAPTURE_COUNTDOWN_SECONDS = 3;\n\n const clearCountdown = useCallback(() => {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n setCountdown(0);\n }, []);\n\n useEffect(() => {\n const handleOrientationChange = () => {\n setIsPortrait(window.matchMedia(\"(orientation: portrait)\").matches);\n };\n\n const mediaQuery = window.matchMedia(\"(orientation: portrait)\");\n mediaQuery.addEventListener(\"change\", handleOrientationChange);\n\n return () => {\n mediaQuery.removeEventListener(\"change\", handleOrientationChange);\n };\n }, []);\n\n const stopDetection = useCallback(() => {\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n documentEdgeDetectionService.stopDocumentDetection();\n }, []);\n\n const captureDocument = useCallback(async () => {\n if (!videoRef.current) {\n throw new Error(t(\"id_check.photo.errors.video_unavailable\", \"Le flux vidéo n'est pas disponible\"));\n }\n\n const video = videoRef.current;\n if (!video.videoWidth || !video.videoHeight) {\n throw new Error(\n t(\n \"id_check.photo.errors.video_dimensions_unavailable\",\n \"Dimensions vidéo indisponibles pour la capture\"\n )\n );\n }\n\n // Calculate crop area from mask if available\n let cropArea = null;\n if (maskRect) {\n const videoRect = video.getBoundingClientRect();\n\n // Calculate the actual displayed video dimensions accounting for object-fit: contain\n // Calculate the actual displayed video dimensions accounting for object-fit: cover\n const videoAspect = video.videoWidth / video.videoHeight;\n const displayAspect = videoRect.width / videoRect.height;\n\n let displayedWidth, displayedHeight, offsetX, offsetY;\n\n if (videoAspect > displayAspect) {\n // Video is wider than container - scaled to match height, sides cropped\n displayedHeight = videoRect.height;\n displayedWidth = videoRect.height * videoAspect;\n offsetY = 0;\n offsetX = (videoRect.width - displayedWidth) / 2;\n } else {\n // Video is taller than container - scaled to match width, top/bottom cropped\n displayedWidth = videoRect.width;\n displayedHeight = videoRect.width / videoAspect;\n offsetX = 0;\n offsetY = (videoRect.height - displayedHeight) / 2;\n }\n\n // Calculate the scale between actual displayed video and real video dimensions\n const scaleX = video.videoWidth / displayedWidth;\n const scaleY = video.videoHeight / displayedHeight;\n\n // Convert mask coordinates from screen space to video space\n // Account for video element offset and displayed video offset\n const cropX = (maskRect.left - videoRect.left - offsetX) * scaleX;\n const cropY = (maskRect.top - videoRect.top - offsetY) * scaleY;\n const cropWidth = maskRect.width * scaleX;\n const cropHeight = maskRect.height * scaleY;\n\n // Ensure crop area is within video bounds\n cropArea = {\n x: Math.max(0, Math.round(cropX)),\n y: Math.max(0, Math.round(cropY)),\n width: Math.min(video.videoWidth - Math.max(0, cropX), Math.round(cropWidth)),\n height: Math.min(video.videoHeight - Math.max(0, cropY), Math.round(cropHeight)),\n };\n\n console.debug(\"[Photo] Calculated crop area from mask\", {\n maskRect,\n videoRect: { left: videoRect.left, top: videoRect.top, width: videoRect.width, height: videoRect.height },\n videoDimensions: { width: video.videoWidth, height: video.videoHeight },\n displayedDimensions: { width: displayedWidth, height: displayedHeight },\n offset: { x: offsetX, y: offsetY },\n scale: { x: scaleX, y: scaleY },\n cropArea,\n });\n } else {\n console.debug(\"[Photo] No mask rect available, capturing full frame\");\n }\n\n setCaptureError(null);\n setIsDetecting(false);\n // Reste vrai jusqu'au démontage du composant (changement d'étape côté\n // DocumentCheck) en cas de succès : le traitement post-capture côté\n // parent (redimensionnement, conversion) continue pendant que ce\n // composant est encore affiché, donc l'overlay doit rester visible\n // jusqu'à ce que l'écran change réellement — jamais un écran figé sans\n // feedback.\n setIsProcessing(true);\n triggerCaptureFeedback();\n\n try {\n const result = await cameraService.captureDocument(video, cropArea, {\n facingMode,\n format: \"jpeg\",\n jpegQuality: 0.95,\n // Copy the current video frame synchronously: takePhoto() can delay the\n // shutter (or fall back to a later frame after an asynchronous failure).\n preferImageCapture: false,\n });\n\n setLastCaptureMeta(result);\n stopDetection();\n setDocumentDetected(false);\n\n console.debug(\"Document captured\", {\n method: result.method,\n analysis: result.analysis,\n source: result.sourceDimensions,\n crop: result.cropDimensions,\n });\n\n onCapture(result.dataUrl);\n } catch (error) {\n console.error(\"Document capture failed\", error);\n setCaptureError(t(\"id_check.photo.capture_failed\", \"La capture a échoué. Veuillez réessayer.\"));\n setIsDetecting(true);\n setIsProcessing(false);\n throw error;\n }\n }, [facingMode, onCapture, stopDetection, maskRect, t, triggerCaptureFeedback]);\n\n const startCountdown = useCallback(() => {\n if (isCountingDown) return;\n\n setIsCountingDown(true);\n setCountdown(CAPTURE_COUNTDOWN_SECONDS);\n\n let timeLeft = CAPTURE_COUNTDOWN_SECONDS;\n countdownIntervalRef.current = window.setInterval(() => {\n timeLeft = Math.max(0, timeLeft - 0.1);\n setCountdown(parseFloat(timeLeft.toFixed(1)));\n\n if (timeLeft <= 0.1) {\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n setIsCountingDown(false);\n\n captureDocument().catch(() => {\n // Error is handled inside captureDocument, but keep the promise chain quiet\n });\n }\n }, 100);\n }, [captureDocument, isCountingDown]);\n\n const handleDetectionChange = useCallback(\n (result: DocumentDetectionResult) => {\n // isStable (pas juste hasDocument) pilote le feedback visuel et\n // l'auto-capture pour éviter le clignotement : une frame isolée où le\n // document \"apparaît\" ne suffit pas, il faut plusieurs détections\n // consécutives cohérentes.\n setDocumentDetected(result.hasDocument && result.isStable);\n setQualityHint(result.hint);\n\n if (!automaticCapture) {\n return;\n }\n\n if (result.hasDocument && result.isStable) {\n startCountdown();\n } else {\n clearCountdown();\n }\n },\n [automaticCapture, clearCountdown, startCountdown]\n );\n\n const cancelCaptureTimer = useCallback(() => {\n clearCountdown();\n setDocumentDetected(false);\n }, [clearCountdown]);\n\n useEffect(() => {\n let isCancelled = false;\n\n const initCamera = async () => {\n setCameraError(null);\n setIsInitializing(true);\n const result = await cameraService.startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n });\n\n if (isCancelled) return;\n\n setIsInitializing(false);\n\n if (result.success) {\n setLastCaptureMeta(null);\n // Detection also runs in manual mode: it only drives the visual\n // feedback on the mask (documentDetected), it never starts the\n // auto-capture countdown unless automaticCapture is true (see\n // handleDetectionChange).\n setIsDetecting(true);\n } else if (result.error) {\n setCameraError(result.error);\n setIsDetecting(false);\n }\n };\n\n initCamera();\n\n return () => {\n isCancelled = true;\n clearCountdown();\n stopDetection();\n cameraService.stopCamera();\n setIsDetecting(false);\n if (flashTimeoutRef.current) {\n clearTimeout(flashTimeoutRef.current);\n flashTimeoutRef.current = null;\n }\n };\n }, [facingMode, clearCountdown, stopDetection]);\n\n useEffect(() => {\n if (!isDetecting || !videoRef.current) {\n return;\n }\n\n let cancelled = false;\n\n documentEdgeDetectionService\n .startDocumentDetection(videoRef.current, null, (result) => {\n if (!cancelled) {\n handleDetectionChange(result);\n }\n })\n .then((handler) => {\n if (!cancelled) {\n detectionHandlerRef.current = handler;\n }\n })\n .catch((error) => {\n console.error(\"[DocumentDetection] Unable to start automatic capture:\", error);\n if (!cancelled) {\n setIsDetecting(false);\n }\n });\n\n return () => {\n cancelled = true;\n if (detectionHandlerRef.current) {\n detectionHandlerRef.current.stop();\n detectionHandlerRef.current = null;\n }\n };\n }, [handleDetectionChange, isDetecting]);\n\n const toggleCamera = () => {\n setFacingMode((prev) => (prev === \"environment\" ? \"user\" : \"environment\"));\n cancelCaptureTimer();\n };\n\n const handleRetry = () => {\n setCameraError(null);\n cancelCaptureTimer();\n setCaptureError(null);\n setIsDetecting(false);\n setIsInitializing(true);\n stopDetection();\n cameraService.stopCamera();\n\n cameraService\n .startCamera(videoRef.current, {\n facingMode,\n idealResolution: { width: 4096, height: 3072 },\n preferImageCapture: true,\n })\n .then((result) => {\n setIsInitializing(false);\n if (result.success) {\n setIsDetecting(true);\n } else if (result.error) {\n setCameraError(result.error);\n }\n });\n };\n const handleManualCapture = () => {\n if (isProcessing) {\n return;\n }\n clearCountdown();\n captureDocument().catch(() => {\n // captureDocument already logs and sets error state\n });\n };\n\n const statusMessage =\n qualityHint === \"too_dark\"\n ? t(\"id_check.photo.hint.too_dark\", \"Trop sombre, cherchez plus de lumière\")\n : qualityHint === \"too_bright\"\n ? t(\"id_check.photo.hint.too_bright\", \"Trop de reflets, évitez la lumière directe\")\n : automaticCapture\n ? t(\n \"id_check.photo.automatic_instruction\",\n \"Capture automatique active ou appuyez sur le bouton\"\n )\n : t(\"id_check.photo.manual_instruction\", \"Appuyez sur le bouton pour capturer\");\n\n return (\n <div\n className=\"flex flex-col\"\n style={{\n position: isMobile ? \"fixed\" : \"relative\",\n inset: isMobile ? 0 : \"auto\",\n zIndex: isMobile ? 50 : \"auto\",\n height: \"100%\",\n width: \"100%\",\n }}\n >\n {/* Camera content area */}\n <div className=\"flex-1 relative overflow-hidden bg-black\">\n {cameraError ? (\n <div className=\"flex items-center justify-center h-full px-4 py-6\">\n <CameraError errorMessage={cameraError} onRetry={handleRetry} />\n </div>\n ) : (\n <>\n {isInitializing && (\n <div\n data-testid=\"camera-initializing\"\n className=\"absolute inset-0 z-30 flex flex-col items-center justify-center gap-3 bg-black\"\n >\n <div className=\"w-10 h-10 border-4 border-white border-t-transparent rounded-full animate-spin\" />\n <span className=\"text-white text-sm\">\n {t(\"id_check.photo.initializing\", \"Ouverture de la caméra…\")}\n </span>\n </div>\n )}\n {isProcessing && (\n <div\n data-testid=\"camera-processing\"\n className=\"absolute inset-0 z-30 flex flex-col items-center justify-center gap-3 bg-black bg-opacity-70\"\n >\n <div className=\"w-10 h-10 border-4 border-white border-t-transparent rounded-full animate-spin\" />\n <span className=\"text-white text-sm\">\n {t(\"id_check.photo.processing\", \"Traitement de l'image…\")}\n </span>\n </div>\n )}\n {/* Livestream of the camera*/}\n <video\n ref={videoRef}\n autoPlay\n playsInline\n muted\n className={`absolute inset-0 w-full h-full object-cover z-0 bg-black ${facingMode === \"user\" ? \"scale-x-[-1]\" : \"\"\n }`}\n />\n {/* Capture mode indicator */}\n <div className=\"absolute top-4 left-1/2 transform -translate-x-1/2 z-50\">\n <span className=\"text-white z-50 text-sm font-semibold drop-shadow-lg\">\n {automaticCapture ? (\n <span className=\"animate-pulse\">{t(\"id_check.photo.mode_autocapture\", \"Autocapture activée\")}</span>\n ) : (\n <span className=\"bg-orange-500 px-2 py-1 rounded hidden\">{t(\"id_check.photo.mode_manual\", \"Mode manuel\")}</span>\n )}\n </span>\n </div>\n {/* Mask */}\n <CameraMask\n isDetecting={isDetecting}\n isPortrait={isPortrait}\n facingMode={facingMode}\n isCountingDown={isCountingDown}\n countdown={countdown}\n maskType={maskType}\n documentDetected={documentDetected}\n qualityHint={qualityHint}\n onMaskRectChange={setMaskRect}\n />\n {/* Manual capture instructions */}\n <div className=\"absolute bottom-20 left-0 right-0 z-20 pointer-events-none\">\n <div className=\"text-center px-4\">\n <div className=\"bg-black bg-opacity-60 text-white text-sm px-4 py-2 rounded-lg inline-block\">\n {t(\"id_check.photo.position_document\", \"Posez le document à plat ou tenez-le dans le cadre\")}\n </div>\n </div>\n </div>\n {/* Button to change orientation */}\n <OrientationToggle onCameraToggle={toggleCamera} />\n {/* Capture confirmation flash - fires for manual and auto capture alike */}\n {showCaptureFlash && (\n <div\n data-testid=\"capture-flash\"\n className=\"absolute inset-0 z-40 bg-white pointer-events-none animate-pulse\"\n />\n )}\n </>\n )}\n </div>\n\n {/* Controls at the bottom */}\n <div className=\"relative z-20 bg-black bg-opacity-80 p-4\">\n <div className=\"flex flex-col items-center space-y-4\">\n {/* Manual capture button - always available */}\n <button\n onClick={handleManualCapture}\n className={`w-16 h-16 rounded-full border-4 border-white flex items-center justify-center transition-all duration-150 bg-transparent hover:bg-white hover:bg-opacity-20 cursor-pointer ${showCaptureFlash ? \"scale-90 ring-4 ring-[#11E5C5]\" : \"\"\n }`}\n >\n <div className=\"w-8 h-8 bg-white rounded-full\"></div>\n </button>\n\n {/* Status message */}\n <div className=\"text-white text-center text-sm\">\n <div className=\"flex items-center justify-center space-x-2\">\n <div\n className={`w-2 h-2 rounded-full ${automaticCapture\n ? \"bg-[#11E5C5] animate-pulse\"\n : \"bg-orange-500\"\n }`}\n ></div>\n <span>{statusMessage}</span>\n </div>\n {captureError && (\n <p className=\"text-red-400 text-xs mt-2 text-center\">\n {captureError}\n </p>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default Photo;\n"],"names":["_jsxs","_jsx","_Fragment"],"mappings":"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"}
@@ -36,7 +36,7 @@ import '../../assets/before-document.png.js';
36
36
  import '../../assets/selfietake.svg.js';
37
37
  import '../../assets/before-passport.png.js';
38
38
  import '../../services/cameraService.js';
39
- import '../../services/documentDetectionService.js';
39
+ import '../../services/documentEdgeDetectionService.js';
40
40
  import '../document-video/document-video-flow/DocumentVideoFlow.js';
41
41
  import '../document-collection/DocumentProcessing.js';
42
42
  import '../../constants/userInputForm.js';
@@ -36,7 +36,7 @@ import '../../assets/before-document.png.js';
36
36
  import '../../assets/selfietake.svg.js';
37
37
  import '../../assets/before-passport.png.js';
38
38
  import '../../services/cameraService.js';
39
- import '../../services/documentDetectionService.js';
39
+ import '../../services/documentEdgeDetectionService.js';
40
40
  import '../document-video/document-video-flow/DocumentVideoFlow.js';
41
41
  import '../document-collection/DocumentProcessing.js';
42
42
  import '../../constants/userInputForm.js';
@@ -9,10 +9,18 @@ var DEFAULT_RESOLUTION = {
9
9
  width: 4096,
10
10
  height: 3072,
11
11
  };
12
+ // Aligned with imageProcessing.ts's MAX_WIDTH (2048): the app downsizes every
13
+ // captured image to that width right after capture (DocumentCheck.tsx ->
14
+ // resizeAfterCapture), so synthetically upscaling beyond it here only adds a
15
+ // multi-second canvas encode (observed up to several seconds on mobile) for
16
+ // pixels that get thrown away a moment later. Previously targeted 4800x3200
17
+ // with up to 4x upscale — this caused the capture button to appear "stuck"
18
+ // for a few seconds after the flash, with no real quality benefit since the
19
+ // oversized image never survives the post-capture resize anyway.
12
20
  var QUALITY_REQUIREMENTS = {
13
- minArea: 3500 * 2200,
14
- targetArea: 4800 * 3200,
15
- minLongSide: 3200,
21
+ minArea: 1600000, // ~ 1600x1000, same proportion to targetArea as before
22
+ targetArea: 2048 * 1536,
23
+ minLongSide: 2048,
16
24
  };
17
25
  var supportsImageCapture = function () {
18
26
  return typeof window !== "undefined" && "ImageCapture" in window;
@@ -113,7 +121,7 @@ var CameraService = /** @class */ (function () {
113
121
  };
114
122
  CameraService.prototype._doStartCamera = function (videoElement, options) {
115
123
  return __awaiter(this, void 0, void 0, function () {
116
- var facingMode, preferImageCapture, desiredWidth, desiredHeight, maxResolution, targetWidth, targetHeight, videoConstraints, stream, err_2, errorMessage;
124
+ var facingMode, preferImageCapture, desiredWidth, desiredHeight, videoConstraints, stream, err_2, errorMessage;
117
125
  var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
118
126
  return __generator(this, function (_o) {
119
127
  switch (_o.label) {
@@ -124,7 +132,7 @@ var CameraService = /** @class */ (function () {
124
132
  desiredHeight = (_g = (_f = options.idealResolution) === null || _f === void 0 ? void 0 : _f.height) !== null && _g !== void 0 ? _g : DEFAULT_RESOLUTION.height;
125
133
  _o.label = 1;
126
134
  case 1:
127
- _o.trys.push([1, 9, , 10]);
135
+ _o.trys.push([1, 8, , 9]);
128
136
  // Close any existing stream before opening a new one
129
137
  if (this.stream) {
130
138
  this.stream.getTracks().forEach(function (t) { return t.stop(); });
@@ -132,24 +140,10 @@ var CameraService = /** @class */ (function () {
132
140
  this.videoTrack = null;
133
141
  this.imageCapture = null;
134
142
  }
135
- return [4 /*yield*/, this.getMaxCameraResolution(facingMode, options.deviceId)];
136
- case 2:
137
- maxResolution = _o.sent();
138
- targetWidth = maxResolution
139
- ? Math.min(desiredWidth, maxResolution.width)
140
- : desiredWidth;
141
- targetHeight = maxResolution
142
- ? Math.min(desiredHeight, maxResolution.height)
143
- : desiredHeight;
144
- console.debug("[CameraService] Resolution negotiation", {
145
- desired: { width: desiredWidth, height: desiredHeight },
146
- deviceMax: maxResolution !== null && maxResolution !== void 0 ? maxResolution : "unknown",
147
- target: { width: targetWidth, height: targetHeight },
148
- });
149
143
  videoConstraints = {
150
144
  facingMode: facingMode,
151
- width: { ideal: targetWidth },
152
- height: { ideal: targetHeight },
145
+ width: { ideal: desiredWidth },
146
+ height: { ideal: desiredHeight },
153
147
  };
154
148
  if (options.deviceId) {
155
149
  videoConstraints.deviceId = { exact: options.deviceId };
@@ -160,25 +154,29 @@ var CameraService = /** @class */ (function () {
160
154
  return [4 /*yield*/, navigator.mediaDevices.getUserMedia({
161
155
  video: videoConstraints,
162
156
  })];
163
- case 3:
157
+ case 2:
164
158
  stream = _o.sent();
165
159
  this.stream = stream;
166
160
  this.videoTrack = (_j = stream.getVideoTracks()[0]) !== null && _j !== void 0 ? _j : null;
167
161
  this.lastTrackSettings = (_l = (_k = this.videoTrack) === null || _k === void 0 ? void 0 : _k.getSettings()) !== null && _l !== void 0 ? _l : null;
168
- if (!this.videoTrack) return [3 /*break*/, 7];
169
- _o.label = 4;
170
- case 4:
171
- _o.trys.push([4, 6, , 7]);
162
+ console.debug("[CameraService] Camera opened", {
163
+ desired: { width: desiredWidth, height: desiredHeight },
164
+ actual: this.lastTrackSettings,
165
+ });
166
+ if (!this.videoTrack) return [3 /*break*/, 6];
167
+ _o.label = 3;
168
+ case 3:
169
+ _o.trys.push([3, 5, , 6]);
172
170
  return [4 /*yield*/, this.videoTrack.applyConstraints({
173
171
  advanced: [{ focusMode: "continuous" }],
174
172
  })];
173
+ case 4:
174
+ _o.sent();
175
+ return [3 /*break*/, 6];
175
176
  case 5:
176
177
  _o.sent();
177
- return [3 /*break*/, 7];
178
+ return [3 /*break*/, 6];
178
179
  case 6:
179
- _o.sent();
180
- return [3 /*break*/, 7];
181
- case 7:
182
180
  if (supportsImageCapture() && this.videoTrack && preferImageCapture) {
183
181
  try {
184
182
  this.imageCapture = new ImageCapture(this.videoTrack);
@@ -196,14 +194,14 @@ var CameraService = /** @class */ (function () {
196
194
  }
197
195
  videoElement.srcObject = stream;
198
196
  return [4 /*yield*/, this.waitForVideoReady(videoElement)];
199
- case 8:
197
+ case 7:
200
198
  _o.sent();
201
199
  return [2 /*return*/, {
202
200
  success: true,
203
201
  settings: (_m = this.lastTrackSettings) !== null && _m !== void 0 ? _m : undefined,
204
202
  captureMethod: this.captureMethod,
205
203
  }];
206
- case 9:
204
+ case 8:
207
205
  err_2 = _o.sent();
208
206
  console.error("Erreur lors de l'accès à la caméra:", err_2);
209
207
  errorMessage = "Une erreur inconnue s'est produite lors de l'accès à la caméra.";
@@ -220,7 +218,7 @@ var CameraService = /** @class */ (function () {
220
218
  }
221
219
  }
222
220
  return [2 /*return*/, { success: false, error: errorMessage }];
223
- case 10: return [2 /*return*/];
221
+ case 9: return [2 /*return*/];
224
222
  }
225
223
  });
226
224
  });
@@ -345,60 +343,6 @@ var CameraService = /** @class */ (function () {
345
343
  CameraService.prototype.getCurrentCaptureMethod = function () {
346
344
  return this.captureMethod;
347
345
  };
348
- /**
349
- * Probes the camera to discover its maximum supported resolution.
350
- * Opens a temporary low-res stream, reads getCapabilities(), then closes it.
351
- * Returns null if capabilities cannot be determined (the caller should fallback to defaults).
352
- */
353
- CameraService.prototype.getMaxCameraResolution = function (facingMode, deviceId) {
354
- return __awaiter(this, void 0, void 0, function () {
355
- var constraints, probeStream, track, maxWidth, maxHeight, capabilities, error_2;
356
- var _a, _b;
357
- return __generator(this, function (_c) {
358
- switch (_c.label) {
359
- case 0:
360
- _c.trys.push([0, 2, , 3]);
361
- constraints = { facingMode: facingMode };
362
- if (deviceId) {
363
- constraints.deviceId = { exact: deviceId };
364
- }
365
- return [4 /*yield*/, navigator.mediaDevices.getUserMedia({
366
- video: constraints,
367
- })];
368
- case 1:
369
- probeStream = _c.sent();
370
- track = probeStream.getVideoTracks()[0];
371
- if (!track) {
372
- probeStream.getTracks().forEach(function (t) { return t.stop(); });
373
- return [2 /*return*/, null];
374
- }
375
- maxWidth = void 0;
376
- maxHeight = void 0;
377
- // getCapabilities() is supported on Chrome/Edge/Android but not all browsers
378
- if (typeof track.getCapabilities === "function") {
379
- capabilities = track.getCapabilities();
380
- maxWidth = (_a = capabilities.width) === null || _a === void 0 ? void 0 : _a.max;
381
- maxHeight = (_b = capabilities.height) === null || _b === void 0 ? void 0 : _b.max;
382
- }
383
- // Stop the probe stream immediately
384
- probeStream.getTracks().forEach(function (t) { return t.stop(); });
385
- if (maxWidth && maxHeight) {
386
- console.debug("[CameraService] Device max resolution", {
387
- width: maxWidth,
388
- height: maxHeight,
389
- });
390
- return [2 /*return*/, { width: maxWidth, height: maxHeight }];
391
- }
392
- return [2 /*return*/, null];
393
- case 2:
394
- error_2 = _c.sent();
395
- console.warn("[CameraService] Could not probe camera capabilities", error_2);
396
- return [2 /*return*/, null];
397
- case 3: return [2 /*return*/];
398
- }
399
- });
400
- });
401
- };
402
346
  CameraService.prototype.waitForVideoReady = function (video) {
403
347
  return __awaiter(this, void 0, void 0, function () {
404
348
  var playError_1;
@@ -524,7 +468,7 @@ var CameraService = /** @class */ (function () {
524
468
  };
525
469
  CameraService.prototype.loadCanvasSourceFromBlob = function (blob) {
526
470
  return __awaiter(this, void 0, void 0, function () {
527
- var bitmap_1, error_3, objectUrl, image;
471
+ var bitmap_1, error_2, objectUrl, image;
528
472
  return __generator(this, function (_a) {
529
473
  switch (_a.label) {
530
474
  case 0:
@@ -548,8 +492,8 @@ var CameraService = /** @class */ (function () {
548
492
  },
549
493
  }];
550
494
  case 3:
551
- error_3 = _a.sent();
552
- console.warn("createImageBitmap a échoué, fallback sur HTMLImageElement", error_3);
495
+ error_2 = _a.sent();
496
+ console.warn("createImageBitmap a échoué, fallback sur HTMLImageElement", error_2);
553
497
  return [3 /*break*/, 4];
554
498
  case 4:
555
499
  objectUrl = URL.createObjectURL(blob);