@andresxid/xid_camera_ocr_sdk_react 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0
4
+
5
+ The photo is exactly what is inside the guide.
6
+
7
+ ### Changed
8
+
9
+ - Behavior change (BREAKING): the captured JPEG passed to `onCaptured` and `onUpload` is now the region inside the on-screen guide rectangle, cropped from the full-resolution frame. There is no perspective warp at capture anymore, even when the detector found the document corners; framing quality depends on the user. If the guide cannot be mapped, the full frame is used and the shape hint is `null`.
10
+ - The crop applies only when the guide is on screen. New option `cropToGuide` (default `false` in the session and the headless hook, which keep the full-frame snapshot); `<XidCameraOcr />` sets it to `true` unless `hideStatusOverlay` is set. Headless users may opt in if their video is `object-fit: cover` filling its box with a centered guide drawn with the newly exported `guideBox` and `guideRatioFor`.
11
+ - The crop reads the guide ratio at capture time, so changing `documentTypes` after mount is honored (new `guideRatio` session option; the hook supplies it).
12
+ - The guide element pins `box-sizing: content-box` (a host `border-box` reset can no longer shrink the inner area) and no longer transitions width or height, so the drawn guide never lags the crop.
13
+ - The photo is always horizontal and upright (document-shaped), whether the phone is held in portrait or landscape; the crop is computed at capture time, so rotation mid-session is handled. Its long side is at most 1024 px (`standard`) or 1600 px (`high`) and is never upscaled.
14
+ - The guide ratio is fixed by the first entry of `documentTypes` (`PASSPORT_MX` → TD3, otherwise ID-1). It no longer changes shape when detection flips the type hint. Detection keeps running only for the quality hints and the optional auto-shutter.
15
+ - The camera is requested with an ideal `aspectRatio` matching the viewport orientation (9:16 portrait, 16:9 landscape) instead of always 16:9, with the same ideal resolution.
16
+
17
+ ### Added
18
+
19
+ - Full demo: the results panel shows the captured photo with its pixel dimensions and size in KB.
20
+
21
+ ### Notes
22
+
23
+ - The `warpDocument`, `warpDocumentImageData` and `warpedSnapshotToBlob` exports are kept for compatibility; the session no longer uses them.
24
+
25
+ ## 0.2.0
26
+
27
+ Manual capture by default and a shutter that can live anywhere.
28
+
29
+ ### Changed
30
+
31
+ - Behavior change (BREAKING-ish): `autoCapture` now defaults to `false`; the user takes the photo. Pass `autoCapture: true` to restore the auto-shutter.
32
+ - The guide rectangle and dark mask are always shown while the camera is live. The SVG overlay that drew the detected OpenCV corners is removed; detection still runs for the quality hints and the rectified output. Cropping to the guide is not implemented.
33
+ - Default texts no longer promise automatic capture. es-MX: `ready` "¡Perfecto! Toma la foto", `hold_still` "Mantén la cámara quieta", `tip_focus` "Espera a que la cámara enfoque y luego toca el botón". English: `ready` "Perfect! Take the photo", `hold_still` "Hold the camera steady", `tip_focus` "Wait for the camera to focus, then tap the button".
34
+
35
+ ### Added
36
+
37
+ - `hideShutter` prop to hide the built-in shutter button.
38
+ - `<XidCameraOcr />` accepts a `ref` typed by the new exported `XidCameraOcrHandle` (`capture()`, `retake()`, `start()`).
39
+ - `onStatusChange` prop, called with the initial status and on every change.
40
+
3
41
  ## 0.1.1
4
42
 
5
43
  Public release under the XID proprietary license (LICENSE file added). No code changes.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @andresxid/xid_camera_ocr_sdk_react
2
2
 
3
- React component and headless hook that capture an identity document in the browser: camera, on-device OpenCV edge detection, quality checks and an auto-shutter. It returns a rectified JPEG to your `onUpload` callback and knows nothing about your backend.
3
+ React component and headless hook that capture an identity document in the browser: camera, on-device OpenCV edge detection, quality hints and a manual shutter (an optional auto-shutter is available). It returns a JPEG of exactly the on-screen guide region to your `onUpload` callback and knows nothing about your backend.
4
4
 
5
5
  ## Install
6
6
 
@@ -32,10 +32,59 @@ export function Capture() {
32
32
  }
33
33
  ```
34
34
 
35
- `onUpload` receives the rectified JPEG `Blob` and a shape hint (`'INE' | 'PASSPORT_MX' | 'OTHER' | null`). It must return the backend JSON. The hint is a card shape, not a document-type claim: your backend decides the real type.
35
+ `onUpload` receives the JPEG `Blob` of the guide region (see Captured photo) and a shape hint (`'INE' | 'PASSPORT_MX' | 'OTHER' | null`). It must return the backend JSON. The hint is a card shape, not a document-type claim: your backend decides the real type.
36
36
 
37
37
  Need your own UI? `useXidCameraOcr(options)` is the headless hook. It returns `videoRef`, `status`, `frame`, `result`, `error`, `start`, `stop`, `captureNow` and `retake`; attach `videoRef` to a `<video playsInline muted>` and render whatever you like. `XidCameraOcrSession` is the framework-free class underneath both.
38
38
 
39
+ ## Manual capture and custom shutter
40
+
41
+ The user takes the photo. A fixed guide rectangle with a dark mask is always shown while the camera is live; the detector keeps running only for the quality hints (`blurry`, `glare`, `too_dark`, `too_small`, `no_document`) and for the optional auto-shutter. To capture automatically, pass `autoCapture: true`.
42
+
43
+ To put the shutter anywhere, hide the built-in one and drive the component through its `ref`:
44
+
45
+ ```tsx
46
+ import { useRef, useState } from 'react';
47
+ import { XidCameraOcr, type XidCameraOcrHandle } from '@andresxid/xid_camera_ocr_sdk_react';
48
+
49
+ export function Capture() {
50
+ const camera = useRef<XidCameraOcrHandle>(null);
51
+ const [ready, setReady] = useState(false);
52
+
53
+ return (
54
+ <div style={{ position: 'relative', height: 480 }}>
55
+ <XidCameraOcr
56
+ ref={camera}
57
+ hideShutter
58
+ onStatusChange={(status) => setReady(status === 'streaming')}
59
+ onUpload={upload}
60
+ />
61
+ <button
62
+ type="button"
63
+ disabled={!ready}
64
+ onClick={() => camera.current?.capture()}
65
+ style={{ position: 'absolute', right: 16, bottom: 16 }}
66
+ >
67
+ Take photo
68
+ </button>
69
+ </div>
70
+ );
71
+ }
72
+ ```
73
+
74
+ `XidCameraOcrHandle` has `capture(): Promise<void>` (same as the built-in shutter; ignored unless the camera is live), `retake(): void` (same as the built-in retake; ignored unless the run is `done` or `error`) and `start(): Promise<void>`. Errors behave like the built-in buttons: they are not thrown and reach `onError`. `hideShutter` hides only the shutter; the retake button stays.
75
+
76
+ ## Captured photo
77
+
78
+ The JPEG passed to `onCaptured` and `onUpload` is exactly the region inside the guide rectangle you see on screen, cropped from the full-resolution camera frame at the moment of capture. Nothing outside the guide is uploaded.
79
+
80
+ - **Crop only, no perspective correction.** The SDK does not deskew or warp the document, even when the detector found its corners. If the card is tilted, rotated or only partly inside the guide, the photo shows it that way: framing quality depends on the user, so keep the hints visible.
81
+ - **Always horizontal.** The guide is document-shaped (wider than tall) and the photo keeps that shape and stays upright whether the phone is held in portrait or landscape. The crop is computed at capture time, so rotating the phone mid-session is handled.
82
+ - **Only with the built-in guide.** `<XidCameraOcr />` crops because it draws the guide itself. With `hideStatusOverlay` the guide is not drawn, so the component takes the full frame instead. The hook and `XidCameraOcrSession` also take the full frame unless you pass `cropToGuide: true`. Opting in is correct only when your `<video>` is `object-fit: cover` filling its box and you draw a centered guide with the exported `guideBox(container, guideRatioFor(documentTypes))` (same maths the crop uses).
83
+ - **Fixed guide ratio.** The guide ratio comes from the first entry of `documentTypes`: `PASSPORT_MX` uses the TD3 passport ratio (125:88), anything else the ID-1 card ratio (85.6:53.98). Detection never reshapes the guide.
84
+ - **Size.** The crop is downscaled so its long side is at most 1024 px (`captureResolution: 'standard'`) or 1600 px (`'high'`); it is never upscaled, so a low-resolution camera yields a smaller photo. JPEG quality is `captureQuality`.
85
+ - **Camera orientation.** The camera is requested with an ideal aspect that matches the viewport: 9:16 in a portrait viewport and 16:9 in a landscape one, so an upright phone does not waste most of the sensor frame. It is read when the camera starts; the browser may still deliver another shape.
86
+ - **Fallback.** If the guide cannot be mapped (the video has no layout yet) or the crop fails, the full unmodified camera frame is uploaded and the shape hint is `null`.
87
+
39
88
  ## Backend pattern
40
89
 
41
90
  The browser never holds a credential. It posts the JPEG to **your** backend, and your backend signs and forwards the request as `multipart/form-data` with the file in the `document` field:
@@ -94,9 +143,9 @@ Pass a `theme` object. The component writes a `--xco-*` custom property to its r
94
143
 
95
144
  | Variable | Default | Used by |
96
145
  |---|---|---|
97
- | `--xco-accent` | `#22c55e` | Detected-and-ready outline, spinner arc |
98
- | `--xco-warning` | `#eab308` | Outline while the frame is detected but not yet stable |
99
- | `--xco-danger` | `#ef4444` | Outline with no document, and on error |
146
+ | `--xco-accent` | `#22c55e` | Guide border when the frame is ready to capture, spinner arc |
147
+ | `--xco-warning` | `#eab308` | Guide border while the document is seen but the frame is not yet good |
148
+ | `--xco-danger` | `#ef4444` | Guide border with no document, and on error |
100
149
  | `--xco-background` | `#000` | Camera container background |
101
150
  | `--xco-mask` | `rgba(0,0,0,0.4)` | Dim area outside the guide |
102
151
  | `--xco-hint-bg` | `rgba(0,0,0,0.7)` | Hint banner background |
@@ -134,18 +183,18 @@ import { XidCameraOcr, DEFAULT_TEXTS_EN } from '@andresxid/xid_camera_ocr_sdk_re
134
183
  | `too_dark` | Hay poca luz, busca un lugar más iluminado |
135
184
  | `glare` | Hay un reflejo, inclina un poco tu identificación |
136
185
  | `blurry` | Espera a que la cámara enfoque |
137
- | `hold_still` | No te muevas… |
138
- | `ready` | ¡Perfecto! No te muevas |
186
+ | `hold_still` | Mantén la cámara quieta |
187
+ | `ready` | ¡Perfecto! Toma la foto |
139
188
  | `capturing` | Tomando la foto… |
140
189
  | `uploading` | Revisando tu identificación… |
141
190
  | `done` | ¡Listo! |
142
191
  | `error` | Algo salió mal, inténtalo de nuevo |
143
- | `detector_unavailable` | Toma la foto con el botón blanco |
192
+ | `detector_unavailable` | Toma la foto con el botón |
144
193
  | `retake` | Tomar otra vez |
145
194
  | `capture` | Tomar foto |
146
195
  | `tip_light` | Busca un lugar con buena luz |
147
196
  | `tip_glare` | Evita reflejos: no apuntes una lámpara directo a tu identificación |
148
- | `tip_focus` | Espera a que la cámara enfoque; la foto se toma sola |
197
+ | `tip_focus` | Espera a que la cámara enfoque y luego toca el botón |
149
198
  | `tips_dismiss` | Entendido |
150
199
 
151
200
  The tips card (`tip_light`, `tip_glare`, `tip_focus`, `tips_dismiss`) shows while the camera starts or the detector loads (`starting`, `loading_detector`) before the first completed capture, and hides once the status is `streaming`. The user can dismiss it with its button, but it returns on every `error` even if it was dismissed earlier. Hide it entirely with `showTips={false}`.
@@ -162,17 +211,20 @@ The tips card (`tip_light`, `tip_glare`, `tip_focus`, `tips_dismiss`) shows whil
162
211
  | `onResult` | `(result) => void` | | After `onUpload` resolves |
163
212
  | `onError` | `(err: Error) => void` | | Camera, detector or upload failure |
164
213
  | `autoStart` | `boolean` | `true` | Start the stream on mount |
165
- | `autoCapture` | `boolean` | `true` | Auto-shutter on a stable, good frame |
166
- | `documentTypes` | `DocumentType[]` | `['INE', 'PASSPORT_MX']` | Sizes the fallback guide; does not filter detection |
167
- | `stableFramesRequired` | `number` | `10` | Stable frames before auto-capture |
214
+ | `autoCapture` | `boolean` | `false` | Opt-in auto-shutter on a stable, good frame. By default the user takes the photo with the shutter |
215
+ | `documentTypes` | `DocumentType[]` | `['INE', 'PASSPORT_MX']` | The first entry fixes the guide and photo ratio (`PASSPORT_MX` → TD3, otherwise ID-1); does not filter detection |
216
+ | `cropToGuide` | `boolean` | `false` (component: `true` unless `hideStatusOverlay`) | Crop the photo to the guide. Headless opt-in requires an `object-fit: cover` video and a centered guide drawn with `guideBox` (see Captured photo) |
217
+ | `stableFramesRequired` | `number` | `10` | Stable frames before auto-capture (only with `autoCapture: true`) |
168
218
  | `captureQuality` | `number` | `0.92` | JPEG quality, 0 to 1 |
169
- | `captureResolution` | `'standard' \| 'high'` | `'standard'` | Long side 1024 px or 1600 px |
219
+ | `captureResolution` | `'standard' \| 'high'` | `'standard'` | Max long side of the photo, 1024 px or 1600 px (never upscaled) |
170
220
  | `opencvUrl` | `string` | packaged `opencv.js` | Self-hosted `dist/opencv.js`; required with `workerUrl` for CJS and non-Vite bundlers (see Known limitations) |
171
221
  | `workerUrl` | `string` | packaged `cv-worker.js` | Self-hosted `dist/cv-worker.js`, spawned as a module worker; required with `opencvUrl` for CJS and non-Vite bundlers |
172
222
  | `theme` | `XidCameraOcrTheme` | `{}` | See Theming |
173
223
  | `texts` | `Partial<HintCopy>` | es-MX defaults | See Texts |
174
224
  | `showTips` | `boolean` | `true` | Tips card |
175
- | `hideStatusOverlay` | `boolean` | `false` | Hides everything drawn over the video: guide and detected outline, hint banner (including the tap-to-start button), shutter, retake button, loader and tips card |
225
+ | `hideShutter` | `boolean` | `false` | Hides the built-in shutter button; capture with your own button through the `ref` handle |
226
+ | `onStatusChange` | `(status: SessionStatus) => void` | | Called with the initial status and on every change; enable your own button when it is `streaming` |
227
+ | `hideStatusOverlay` | `boolean` | `false` | Hides everything drawn over the video: guide rectangle and mask, hint banner (including the tap-to-start button), shutter, retake button, loader and tips card |
176
228
  | `className`, `style` | | | On the root `xid-camera-ocr` element |
177
229
 
178
230
  ## Status lifecycle
@@ -181,7 +233,7 @@ The tips card (`tip_light`, `tip_glare`, `tip_focus`, `tips_dismiss`) shows whil
181
233
 
182
234
  - `stopped` is reached after `stop()`.
183
235
  - One capture per run: after `done` or `error`, `retake()` stops and restarts the run to arm the shutter again.
184
- - If OpenCV cannot load, the status stays `streaming` with the frame hint `detector_unavailable`: auto-capture is off but the manual shutter still works.
236
+ - If OpenCV cannot load, the status stays `streaming` with the frame hint `detector_unavailable`: auto-capture (if enabled) is off but the manual shutter still works.
185
237
 
186
238
  ## Vite
187
239
 
@@ -205,9 +257,24 @@ Why each directive:
205
257
  - `img-src 'self' blob:`: the component itself loads no images. `blob:` is only needed if your page previews the captured `Blob` with `URL.createObjectURL`; drop it otherwise.
206
258
  - `connect-src 'self'`: your upload endpoint on the same origin. Add your API origin here if it differs.
207
259
 
260
+ ## Upgrading
261
+
262
+ ### From 0.1.x
263
+
264
+ - **No auto-shutter by default.** The user now takes the photo. To keep the 0.1.x behavior, pass `autoCapture: true`.
265
+ - **Fixed guide.** The guide rectangle is always shown and the detected-corner outline is gone.
266
+ - **Different photo.** The upload is now the guide region, cropped and not deskewed, instead of the perspective-corrected document. See Captured photo.
267
+ - Everything in "From 0.2.x" below also applies.
268
+
269
+ ### From 0.2.x
270
+
271
+ - **Different photo.** `onCaptured` and `onUpload` now receive only the guide region (always horizontal) instead of the warped document or the full frame. If your backend relied on the full frame, pass `hideStatusOverlay` (no guide, full frame) or use the hook without `cropToGuide`.
272
+ - **Guide ratio no longer follows detection.** It is fixed by the first entry of `documentTypes`; put `PASSPORT_MX` first for a passport-only flow.
273
+ - **Headless users:** the hook and `XidCameraOcrSession` keep uploading the full frame unless you opt in with `cropToGuide: true`.
274
+
208
275
  ## Known limitations
209
276
 
210
- - **Detection quality (0.4.0 gate not met).** The detector was inherited from 0.4.0 and has not been improved here. On the detection eval, hand-occlusion IoU is 0.492 against a 0.90 threshold and clutter IoU is 0.534 against 0.80. The false-positive rate is unmeasured. Keep the manual shutter reachable and treat auto-capture as a convenience, not a guarantee.
277
+ - **Detection quality (0.4.0 gate not met).** The detector was inherited from 0.4.0 and has not been improved here. On the detection eval, hand-occlusion IoU is 0.492 against a 0.90 threshold and clutter IoU is 0.534 against 0.80. The false-positive rate is unmeasured. Keep the manual shutter reachable: detection only drives the quality hints and the optional auto-shutter, so do not rely on it to find the document.
211
278
  - **Phone validation.** Phone validation (iOS Safari / Android Chrome) is in progress; results will be published in a later release.
212
279
  - **CJS build needs `workerUrl` and `opencvUrl`.** The CJS bundle resolves `import.meta.url` against the document, not the package. CJS consumers must serve `dist/cv-worker.js` and `dist/opencv.js` from their own origin (copy them from `node_modules/@andresxid/xid_camera_ocr_sdk_react/dist/`) and pass both URLs; otherwise the detector cannot start and only manual capture works. ESM consumers on Vite need nothing.
213
280
  - **Non-Vite bundlers are untested** (webpack, Rollup alone, esbuild, Next.js). Host `dist/cv-worker.js` and `dist/opencv.js` yourself and pass both `workerUrl` and `opencvUrl`; otherwise only manual capture works.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var gt=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,C=gt();async function de(e,t){let r={audio:false,video:{facingMode:{ideal:"environment"},width:{ideal:1920,min:640},height:{ideal:1080,min:480},aspectRatio:{ideal:1.7777777777777777}}};if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw new Error("Camera unavailable: getUserMedia requires a secure context (HTTPS or localhost) and a browser with MediaDevices support.");let n;try{n=await navigator.mediaDevices.getUserMedia(t??r);}catch(s){if(!t)n=await navigator.mediaDevices.getUserMedia({audio:false,video:true});else throw s}e.srcObject=n,e.muted=true,e.playsInline=true,e.autoplay=true;let o=n.getVideoTracks()[0],i=o.getCapabilities?.();return i&&"focusMode"in i&&i.focusMode?.includes("continuous")&&o.applyConstraints({advanced:[{focusMode:"continuous"}]}).catch(()=>{}),await e.play().catch(()=>{}),n}function pe(e,t){e.srcObject===t&&(e.srcObject=null),t?.getTracks().forEach(r=>r.stop());}async function me(e,t=.92){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)throw new Error("Video stream not ready (videoWidth=0)");let o=document.createElement("canvas");o.width=r,o.height=n;let i=o.getContext("2d");if(!i)throw new Error("2D canvas context unavailable");return i.drawImage(e,0,0,r,n),new Promise((s,a)=>{o.toBlob(l=>l?s(l):a(new Error("Canvas toBlob returned null")),"image/jpeg",t);})}var N=null;function he(e,t=640){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)return null;let o=Math.round(t),i=Math.round(n*t/r);N??=document.createElement("canvas"),(N.width!==o||N.height!==i)&&(N.width=o,N.height=i);let s=N.getContext("2d",{willReadFrequently:true});return s?(s.drawImage(e,0,0,o,i),s.getImageData(0,0,o,i)):null}function Fe(e){let t=e.videoWidth,r=e.videoHeight;if(!t||!r)return null;let n=document.createElement("canvas");n.width=t,n.height=r;let o=n.getContext("2d",{willReadFrequently:true});return o?(o.drawImage(e,0,0,t,r),o.getImageData(0,0,t,r)):null}function Pe(e,t=.92){let r=document.createElement("canvas");r.width=e.width,r.height=e.height;let n=r.getContext("2d");return n?(n.putImageData(e,0,0),new Promise((o,i)=>r.toBlob(s=>s?o(s):i(new Error("Canvas toBlob returned null")),"image/jpeg",t))):Promise.reject(new Error("2D canvas context unavailable"))}function ye(e){let t=e.getCapabilities;return typeof t!="function"?false:t.call(e).torch===true}async function fe(e,t){try{return await e.applyConstraints({advanced:[{torch:t}]}),!0}catch{return false}}var xt="@andresxid/xid_camera_ocr_sdk_react";function Ie(e,t){return e.pathname.endsWith(`/${xt}/${t}`)}function De(e){return new URL(e,C)}function Oe(){return new URL("@andresxid/xid_camera_ocr_sdk_react/opencv.js",C)}function be(){let e=Oe();return Ie(e,"opencv.js")?De("./opencv.js").href:e.href}function He(e){return e!==void 0?new Worker(e,{type:"module"}):Ie(Oe(),"opencv.js")?new Worker(De("./cv-worker.js"),{type:"module"}):new Worker(new URL("@andresxid/xid_camera_ocr_sdk_react/cv-worker.js",C),{type:"module"})}function Le(e){if(!e||typeof e!="object")return null;let t=e;switch(t.type){case "ready":return {type:"ready"};case "init-error":return typeof t.error=="string"?{type:"init-error",error:t.error}:null;case "error":return typeof t.id=="number"&&typeof t.error=="string"?{type:"error",id:t.id,error:t.error}:null;case "analyze-result":return typeof t.id=="number"&&t.result&&typeof t.result=="object"?{type:"analyze-result",id:t.id,result:t.result}:null;case "warp-result":return typeof t.id=="number"&&typeof t.width=="number"&&typeof t.height=="number"&&t.buffer instanceof ArrayBuffer?{type:"warp-result",id:t.id,width:t.width,height:t.height,buffer:t.buffer}:null;default:return null}}function Ue(e){let t=new Uint8ClampedArray(e.data.byteLength);return t.set(e.data),t.buffer}var Ct=e=>e instanceof Error?e:new Error(String(e)),j=class{initTimeoutMs;worker=null;readyPromise=null;rejectInit=null;initTimer=null;ready=false;pending=new Map;nextId=1;constructor(t={}){this.initTimeoutMs=t.initTimeoutMs??3e4;}init(t=be(),r){if(this.readyPromise)return this.readyPromise;let n;try{n=He(r);}catch(i){return Promise.reject(Ct(i))}this.worker=n;let o=new Promise((i,s)=>{this.rejectInit=s,this.initTimer=setTimeout(()=>this.fail(new Error(`OpenCV worker not ready within ${this.initTimeoutMs} ms`)),this.initTimeoutMs),n.addEventListener("message",a=>{if(this.worker!==n)return;let l=Le(a.data);if(!l)return;if(l.type==="ready"){this.clearInitTimer(),this.rejectInit=null,this.ready=true,i();return}if(l.type==="init-error"){this.fail(new Error(l.error));return}let c=this.pending.get(l.id);c&&(this.pending.delete(l.id),l.type==="error"?c.reject(new Error(l.error)):c.resolve(l));}),n.addEventListener("error",a=>{this.worker===n&&this.fail(new Error(a.message||"Worker error"));}),n.addEventListener("messageerror",a=>{if(this.worker!==n)return;let l=new Error("Worker message could not be deserialized"),c=a.data?.id,d=typeof c=="number"?this.pending.get(c):void 0;if(typeof c=="number"&&d){this.pending.delete(c),d.reject(l);return}this.fail(l);});});return this.readyPromise=o,n.postMessage({type:"init",opencvUrl:t}),o}isReady(){return this.ready&&this.worker!==null}async analyze(t,r={}){let n=Ue(t),o=r.prior,i=await this.request(s=>({type:"analyze",id:s,width:t.width,height:t.height,buffer:n,...o?{prior:o}:{}}),[n]);if(i.type!=="analyze-result")throw new Error(`Unexpected worker response: ${i.type}`);return i.result}async warp(t,r,n,o=1024){let i=Ue(t),s=await this.request(a=>({type:"warp",id:a,width:t.width,height:t.height,buffer:i,corners:r,docType:n,longSide:o}),[i]);if(s.type!=="warp-result")throw new Error(`Unexpected worker response: ${s.type}`);return new ImageData(new Uint8ClampedArray(s.buffer),s.width,s.height)}terminate(){this.rejectInit=null,this.shutdown(new Error("Worker terminated"));}fail(t){let r=this.rejectInit;this.rejectInit=null,this.shutdown(t),r?.(t);}clearInitTimer(){this.initTimer!==null&&clearTimeout(this.initTimer),this.initTimer=null;}shutdown(t){this.clearInitTimer(),this.worker?.terminate(),this.worker=null,this.readyPromise=null,this.ready=false;let r=[...this.pending.values()];this.pending.clear();for(let n of r)n.reject(t);}request(t,r){let n=this.worker;if(!n||!this.ready)return Promise.reject(new Error("CVWorkerClient not ready"));let o=t(this.nextId++),i=new Promise((s,a)=>this.pending.set(o.id,{resolve:s,reject:a}));return n.postMessage(o,r),i}};var D=1.585772508336421,H=125/88,wt=1.503,Rt=.05,re=1.25,ge=1.75,Tt=.25;function xe(e){if(e.length!==4)throw new Error(`orderCorners expects 4 points, got ${e.length}`);let t=(e[0].x+e[1].x+e[2].x+e[3].x)/4,r=(e[0].y+e[1].y+e[2].y+e[3].y)/4,n=[...e].sort((i,s)=>Math.atan2(i.y-r,i.x-t)-Math.atan2(s.y-r,s.x-t)),o=0;for(let i=1;i<4;i++){let s=n[i],a=n[o];(s.x+s.y<a.x+a.y||s.x+s.y===a.x+a.y&&s.y<a.y)&&(o=i);}return [0,1,2,3].map(i=>n[(o+i)%4])}function L(e){let t=0;for(let r=0;r<e.length;r++){let n=e[r],o=e[(r+1)%e.length];t+=n.x*o.y-o.x*n.y;}return Math.abs(t)/2}function ne(e){let[t,r,n,o]=e;return {top:Math.hypot(r.x-t.x,r.y-t.y),right:Math.hypot(n.x-r.x,n.y-r.y),bottom:Math.hypot(n.x-o.x,n.y-o.y),left:Math.hypot(o.x-t.x,o.y-t.y)}}function vt(e){let t=[0,0,0,0];for(let r=0;r<4;r++){let n=e[(r+3)%4],o=e[r],i=e[(r+1)%4],s=n.x-o.x,a=n.y-o.y,l=i.x-o.x,c=i.y-o.y,d=Math.hypot(s,a),p=Math.hypot(l,c);if(d===0||p===0){t[r]=0;continue}let m=Math.min(1,Math.max(-1,(s*l+a*c)/(d*p)));t[r]=Math.acos(m)*180/Math.PI;}return t}function oe(e,t=70,r=110){let n=ne(e);return n.top<=0||n.right<=0||n.bottom<=0||n.left<=0||!kt(e)||L(e)<=0?false:vt(e).every(o=>o>=t&&o<=r)}function kt(e){let t=0;for(let r=0;r<4;r++){let n=e[r],o=e[(r+1)%4],i=e[(r+2)%4],s=(o.x-n.x)*(i.y-o.y)-(o.y-n.y)*(i.x-o.x);if(s===0)return false;let a=Math.sign(s);if(t===0)t=a;else if(a!==t)return false}return true}function z(e){let t=ne(e),r=(t.top+t.bottom)/2,n=(t.left+t.right)/2,o=Math.min(r,n);return o<=0?0:Math.max(r,n)/o}function Mt(e){if(!Number.isFinite(e))return 0;let t=Math.min(Math.abs(e-D),Math.abs(e-H));return Math.max(0,1-t/Tt)}function Qe(e){return .5*e.areaRatio+.3*e.rectangularity+.2*Mt(e.aspect)}function ae(e){let t=e>=wt?D:H;return Math.abs(e-t)/t<=Rt?t===D?"INE":"PASSPORT_MX":"OTHER"}function Se(e){return e>=re&&e<=ge}function Ne(e,t){return e==="INE"?D:e==="PASSPORT_MX"?H:t}var V=1024,qe=1600;function Be(e,t,r,n,o=V){let i=_t(Ne(n,z(r))),s=Math.max(1,Math.round(o/i)),a=ne(r),l=a.top+a.bottom<a.left+a.right,c=n==="INE"||n==="PASSPORT_MX",d=l&&c?[r[3],r[0],r[1],r[2]]:r,p=!l||c,m=p?o:s,u=p?s:o,x=null,S=null,y=null,g=null,h=null,f=null;try{return x=e.matFromImageData(t),S=new e.Mat,y=e.matFromArray(4,1,e.CV_32FC2,[d[0].x,d[0].y,d[1].x,d[1].y,d[2].x,d[2].y,d[3].x,d[3].y]),g=e.matFromArray(4,1,e.CV_32FC2,[0,0,m,0,m,u,0,u]),h=e.getPerspectiveTransform(y,g),e.warpPerspective(x,S,h,new e.Size(m,u),e.INTER_LINEAR,e.BORDER_CONSTANT,new e.Scalar(0,0,0,255)),S.channels()!==4&&(f=new e.Mat,e.cvtColor(S,f,e.COLOR_BGR2RGBA)),At(new Uint8ClampedArray((f??S).data),m,u)}finally{for(let k of [f,h,g,y,S,x])k?.delete();}}function Xe(e,t,r,n,o=V){let i=t.getContext("2d",{willReadFrequently:true});if(!i)throw new Error("2D canvas context unavailable");let s=i.getImageData(0,0,t.width,t.height),a=Be(e,s,r,n,o),l=document.createElement("canvas");l.width=a.width,l.height=a.height;let c=l.getContext("2d");if(!c)throw new Error("2D canvas context unavailable (output)");return c.putImageData(a,0,0),l}async function Et(e,t,r,n,o=.92,i=V){let s=r?Xe(e,t,r,n,i):t;return new Promise((a,l)=>{s.toBlob(c=>c?a(c):l(new Error("Canvas toBlob returned null")),"image/jpeg",o);})}function _t(e){return Number.isFinite(e)?Math.min(ge,Math.max(re,e)):re}function At(e,t,r){return typeof globalThis.ImageData=="function"?new ImageData(e,t,r):{data:e,width:t,height:r,colorSpace:"srgb"}}var A={brightnessMin:.18,brightnessMax:.9,blurMin:60,glareMax:.04,fillMin:.25,glarePixel:248};function G(e,t,r){let n=new Int32Array(r*2);for(let o=0;o<r;o++){let i=o+.5,s=1/0,a=-1/0;for(let l=0;l<4;l++){let c=e[l],d=e[(l+1)%4],p=Math.min(c.y,d.y),m=Math.max(c.y,d.y);if(i<p||i>m||m===p)continue;let u=c.x+(i-c.y)*(d.x-c.x)/(d.y-c.y);u<s&&(s=u),u>a&&(a=u);}if(s===1/0){n[o*2]=0,n[o*2+1]=0;continue}n[o*2]=Math.max(0,Math.ceil(s-.5)),n[o*2+1]=Math.min(t,Math.floor(a+.5));}return n}function Ce(e,t){let{data:r,width:n,height:o}=e,i=G(t,n,o),s=A.glarePixel,a=0,l=0,c=0,d=0,p=0,m=0;for(let f=0;f<o;f++){let k=i[f*2],M=i[f*2+1];if(k>=M)continue;let _=0,E=0;f>0&&f<o-1&&(_=Math.max(k,i[(f-1)*2],i[(f+1)*2])+1,E=Math.min(M,i[(f-1)*2+1],i[(f+1)*2+1])-1);let R=f*n;for(let v=k;v<M;v++){let F=R+v,P=r[F];if(a+=P,P>=s&&l++,c++,v>=_&&v<E){let w=4*P-r[F-n]-r[F+n]-r[F-1]-r[F+1];d+=w,p+=w*w,m++;}}}let u=c>0?a/c/255:0,x=c>0?l/c:0,S=m>0?Math.max(0,p/m-(d/m)**2):0,y=n*o,g=y>0?L(t)/y:0,h=u>=A.brightnessMin&&u<=A.brightnessMax&&S>=A.blurMin&&x<=A.glareMax&&g>=A.fillMin;return {brightness:u,blurScore:S,glareRatio:x,docFillRatio:g,ok:h}}function We(e){let{data:t}=e;if(t.length===0)return 0;let r=0;for(let n=0;n<t.length;n++)r+=t[n];return r/t.length/255}function we(e){if(!e.detected||!e.quality)return "no_document";let t=e.quality;return !Number.isFinite(t.docFillRatio)||t.docFillRatio<A.fillMin?"too_small":!Number.isFinite(t.brightness)||t.brightness<A.brightnessMin?"too_dark":!Number.isFinite(t.glareRatio)||t.glareRatio>A.glareMax||t.brightness>A.brightnessMax?"glare":!Number.isFinite(t.blurScore)||t.blurScore<A.blurMin?"blurry":e.stableFrames<e.stableFramesRequired?"hold_still":"ready"}var Ft=A.brightnessMin;function je(e){return !e.torchSupported||e.torchOn?false:(e.quality?e.quality.brightness:e.frameBrightness)<Ft}var Re=Object.freeze({idle:"Toca para activar la c\xE1mara",starting:"Abriendo la c\xE1mara\u2026",loading_detector:"Preparando la c\xE1mara\u2026",no_document:"Coloca tu identificaci\xF3n dentro del recuadro",too_small:"Acerca m\xE1s tu identificaci\xF3n",too_dark:"Hay poca luz, busca un lugar m\xE1s iluminado",glare:"Hay un reflejo, inclina un poco tu identificaci\xF3n",blurry:"Espera a que la c\xE1mara enfoque",hold_still:"No te muevas\u2026",ready:"\xA1Perfecto! No te muevas",capturing:"Tomando la foto\u2026",uploading:"Revisando tu identificaci\xF3n\u2026",done:"\xA1Listo!",error:"Algo sali\xF3 mal, int\xE9ntalo de nuevo",detector_unavailable:"Toma la foto con el bot\xF3n blanco",retake:"Tomar otra vez",capture:"Tomar foto",tip_light:"Busca un lugar con buena luz",tip_glare:"Evita reflejos: no apuntes una l\xE1mpara directo a tu identificaci\xF3n",tip_focus:"Espera a que la c\xE1mara enfoque; la foto se toma sola",tips_dismiss:"Entendido"}),Pt=Object.freeze({idle:"Ready to start",starting:"Starting camera\u2026",loading_detector:"Loading detector\u2026",no_document:"Place the document inside the frame",too_small:"Move closer to the document",too_dark:"Find more light",glare:"Tilt the document to avoid glare",blurry:"Hold still to focus",hold_still:"Hold still\u2026",ready:"Ready \u2014 hold still",capturing:"Capturing\u2026",uploading:"Processing document\u2026",done:"Done",error:"Something went wrong \u2014 try again",detector_unavailable:"Detector unavailable \u2014 capture manually",retake:"Capture again",capture:"Capture now",tip_light:"Find a well-lit place",tip_glare:"Avoid glare: don't point a lamp straight at your ID",tip_focus:"Wait for the camera to focus; the photo is taken automatically",tips_dismiss:"Got it"}),It=["loading_detector","capturing","uploading","done","error"];function Dt(e){return It.includes(e)}function Y(e,t){return t?.[e]??Re[e]}function Te(e){let t={...Re};for(let r of Object.keys(t))t[r]=Y(r,e);return t}function ie(e,t,r){return e==="idle"||e==="stopped"?Y("idle",r):e==="starting"?Y("starting",r):Dt(e)?Y(e,r):Y(t??"no_document",r)}var Ot=.05;function Ht(e,t,r){let n=r.width/t.width,o=r.height/t.height;return e.map(i=>({x:i.x*n,y:i.y*o}))}function Lt(e,t){return e.map(r=>({x:Math.min(t.width,Math.max(0,r.x)),y:Math.min(t.height,Math.max(0,r.y))}))}function ze(e,t,r){let n=Lt(Ht(e,t,r),r);return !oe(n)||L(n)<Ot*r.width*r.height?null:n}var Ve={stableFrames:0,isStable:false,quad:null,typeHint:null},$=class{required;maxRatio;switchFrames;current=Ve;candidate=null;constructor(t={}){this.required=t.stableFramesRequired??10,this.maxRatio=t.maxDisplacementRatio??.015,this.switchFrames=Math.max(1,t.hintSwitchFrames??3);}get snapshot(){return this.current}reset(){this.current=Ve,this.candidate=null;}update(t,r){if(!t)return this.reset(),this.current;let n=Math.hypot(r.width,r.height)*this.maxRatio,o=this.current,i=o.quad!==null&&o.quad.every((l,c)=>Math.hypot(t.quad[c].x-l.x,t.quad[c].y-l.y)<=n),s=o.typeHint??t.typeHint,a=i?o.stableFrames+1:1;if(t.typeHint===s)this.candidate=null;else {let l=this.candidate?.typeHint===t.typeHint?this.candidate.frames+1:1;this.candidate={typeHint:t.typeHint,frames:l},l>=this.switchFrames&&(s=t.typeHint,a=1,this.candidate=null);}return this.current={stableFrames:a,isStable:a>=this.required,quad:t.quad,typeHint:s},this.current}};var Qt=640,Nt=10,Ge=1500,qt=35e3,Bt=5,Xt={createWorkerClient:e=>new j(e),attachCamera:e=>de(e),detachCamera:pe,sampleFrame:he,grabFrame:Fe,encodeJpeg:Pe,snapshotToBlob:me,supportsTorch:ye,setTorch:fe,now:()=>performance.now()},Ye=e=>e.provenance==="reduced"||e.provenance==="lowres",$e=e=>e instanceof Error?e:new Error(String(e)),Ke=e=>e.map(t=>({x:t.x,y:t.y})),K=class{opts;deps;stream=null;track=null;cv=null;generation=0;timer=null;frameCallback=null;inFlight=null;warmupUntil=0;capturing=false;autoShutterSpent=false;torchSupported=false;torchOn=false;torchRejected=false;weakRun=false;prior=null;stability;state={status:"idle",lastFrame:null,lastResult:null,lastError:null};constructor(t,r={}){this.opts={videoElement:t.videoElement,documentTypes:t.documentTypes??["INE","PASSPORT_MX"],autoCapture:t.autoCapture??true,stableFramesRequired:t.stableFramesRequired??10,captureQuality:t.captureQuality??.92,captureResolution:t.captureResolution??"standard",opencvUrl:t.opencvUrl,workerUrl:t.workerUrl,onUpload:t.onUpload,onFrameAnalyzed:t.onFrameAnalyzed,onCaptured:t.onCaptured,onResult:t.onResult,onError:t.onError},this.deps={...Xt,...r},this.stability=new $({stableFramesRequired:this.opts.stableFramesRequired});}async start(){if(!["idle","stopped","error"].includes(this.state.status))throw new Error(`Cannot start session from status=${this.state.status}`);this.release();let t=++this.generation;this.setStatus("starting"),this.state.lastError=null;try{let r=await this.deps.attachCamera(this.opts.videoElement);if(t!==this.generation){this.deps.detachCamera(this.opts.videoElement,r);return}this.stream=r,this.track=r.getVideoTracks()[0]??null,this.torchSupported=this.track?this.deps.supportsTorch(this.track):!1,this.warmupUntil=0,this.setStatus("loading_detector");let n=this.deps.createWorkerClient({initTimeoutMs:qt});this.cv=n,n.init(this.opts.opencvUrl,this.opts.workerUrl).then(()=>{t!==this.generation||this.cv!==n||(this.state.status==="loading_detector"&&this.setStatus("streaming"),this.scheduleNext(t,0));},o=>this.detectorUnavailable(t,n,o));}catch(r){throw t===this.generation&&this.emitError(r),r}}stop(){this.generation++,this.release(),this.setStatus("stopped");}async captureNow(){if(this.capturing)return;let t=this.state.status;if(t!=="streaming"&&t!=="loading_detector"&&!(t==="done"&&this.stream))throw new Error(`Cannot capture from status=${this.state.status}`);let r=this.stability.snapshot,n=this.state.lastFrame?.frameSize??null,o=r.quad&&n?this.fullFrameQuad(r.quad,n):null;await this.doCapture(this.generation,o?r.typeHint:null,o);}getState(){return {...this.state}}scheduleNext(t,r){this.timer=setTimeout(()=>{if(this.timer=null,t!==this.generation)return;let n=this.opts.videoElement;typeof n.requestVideoFrameCallback=="function"?this.frameCallback=n.requestVideoFrameCallback(()=>{this.frameCallback=null,this.tick(t);}):this.tick(t);},r);}async tick(t){if(t!==this.generation)return;let r=this.deps.now();try{await this.analyzeFrame(t);}catch(n){t===this.generation&&console.warn("[xid-camera-ocr] analyzeFrame error:",n);}t!==this.generation||!this.cv||this.scheduleNext(t,Math.max(0,1e3/Nt-(this.deps.now()-r)));}async analyzeFrame(t){let r=this.cv;if(this.capturing||!r?.isReady())return;let n=this.deps.sampleFrame(this.opts.videoElement,Qt);if(!n)return;let o={width:n.width,height:n.height};this.warmupUntil===0&&(this.warmupUntil=this.deps.now()+Ge);let i=this.prior&&this.prior.width===n.width&&this.prior.height===n.height?this.prior.quad:null,s=r.analyze(n,i?{prior:i}:{});this.inFlight=s;let a;try{a=await s;}catch(u){if(t===this.generation&&this.cv===r&&!r.isReady()){this.detectorUnavailable(t,r,u);return}throw u}finally{this.inFlight===s&&(this.inFlight=null);}if(t!==this.generation||this.capturing)return;this.prior=a.detected&&a.corners?{quad:Ke(a.corners),...o}:null;let c=!(this.deps.now()<this.warmupUntil)&&a.detected&&a.corners&&a.documentType?{quad:a.corners,typeHint:a.documentType}:null,d=this.stability.update(c,o);this.weakRun=d.stableFrames<=1?c!==null&&Ye(a):this.weakRun||Ye(a);let p=this.opts.stableFramesRequired+(this.weakRun?Bt:0);if(await this.updateTorch(t,a),t!==this.generation)return;let m={detected:a.detected,documentType:a.documentType,confidence:Math.min(d.stableFrames/p,1),aspectRatio:a.aspectRatio,quality:a.quality,corners:a.corners?Ke(a.corners):null,frameSize:o,hint:we({detected:a.detected,quality:a.quality,stableFrames:d.stableFrames,stableFramesRequired:p}),...this.torchSupported?{torch:this.torchOn}:{}};if(this.state.lastFrame=m,this.opts.onFrameAnalyzed?.(m),t===this.generation&&this.opts.autoCapture&&!this.autoShutterSpent&&d.quad&&d.stableFrames>=p&&a.quality?.ok){let u=this.fullFrameQuad(d.quad,o);if(!u){this.stability.reset(),this.weakRun=false;return}await this.doCapture(t,d.typeHint,u);}}detectorUnavailable(t,r,n){if(t!==this.generation||this.cv!==r)return;r.terminate(),this.cv=null,this.inFlight=null,this.prior=null,this.stability.reset(),this.weakRun=false,this.autoShutterSpent=true,this.state.status==="loading_detector"&&this.setStatus("streaming");let o=$e(n);this.state.lastError=o;let i={detected:false,documentType:null,confidence:0,aspectRatio:null,quality:null,corners:null,frameSize:null,hint:"detector_unavailable",...this.torchSupported?{torch:this.torchOn}:{}};this.state.lastFrame=i,this.opts.onFrameAnalyzed?.(i),t===this.generation&&this.opts.onError?.(o);}async updateTorch(t,r){if(!this.track||this.torchRejected||!je({torchSupported:this.torchSupported,torchOn:this.torchOn,quality:r.quality,frameBrightness:r.frameBrightness}))return;let n=await this.deps.setTorch(this.track,true);t===this.generation&&(this.torchOn=n,n||(this.torchRejected=true));}fullFrameQuad(t,r){let n=this.opts.videoElement;return !n.videoWidth||!n.videoHeight?null:ze(t,r,{width:n.videoWidth,height:n.videoHeight})}async doCapture(t,r,n){if(!this.capturing){this.capturing=true,this.autoShutterSpent=true,this.prior=null,this.stability.reset(),this.weakRun=false,this.setStatus("capturing");try{let{blob:o,type:i}=await this.captureBlob(t,r,n);if(t!==this.generation)return;this.opts.onCaptured?.(o,i),this.setStatus("uploading");let s=await this.opts.onUpload(o,i);if(t!==this.generation)return;this.state.lastResult=s,this.setStatus("done"),this.opts.onResult?.(s);}catch(o){t===this.generation&&this.emitError(o);}finally{t===this.generation&&(this.stability.reset(),this.weakRun=false,this.warmupUntil=this.deps.now()+Ge,this.capturing=false);}}}async captureBlob(t,r,n){let o=this.opts.videoElement,i=async()=>({blob:await this.deps.snapshotToBlob(o,this.opts.captureQuality),type:null}),s=this.cv;if(!s?.isReady()||!n)return i();try{await this.inFlight?.catch(()=>{});let a=this.deps.grabFrame(o);if(!a||!s.isReady())return i();let l=this.opts.captureResolution==="high"?qe:V,c=await s.warp(a,n,r,l);return {blob:await this.deps.encodeJpeg(c,this.opts.captureQuality),type:r}}catch(a){if(t!==this.generation)throw a;return console.warn("[xid-camera-ocr] warp failed, using plain snapshot:",a),i()}}release(){this.prior=null,this.timer!==null&&clearTimeout(this.timer),this.timer=null,this.frameCallback!==null&&(this.opts.videoElement.cancelVideoFrameCallback?.(this.frameCallback),this.frameCallback=null),this.track&&this.torchOn&&this.deps.setTorch(this.track,false),this.torchOn=false,this.torchRejected=false,this.stream&&this.deps.detachCamera(this.opts.videoElement,this.stream),this.stream=null,this.track=null,this.cv?.terminate(),this.cv=null,this.inFlight=null,this.stability.reset(),this.weakRun=false,this.capturing=false,this.autoShutterSpent=false;}setStatus(t){this.state.status=t;}emitError(t){let r=$e(t);this.state.lastError=r,this.setStatus("error"),this.opts.onError?.(r);}};var Je=.08,Wt=.95,jt=.02,q=8,zt=2,Ze=8,et=.33,se=2,Vt=2,Gt=1,Yt=Vt+se,$t=2,Kt=2*(se+1),Jt=10,tt=1.1,at=se+1,Zt=6,it=.92,er=1/it,tr=.85,rr=2,nr=.05,rt=2,nt=64;function st(e){return {detected:false,documentType:null,aspectRatio:null,corners:null,boundingBox:null,quality:null,frameBrightness:e,score:null}}function or(e,t,r,n={}){let o={brightness:0};try{return ar(e,t,o,n.prior??null)}catch(i){return console.warn("[xid-camera-ocr] detectDocumentCV failed:",i),st(o.brightness)}}function ar(e,t,r,n){let{width:o,height:i}=t,s=[],a=l=>(s.push(l),l);try{let l=a(e.matFromImageData(t)),c=a(new e.Mat),d=a(new e.Mat),p={equalized:a(new e.Mat),filtered:a(new e.Mat),padded:a(new e.Mat),edges:a(new e.Mat),dilated:a(new e.Mat),kernel:a(e.Mat.ones(3,3,e.CV_8U)),contours:a(new e.MatVector),hierarchy:a(new e.Mat),hull:a(new e.Mat),approx:a(new e.Mat),clahe:a(new e.CLAHE(zt,new e.Size(Ze,Ze)))};e.cvtColor(l,c,e.COLOR_RGBA2GRAY),r.brightness=We(ve(c,o,i));let m=[],u=ot(e,c,p,o,i,m,n),x=!1,S=Math.round(o/rt),y=Math.round(i/rt);if(!u&&S>=nt&&y>=nt&&(e.resize(c,d,new e.Size(S,y),0,0,e.INTER_AREA),u=ot(e,d,p,o,i,m,n),x=u!==null),u&&dr(u,m,ve(c,o,i))&&(u=null),!u)return st(r.brightness);let g=x?"lowres":u.reduced?"reduced":"direct",h=u.quad.map(R=>R.x),f=u.quad.map(R=>R.y),k=Math.min(...h),M=Math.max(...h),_=Math.min(...f),E=Math.max(...f);return {detected:!0,documentType:ae(u.aspect),aspectRatio:u.aspect,corners:u.quad,boundingBox:{x:k/o,y:_/i,width:(M-k)/o,height:(E-_)/i},quality:Ce(ve(c,o,i),ut(u.quad,at*u.scale)),frameBrightness:r.brightness,score:g==="direct"?u.score:u.score*tr,provenance:g}}finally{for(let l of s)l.delete();}}function ot(e,t,r,n,o,i,s){let a=t.cols,l=t.rows,c=n/a,d=o/l,p=a*l,m=h=>({x:h.x*c,y:h.y*d}),{hull:u,approx:x,contours:S}=r;r.clahe.apply(t,r.equalized),e.bilateralFilter(r.equalized,r.filtered,9,75,75,e.BORDER_DEFAULT),e.copyMakeBorder(r.filtered,r.padded,q,q,q,q,e.BORDER_CONSTANT,new e.Scalar(0));let y=yr(r.padded.data);e.Canny(r.padded,r.edges,Math.max(10,(1-et)*y),Math.min(255,(1+et)*y)),e.dilate(r.edges,r.dilated,r.kernel,new e.Point(-1,-1),se),e.findContours(r.dilated,S,r.hierarchy,e.RETR_LIST,e.CHAIN_APPROX_SIMPLE);let g=null;for(let h=0;h<S.size();h++){let f=S.get(h);try{let k=e.boundingRect(f);if(k.width*k.height<p*Je)continue;e.convexHull(f,u,!1,!0);let M=e.contourArea(u);if(M<p*Je||M>p*Wt||(e.approxPolyDP(u,x,jt*e.arcLength(u,!0),!0),x.rows<4||x.rows>Zt||!e.isContourConvex(x)))continue;let _=x.rows!==4,E;if(!_)E=sr(x,a,l);else {let W=lr(lt(x));if(!W)continue;E=W.map(Q=>ct(Q,a,l));let U=M/L(E);if(!(U>=it&&U<=er))continue}let R=M*c*d,v=E.map(m),F=Yt*c;if(hr(v,n,o,F)>Gt){ur(v,n,o,F)||i.push({pts:v,area:R});continue}let P=xe(v);if(!oe(P))continue;let w=e.minAreaRect(_?u:x),O=w.size.width*w.size.height,ee=O>0?Math.min(1,M/O):0,B=z(P);if(!Se(B))continue;let X=Qe({areaRatio:M/p,rectangularity:ee,aspect:B}),te=s?X-ir(P,s,n,o):X;(!g||te>g.rank)&&(g={quad:P,score:X,rank:te,aspect:B,area:R,scale:c,reduced:_});}finally{f.delete();}}return g}function ir(e,t,r,n){let o=1/0;for(let i=0;i<4;i++){let s=0;for(let a=0;a<4;a++){let l=e[(a+i)%4];s=Math.max(s,Math.hypot(l.x-t[a].x,l.y-t[a].y));}o=Math.min(o,s);}return rr*Math.min(o/Math.hypot(r,n),nr)}function ve(e,t,r){return {data:e.data,width:t,height:r}}function lt(e){let t=e.data32S,r=[];for(let n=0;n<e.rows;n++)r.push({x:t[n*2]-q,y:t[n*2+1]-q});return r}function ct(e,t,r){return {x:Math.min(t,Math.max(0,e.x)),y:Math.min(r,Math.max(0,e.y))}}function sr(e,t,r){return lt(e).map(n=>ct(n,t,r))}function lr(e){let t=e;for(;t.length>4;){let r=t.length,n=-1,o=1/0,i=null;for(let a=0;a<r;a++){let l=t[(a+r-1)%r],c=t[a],d=t[(a+1)%r],p=t[(a+2)%r],m=cr(l,c,p,d);if(!m)continue;let u=Math.abs((m.x-c.x)*(d.y-c.y)-(m.y-c.y)*(d.x-c.x))/2;u<o&&(o=u,n=a,i=m);}if(n<0||!i)return null;let s=[];for(let a=0;a<r;a++)a===n?s.push(i):a!==(n+1)%r&&s.push(t[a]);t=s;}return t}function cr(e,t,r,n){let o=t.x-e.x,i=t.y-e.y,s=n.x-r.x,a=n.y-r.y,l=o*a-i*s;if(Math.abs(l)<1e-9)return null;let c=((r.x-e.x)*a-(r.y-e.y)*s)/l,d=((r.x-e.x)*i-(r.y-e.y)*o)/l;return c<1||d<1?null:{x:e.x+c*o,y:e.y+c*i}}function ur(e,t,r,n){let o=e.map(s=>s.x),i=e.map(s=>s.y);return Math.min(...o)<=n&&Math.max(...o)>=t-n||Math.min(...i)<=n&&Math.max(...i)>=r-n}function dr(e,t,r){let n=Kt*e.scale;if(!t.some(a=>a.area>=$t*e.area&&e.quad.every(l=>mr(a.pts,l,n))))return false;if(ae(e.aspect)==="OTHER")return true;let{inner:i,ring:s}=pr(r,ut(e.quad,at*e.scale),e.quad);return i<s-Jt}function pr(e,t,r){let{data:n,width:o,height:i}=e,s=(r[0].x+r[1].x+r[2].x+r[3].x)/4,a=(r[0].y+r[1].y+r[2].y+r[3].y)/4,l=r.map(y=>({x:s+(y.x-s)*tt,y:a+(y.y-a)*tt})),c=G(l,o,i),d=G(r,o,i),p=G(t,o,i),m=0,u=0,x=0,S=0;for(let y=0;y<i;y++){let g=c[y*2],h=c[y*2+1];if(g>=h)continue;let f=d[y*2],k=d[y*2+1],M=p[y*2],_=p[y*2+1],E=y*o;for(let R=g;R<h;R++){let v=n[E+R];R>=M&&R<_?(m+=v,u++):(R<f||R>=k)&&(x+=v,S++);}}return {inner:u>0?m/u:0,ring:S>0?x/S:0}}function mr(e,t,r){let n=0;for(let i=0;i<e.length;i++){let s=e[i],a=e[(i+1)%e.length];n+=s.x*a.y-a.x*s.y;}let o=Math.sign(n);if(o===0)return false;for(let i=0;i<e.length;i++){let s=e[i],a=e[(i+1)%e.length],l=Math.hypot(a.x-s.x,a.y-s.y);if(l===0)continue;if(o*((a.x-s.x)*(t.y-s.y)-(a.y-s.y)*(t.x-s.x))/l<r)return false}return true}function ut(e,t){return e.map((r,n)=>{let o=e[(n+3)%4],i=e[(n+1)%4],s=o.x-r.x,a=o.y-r.y,l=i.x-r.x,c=i.y-r.y,d=Math.hypot(s,a),p=Math.hypot(l,c),m=s/d+l/p,u=a/d+c/p,x=Math.hypot(m,u),S=Math.sin(Math.acos(Math.min(1,Math.max(-1,(s*l+a*c)/(d*p))))/2),y=t/S/x;return {x:r.x+m*y,y:r.y+u*y}})}function hr(e,t,r,n){let o=0;for(let i of e)(i.x<=n||i.x>=t-n||i.y<=n||i.y>=r-n)&&o++;return o}function yr(e){let t=new Uint32Array(256);for(let n=0;n<e.length;n++)t[e[n]]++;let r=0;for(let n=0;n<256;n++)if(r+=t[n],r>=e.length/2)return n;return 128}function Me(e){let t=react.useRef(null),r=react.useRef(null),[n,o]=react.useState("idle"),[i,s]=react.useState(null),[a,l]=react.useState(null),[c,d]=react.useState(null),p=react.useRef(e);p.current=e;let m=react.useCallback(()=>{if(r.current)return r.current;if(!t.current)throw new Error("videoRef not attached yet");let g=new K({videoElement:t.current,documentTypes:p.current.documentTypes,autoCapture:p.current.autoCapture,stableFramesRequired:p.current.stableFramesRequired,captureQuality:p.current.captureQuality,captureResolution:p.current.captureResolution,opencvUrl:p.current.opencvUrl,workerUrl:p.current.workerUrl,onUpload:(h,f)=>p.current.onUpload(h,f),onFrameAnalyzed:h=>{s(h),r.current===g&&o(g.getState().status),p.current.onFrameAnalyzed?.(h);},onCaptured:(h,f)=>{o("capturing"),p.current.onCaptured?.(h,f);},onResult:h=>{l(h),o("done"),p.current.onResult?.(h);},onError:h=>{d(h),r.current===g&&o(g.getState().status),p.current.onError?.(h);}});return r.current=g,g},[]),u=react.useCallback(async()=>{let g=m();await g.start(),r.current===g&&o(g.getState().status);},[m]),x=react.useCallback(()=>{r.current?.stop(),o("stopped");},[]),S=react.useCallback(async()=>{await r.current?.captureNow();},[]),y=react.useCallback(async()=>{x(),l(null),d(null),s(null),await u();},[x,u]);return react.useEffect(()=>(e.autoStart!==false&&t.current&&u().catch(()=>{}),()=>{r.current?.stop(),r.current=null;}),[]),{videoRef:t,status:n,frame:i,result:a,error:c,start:u,stop:x,captureNow:S,retake:y}}function gr({status:e,showTips:t,dismissed:r,completedOnce:n}){return t&&!r&&(e==="error"||!n&&(e==="starting"||e==="loading_detector"))}function dt(e,t){let[r,n]=react.useState(false),[o,i]=react.useState(e==="done"),[s,a]=react.useState(e),l=r,c=o;s!==e&&(a(e),e==="error"&&(l=false,n(false)),e==="done"&&(c=true,i(true)));let d=react.useCallback(()=>n(true),[]);return {visible:gr({status:e,showTips:t,dismissed:l,completedOnce:c}),dismiss:d}}var ce={accent:{name:"--xco-accent",fallback:"#22c55e"},warning:{name:"--xco-warning",fallback:"#eab308"},danger:{name:"--xco-danger",fallback:"#ef4444"},background:{name:"--xco-background",fallback:"#000"},mask:{name:"--xco-mask",fallback:"rgba(0,0,0,0.4)"},hintBg:{name:"--xco-hint-bg",fallback:"rgba(0,0,0,0.7)"},hintFg:{name:"--xco-hint-fg",fallback:"white"},buttonBg:{name:"--xco-button-bg",fallback:"rgba(255,255,255,0.92)"},buttonFg:{name:"--xco-button-fg",fallback:"#111"},shutter:{name:"--xco-shutter",fallback:"rgba(255,255,255,0.9)"},overlayBg:{name:"--xco-overlay-bg",fallback:"rgba(0,0,0,0.78)"},overlayFg:{name:"--xco-overlay-fg",fallback:"white"},fontFamily:{name:"--xco-font-family",fallback:"system-ui, -apple-system, sans-serif"},radius:{name:"--xco-radius",fallback:"12px"}};function b(e){let{name:t,fallback:r}=ce[e];return `var(${t}, ${r})`}function pt(e){let t={};if(!e)return t;for(let r of Object.keys(e)){if(!Object.prototype.hasOwnProperty.call(ce,r))continue;let n=e[r];typeof n!="string"||n===""||(t[ce[r].name]=n);}return t}function mt(e,t){return e==="done"?b("accent"):e==="error"?b("danger"):e==="uploading"||e==="capturing"?b("accent"):t?.detected?t.confidence>=1?b("accent"):b("warning"):b("danger")}var _e={width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",style:{flex:"0 0 auto"}},xr=()=>jsxRuntime.jsxs("svg",{..._e,children:[jsxRuntime.jsx("circle",{cx:"12",cy:"12",r:"4"}),jsxRuntime.jsx("path",{d:"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"})]}),Sr=()=>jsxRuntime.jsxs("svg",{..._e,children:[jsxRuntime.jsx("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),jsxRuntime.jsx("path",{d:"M14 5l-6 14M18 5l-6 14"})]}),Cr=()=>jsxRuntime.jsxs("svg",{..._e,children:[jsxRuntime.jsx("path",{d:"M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3"}),jsxRuntime.jsx("circle",{cx:"12",cy:"12",r:"2"})]});function ht({texts:e,onDismiss:t}){let r=[{Icon:xr,text:e.tip_light},{Icon:Sr,text:e.tip_glare},{Icon:Cr,text:e.tip_focus}];return jsxRuntime.jsxs("div",{className:"xco-tips",style:wr,children:[jsxRuntime.jsx("ul",{style:Rr,children:r.map(({Icon:n,text:o})=>jsxRuntime.jsxs("li",{style:Tr,children:[jsxRuntime.jsx(n,{}),jsxRuntime.jsx("span",{children:o})]},o))}),jsxRuntime.jsx("button",{type:"button",className:"xco-tips-dismiss",onClick:t,style:vr,children:e.tips_dismiss})]})}var wr={position:"absolute",top:"calc(16px + env(safe-area-inset-top, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"calc(100% - 32px)",maxWidth:360,padding:16,background:b("overlayBg"),color:b("overlayFg"),borderRadius:b("radius"),fontFamily:b("fontFamily"),fontSize:15,lineHeight:1.35,display:"flex",flexDirection:"column",gap:12,pointerEvents:"auto",zIndex:5},Rr={listStyle:"none",margin:0,padding:0,display:"flex",flexDirection:"column",gap:10},Tr={display:"flex",alignItems:"center",gap:12},vr={alignSelf:"flex-end",minHeight:44,padding:"10px 20px",borderRadius:b("radius"),background:b("buttonBg"),color:b("buttonFg"),border:"none",fontFamily:b("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",WebkitTapHighlightColor:"transparent"};var Fr=typeof window>"u"?react.useEffect:react.useLayoutEffect;function yt({videoRef:e,status:t,frame:r,texts:n,documentTypes:o,theme:i,className:s,style:a,hideStatusOverlay:l,tipsVisible:c,onCapture:d,onRetake:p,onStart:m,onDismissTips:u}){let x=t==="streaming"||t==="loading_detector",S=t==="done"||t==="error",y=t==="idle"||t==="stopped",g=t==="capturing"||t==="uploading",h="xco-doc-mask-"+react.useId().replace(/[^A-Za-z0-9_-]/g,""),f=react.useRef(null),[k,M]=react.useState({width:0,height:0}),_=r?.documentType,E=_==="PASSPORT_MX"?H:_==="INE"?D:o[0]==="PASSPORT_MX"?H:D;Fr(()=>{let w=f.current;if(!w)return;let O=()=>{let B=w.clientWidth,X=w.clientHeight,te=B*.85,W=X*.7,U=te,Q=U/E;Q>W&&(Q=W,U=Q*E),M({width:U,height:Q});};O();let ee=new ResizeObserver(O);return ee.observe(w),()=>ee.disconnect()},[E]);let R=!!(r?.corners&&r?.frameSize),v=mt(t,r),F=ie(t,r?.hint,n),P=s?`xid-camera-ocr ${s}`:"xid-camera-ocr";return jsxRuntime.jsxs("div",{ref:f,className:P,"data-status":t,"data-hint":r?.hint??"",style:{...Pr,...pt(i),...a},children:[jsxRuntime.jsx("style",{children:"@keyframes xco-spin { to { transform: rotate(360deg); } }"}),jsxRuntime.jsx("video",{ref:e,playsInline:true,muted:true,autoPlay:true,style:Ir}),!l&&!R&&jsxRuntime.jsx("div",{style:Or,children:jsxRuntime.jsx("div",{className:"xco-guide",style:{...Hr,width:k.width,height:k.height,borderColor:v}})}),!l&&R&&r&&r.corners&&r.frameSize&&jsxRuntime.jsxs("svg",{style:Dr,viewBox:`0 0 ${r.frameSize.width} ${r.frameSize.height}`,preserveAspectRatio:"xMidYMid slice",children:[jsxRuntime.jsx("defs",{children:jsxRuntime.jsxs("mask",{id:h,children:[jsxRuntime.jsx("rect",{x:"0",y:"0",width:r.frameSize.width,height:r.frameSize.height,fill:"white"}),jsxRuntime.jsx("polygon",{points:r.corners.map(w=>`${w.x},${w.y}`).join(" "),fill:"black"})]})}),jsxRuntime.jsx("rect",{x:"0",y:"0",width:r.frameSize.width,height:r.frameSize.height,style:{fill:b("mask")},mask:`url(#${h})`}),jsxRuntime.jsx("polygon",{points:r.corners.map(w=>`${w.x},${w.y}`).join(" "),style:{fill:"none",stroke:v},strokeWidth:Math.max(2,r.frameSize.width*.006),strokeLinejoin:"round"}),r.corners.map((w,O)=>jsxRuntime.jsx("circle",{cx:w.x,cy:w.y,r:Math.max(4,r.frameSize.width*.012),style:{fill:v}},O))]}),!l&&(y?jsxRuntime.jsx("button",{type:"button",className:"xco-hint",onClick:m,style:Xr,children:F}):jsxRuntime.jsx("p",{className:"xco-hint",style:bt,role:"status","aria-live":"polite",children:F})),!l&&x&&jsxRuntime.jsx("button",{type:"button",className:"xco-shutter",onClick:d,"aria-label":n.capture,style:Nr,children:jsxRuntime.jsx("span",{style:qr})}),!l&&S&&jsxRuntime.jsx("button",{type:"button",className:"xco-retake",onClick:p,"aria-label":n.retake,style:Br,children:n.retake}),!l&&g&&jsxRuntime.jsxs("div",{className:"xco-loader",style:Lr,"aria-busy":"true","aria-live":"polite",children:[jsxRuntime.jsx("div",{style:Ur}),jsxRuntime.jsx("p",{style:Qr,children:ie(t,void 0,n)})]}),c&&!l&&jsxRuntime.jsx(ht,{texts:n,onDismiss:u})]})}var ft="calc(104px + env(safe-area-inset-bottom, 0px))",Pr={position:"relative",width:"100%",height:"100%",overflow:"hidden",background:b("background"),fontFamily:b("fontFamily"),touchAction:"none"},Ir={position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",display:"block"},Dr={position:"absolute",inset:0,width:"100%",height:"100%",pointerEvents:"none"},Or={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",pointerEvents:"none"},Hr={borderRadius:b("radius"),borderWidth:4,borderStyle:"solid",boxShadow:`0 0 0 9999px ${b("mask")}`,transition:"border-color 200ms ease-in-out, width 200ms ease-in-out, height 200ms ease-in-out"},Lr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:20,background:b("overlayBg"),backdropFilter:"blur(6px)",WebkitBackdropFilter:"blur(6px)",pointerEvents:"auto",zIndex:10},Ur={width:56,height:56,borderRadius:"50%",border:"5px solid rgba(255, 255, 255, 0.18)",borderTopColor:b("accent"),animation:"xco-spin 0.85s linear infinite"},Qr={color:b("overlayFg"),fontFamily:b("fontFamily"),fontSize:15,fontWeight:500,margin:0,textAlign:"center",padding:"0 24px"},Nr={position:"absolute",bottom:ft,left:"50%",transform:"translateX(-50%)",width:68,height:68,borderRadius:"50%",background:"rgba(255,255,255,0.18)",border:`4px solid ${b("shutter")}`,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"auto",WebkitTapHighlightColor:"transparent",padding:0},qr={width:52,height:52,borderRadius:"50%",background:"white",display:"block"},Br={position:"absolute",bottom:ft,left:"50%",transform:"translateX(-50%)",minHeight:44,padding:"10px 20px",borderRadius:22,background:b("buttonBg"),color:b("buttonFg"),border:"none",fontFamily:b("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"},bt={position:"absolute",bottom:"calc(16px + env(safe-area-inset-bottom, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"max-content",maxWidth:"calc(100% - 32px)",background:b("hintBg"),color:b("hintFg"),padding:"10px 16px",borderRadius:b("radius"),fontFamily:b("fontFamily"),fontSize:16,lineHeight:1.35,margin:0,whiteSpace:"normal",textAlign:"center"},Xr={...bt,border:"none",minHeight:44,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"};var jr=["INE","PASSPORT_MX"],Ae=()=>{};function zr({className:e,style:t,hideStatusOverlay:r,texts:n,theme:o,showTips:i,...s}){let{videoRef:a,status:l,frame:c,start:d,captureNow:p,retake:m}=Me(s),u=dt(l,i??true),x=react.useMemo(()=>Te(n),[n]),S=l==="streaming"||l==="loading_detector",y=l==="done"||l==="error",g=()=>{S&&p().catch(Ae);},h=()=>{y&&m().catch(Ae);},f=()=>{d().catch(Ae);};return jsxRuntime.jsx(yt,{videoRef:a,status:l,frame:c,texts:x,documentTypes:s.documentTypes??jr,theme:o,className:e,style:t,hideStatusOverlay:r,tipsVisible:u.visible,onCapture:g,onRetake:h,onStart:f,onDismissTips:u.dismiss})}exports.CVWorkerClient=j;exports.DEFAULT_TEXTS_EN=Pt;exports.DEFAULT_TEXTS_ES=Re;exports.ID1_RATIO=D;exports.QUALITY_THRESHOLDS=A;exports.StabilityTracker=$;exports.TD3_RATIO=H;exports.XCO_VARS=ce;exports.XidCameraOcr=zr;exports.XidCameraOcrSession=K;exports.attachCamera=de;exports.copyFor=ie;exports.decideHint=we;exports.defaultOpencvUrl=be;exports.detachCamera=pe;exports.detectDocumentCV=or;exports.isCapturableAspect=Se;exports.measureQuality=Ce;exports.orderCorners=xe;exports.rectifiedAspect=z;exports.resolveTexts=Te;exports.sampleFrame=he;exports.setTorch=fe;exports.snapshotToBlob=me;exports.supportsTorch=ye;exports.typeHintFromAspect=ae;exports.useXidCameraOcr=Me;exports.warpDocument=Xe;exports.warpDocumentImageData=Be;exports.warpedSnapshotToBlob=Et;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var Tt=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,w=Tt();function Mt(e=typeof window>"u"?void 0:window){return e?typeof e.matchMedia=="function"?e.matchMedia("(orientation: portrait)").matches?"portrait":"landscape":e.innerHeight>e.innerWidth?"portrait":"landscape":"landscape"}function vt(e){return {audio:false,video:{facingMode:{ideal:"environment"},...e==="portrait"?{width:{ideal:1080},height:{ideal:1920},aspectRatio:{ideal:9/16}}:{width:{ideal:1920,min:640},height:{ideal:1080,min:480},aspectRatio:{ideal:16/9}}}}}async function ie(e,t,r=Mt()){let n=vt(r);if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw new Error("Camera unavailable: getUserMedia requires a secure context (HTTPS or localhost) and a browser with MediaDevices support.");let o;try{o=await navigator.mediaDevices.getUserMedia(t??n);}catch(s){if(!t)o=await navigator.mediaDevices.getUserMedia({audio:false,video:true});else throw s}e.srcObject=o,e.muted=true,e.playsInline=true,e.autoplay=true;let a=o.getVideoTracks()[0],i=a.getCapabilities?.();return i&&"focusMode"in i&&i.focusMode?.includes("continuous")&&a.applyConstraints({advanced:[{focusMode:"continuous"}]}).catch(()=>{}),await e.play().catch(()=>{}),o}function se(e,t){e.srcObject===t&&(e.srcObject=null),t?.getTracks().forEach(r=>r.stop());}async function ue(e,t=.92){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)throw new Error("Video stream not ready (videoWidth=0)");let o=document.createElement("canvas");o.width=r,o.height=n;let a=o.getContext("2d");if(!a)throw new Error("2D canvas context unavailable");return a.drawImage(e,0,0,r,n),new Promise((i,s)=>{o.toBlob(u=>u?i(u):s(new Error("Canvas toBlob returned null")),"image/jpeg",t);})}function Pe(e,t,r,n=.92){let o=document.createElement("canvas");o.width=r.width,o.height=r.height;let a=o.getContext("2d");return a?(a.imageSmoothingEnabled=true,a.imageSmoothingQuality="high",a.drawImage(e,t.x,t.y,t.width,t.height,0,0,r.width,r.height),new Promise((i,s)=>o.toBlob(u=>u?i(u):s(new Error("Canvas toBlob returned null")),"image/jpeg",n))):Promise.reject(new Error("2D canvas context unavailable"))}var L=null;function ce(e,t=640){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)return null;let o=Math.round(t),a=Math.round(n*t/r);L??=document.createElement("canvas"),(L.width!==o||L.height!==a)&&(L.width=o,L.height=a);let i=L.getContext("2d",{willReadFrequently:true});return i?(i.drawImage(e,0,0,o,a),i.getImageData(0,0,o,a)):null}function le(e){let t=e.getCapabilities;return typeof t!="function"?false:t.call(e).torch===true}async function de(e,t){try{return await e.applyConstraints({advanced:[{torch:t}]}),!0}catch{return false}}var Et="@andresxid/xid_camera_ocr_sdk_react";function Fe(e,t){return e.pathname.endsWith(`/${Et}/${t}`)}function Oe(e){return new URL(e,w)}function Ie(){return new URL("@andresxid/xid_camera_ocr_sdk_react/opencv.js",w)}function pe(){let e=Ie();return Fe(e,"opencv.js")?Oe("./opencv.js").href:e.href}function De(e){return e!==void 0?new Worker(e,{type:"module"}):Fe(Ie(),"opencv.js")?new Worker(Oe("./cv-worker.js"),{type:"module"}):new Worker(new URL("@andresxid/xid_camera_ocr_sdk_react/cv-worker.js",w),{type:"module"})}function He(e){if(!e||typeof e!="object")return null;let t=e;switch(t.type){case "ready":return {type:"ready"};case "init-error":return typeof t.error=="string"?{type:"init-error",error:t.error}:null;case "error":return typeof t.id=="number"&&typeof t.error=="string"?{type:"error",id:t.id,error:t.error}:null;case "analyze-result":return typeof t.id=="number"&&t.result&&typeof t.result=="object"?{type:"analyze-result",id:t.id,result:t.result}:null;case "warp-result":return typeof t.id=="number"&&typeof t.width=="number"&&typeof t.height=="number"&&t.buffer instanceof ArrayBuffer?{type:"warp-result",id:t.id,width:t.width,height:t.height,buffer:t.buffer}:null;default:return null}}function Le(e){let t=new Uint8ClampedArray(e.data.byteLength);return t.set(e.data),t.buffer}var _t=e=>e instanceof Error?e:new Error(String(e)),Q=class{initTimeoutMs;worker=null;readyPromise=null;rejectInit=null;initTimer=null;ready=false;pending=new Map;nextId=1;constructor(t={}){this.initTimeoutMs=t.initTimeoutMs??3e4;}init(t=pe(),r){if(this.readyPromise)return this.readyPromise;let n;try{n=De(r);}catch(a){return Promise.reject(_t(a))}this.worker=n;let o=new Promise((a,i)=>{this.rejectInit=i,this.initTimer=setTimeout(()=>this.fail(new Error(`OpenCV worker not ready within ${this.initTimeoutMs} ms`)),this.initTimeoutMs),n.addEventListener("message",s=>{if(this.worker!==n)return;let u=He(s.data);if(!u)return;if(u.type==="ready"){this.clearInitTimer(),this.rejectInit=null,this.ready=true,a();return}if(u.type==="init-error"){this.fail(new Error(u.error));return}let c=this.pending.get(u.id);c&&(this.pending.delete(u.id),u.type==="error"?c.reject(new Error(u.error)):c.resolve(u));}),n.addEventListener("error",s=>{this.worker===n&&this.fail(new Error(s.message||"Worker error"));}),n.addEventListener("messageerror",s=>{if(this.worker!==n)return;let u=new Error("Worker message could not be deserialized"),c=s.data?.id,d=typeof c=="number"?this.pending.get(c):void 0;if(typeof c=="number"&&d){this.pending.delete(c),d.reject(u);return}this.fail(u);});});return this.readyPromise=o,n.postMessage({type:"init",opencvUrl:t}),o}isReady(){return this.ready&&this.worker!==null}async analyze(t,r={}){let n=Le(t),o=r.prior,a=await this.request(i=>({type:"analyze",id:i,width:t.width,height:t.height,buffer:n,...o?{prior:o}:{}}),[n]);if(a.type!=="analyze-result")throw new Error(`Unexpected worker response: ${a.type}`);return a.result}async warp(t,r,n,o=1024){let a=Le(t),i=await this.request(s=>({type:"warp",id:s,width:t.width,height:t.height,buffer:a,corners:r,docType:n,longSide:o}),[a]);if(i.type!=="warp-result")throw new Error(`Unexpected worker response: ${i.type}`);return new ImageData(new Uint8ClampedArray(i.buffer),i.width,i.height)}terminate(){this.rejectInit=null,this.shutdown(new Error("Worker terminated"));}fail(t){let r=this.rejectInit;this.rejectInit=null,this.shutdown(t),r?.(t);}clearInitTimer(){this.initTimer!==null&&clearTimeout(this.initTimer),this.initTimer=null;}shutdown(t){this.clearInitTimer(),this.worker?.terminate(),this.worker=null,this.readyPromise=null,this.ready=false;let r=[...this.pending.values()];this.pending.clear();for(let n of r)n.reject(t);}request(t,r){let n=this.worker;if(!n||!this.ready)return Promise.reject(new Error("CVWorkerClient not ready"));let o=t(this.nextId++),a=new Promise((i,s)=>this.pending.set(o.id,{resolve:i,reject:s}));return n.postMessage(o,r),a}};var I=1.585772508336421,U=125/88,At=1.503,Pt=.05,K=1.25,me=1.75,Ft=.25;function he(e){if(e.length!==4)throw new Error(`orderCorners expects 4 points, got ${e.length}`);let t=(e[0].x+e[1].x+e[2].x+e[3].x)/4,r=(e[0].y+e[1].y+e[2].y+e[3].y)/4,n=[...e].sort((a,i)=>Math.atan2(a.y-r,a.x-t)-Math.atan2(i.y-r,i.x-t)),o=0;for(let a=1;a<4;a++){let i=n[a],s=n[o];(i.x+i.y<s.x+s.y||i.x+i.y===s.x+s.y&&i.y<s.y)&&(o=a);}return [0,1,2,3].map(a=>n[(o+a)%4])}function D(e){let t=0;for(let r=0;r<e.length;r++){let n=e[r],o=e[(r+1)%e.length];t+=n.x*o.y-o.x*n.y;}return Math.abs(t)/2}function $(e){let[t,r,n,o]=e;return {top:Math.hypot(r.x-t.x,r.y-t.y),right:Math.hypot(n.x-r.x,n.y-r.y),bottom:Math.hypot(n.x-o.x,n.y-o.y),left:Math.hypot(o.x-t.x,o.y-t.y)}}function Ot(e){let t=[0,0,0,0];for(let r=0;r<4;r++){let n=e[(r+3)%4],o=e[r],a=e[(r+1)%4],i=n.x-o.x,s=n.y-o.y,u=a.x-o.x,c=a.y-o.y,d=Math.hypot(i,s),p=Math.hypot(u,c);if(d===0||p===0){t[r]=0;continue}let m=Math.min(1,Math.max(-1,(i*u+s*c)/(d*p)));t[r]=Math.acos(m)*180/Math.PI;}return t}function Z(e,t=70,r=110){let n=$(e);return n.top<=0||n.right<=0||n.bottom<=0||n.left<=0||!It(e)||D(e)<=0?false:Ot(e).every(o=>o>=t&&o<=r)}function It(e){let t=0;for(let r=0;r<4;r++){let n=e[r],o=e[(r+1)%4],a=e[(r+2)%4],i=(o.x-n.x)*(a.y-o.y)-(o.y-n.y)*(a.x-o.x);if(i===0)return false;let s=Math.sign(i);if(t===0)t=s;else if(s!==t)return false}return true}function X(e){let t=$(e),r=(t.top+t.bottom)/2,n=(t.left+t.right)/2,o=Math.min(r,n);return o<=0?0:Math.max(r,n)/o}function Dt(e){if(!Number.isFinite(e))return 0;let t=Math.min(Math.abs(e-I),Math.abs(e-U));return Math.max(0,1-t/Ft)}function Ue(e){return .5*e.areaRatio+.3*e.rectangularity+.2*Dt(e.aspect)}function J(e){let t=e>=At?I:U;return Math.abs(e-t)/t<=Pt?t===I?"INE":"PASSPORT_MX":"OTHER"}function ye(e){return e>=K&&e<=me}function Be(e,t){return e==="INE"?I:e==="PASSPORT_MX"?U:t}var N=1024,Qe=1600;function Xe(e,t,r,n,o=N){let a=Lt(Be(n,X(r))),i=Math.max(1,Math.round(o/a)),s=$(r),u=s.top+s.bottom<s.left+s.right,c=n==="INE"||n==="PASSPORT_MX",d=u&&c?[r[3],r[0],r[1],r[2]]:r,p=!u||c,m=p?o:i,l=p?i:o,x=null,S=null,y=null,b=null,h=null,f=null;try{return x=e.matFromImageData(t),S=new e.Mat,y=e.matFromArray(4,1,e.CV_32FC2,[d[0].x,d[0].y,d[1].x,d[1].y,d[2].x,d[2].y,d[3].x,d[3].y]),b=e.matFromArray(4,1,e.CV_32FC2,[0,0,m,0,m,l,0,l]),h=e.getPerspectiveTransform(y,b),e.warpPerspective(x,S,h,new e.Size(m,l),e.INTER_LINEAR,e.BORDER_CONSTANT,new e.Scalar(0,0,0,255)),S.channels()!==4&&(f=new e.Mat,e.cvtColor(S,f,e.COLOR_BGR2RGBA)),Ut(new Uint8ClampedArray((f??S).data),m,l)}finally{for(let T of [f,h,b,y,S,x])T?.delete();}}function Ne(e,t,r,n,o=N){let a=t.getContext("2d",{willReadFrequently:true});if(!a)throw new Error("2D canvas context unavailable");let i=a.getImageData(0,0,t.width,t.height),s=Xe(e,i,r,n,o),u=document.createElement("canvas");u.width=s.width,u.height=s.height;let c=u.getContext("2d");if(!c)throw new Error("2D canvas context unavailable (output)");return c.putImageData(s,0,0),u}async function Ht(e,t,r,n,o=.92,a=N){let i=r?Ne(e,t,r,n,a):t;return new Promise((s,u)=>{i.toBlob(c=>c?s(c):u(new Error("Canvas toBlob returned null")),"image/jpeg",o);})}function Lt(e){return Number.isFinite(e)?Math.min(me,Math.max(K,e)):K}function Ut(e,t,r){return typeof globalThis.ImageData=="function"?new ImageData(e,t,r):{data:e,width:t,height:r,colorSpace:"srgb"}}var Bt=.85,Qt=.7;function H(e){return e?.[0]==="PASSPORT_MX"?U:I}function q(e,t){let r=e.width*Bt,n=e.height*Qt,o=r,a=o/t;return a>n&&(a=n,o=a*t),{width:o,height:a}}var qe=e=>Number.isFinite(e)&&e>0,fe=e=>qe(e.width)&&qe(e.height);function We(e,t,r){if(!fe(e)||!fe(t)||!fe(r))return null;let n=Math.max(t.width/e.width,t.height/e.height),o=(t.width-e.width*n)/2,a=(t.height-e.height*n)/2,i=Math.round(((t.width-r.width)/2-o)/n),s=Math.round(((t.height-r.height)/2-a)/n),u=i+Math.round(r.width/n),c=s+Math.round(r.height/n),d=Math.max(0,i),p=Math.max(0,s),m=Math.min(e.width,u),l=Math.min(e.height,c);return m<=d||l<=p?null:{x:d,y:p,width:m-d,height:l-p}}function je(e,t){let r=Math.max(e.width,e.height);if(r<=t)return {width:e.width,height:e.height};let n=t/r;return {width:Math.max(1,Math.round(e.width*n)),height:Math.max(1,Math.round(e.height*n))}}var k={brightnessMin:.18,brightnessMax:.9,blurMin:60,glareMax:.04,fillMin:.25,glarePixel:248};function W(e,t,r){let n=new Int32Array(r*2);for(let o=0;o<r;o++){let a=o+.5,i=1/0,s=-1/0;for(let u=0;u<4;u++){let c=e[u],d=e[(u+1)%4],p=Math.min(c.y,d.y),m=Math.max(c.y,d.y);if(a<p||a>m||m===p)continue;let l=c.x+(a-c.y)*(d.x-c.x)/(d.y-c.y);l<i&&(i=l),l>s&&(s=l);}if(i===1/0){n[o*2]=0,n[o*2+1]=0;continue}n[o*2]=Math.max(0,Math.ceil(i-.5)),n[o*2+1]=Math.min(t,Math.floor(s+.5));}return n}function be(e,t){let{data:r,width:n,height:o}=e,a=W(t,n,o),i=k.glarePixel,s=0,u=0,c=0,d=0,p=0,m=0;for(let f=0;f<o;f++){let T=a[f*2],R=a[f*2+1];if(T>=R)continue;let M=0,v=0;f>0&&f<o-1&&(M=Math.max(T,a[(f-1)*2],a[(f+1)*2])+1,v=Math.min(R,a[(f-1)*2+1],a[(f+1)*2+1])-1);let C=f*n;for(let E=T;E<R;E++){let _=C+E,P=r[_];if(s+=P,P>=i&&u++,c++,E>=M&&E<v){let O=4*P-r[_-n]-r[_+n]-r[_-1]-r[_+1];d+=O,p+=O*O,m++;}}}let l=c>0?s/c/255:0,x=c>0?u/c:0,S=m>0?Math.max(0,p/m-(d/m)**2):0,y=n*o,b=y>0?D(t)/y:0,h=l>=k.brightnessMin&&l<=k.brightnessMax&&S>=k.blurMin&&x<=k.glareMax&&b>=k.fillMin;return {brightness:l,blurScore:S,glareRatio:x,docFillRatio:b,ok:h}}function ze(e){let{data:t}=e;if(t.length===0)return 0;let r=0;for(let n=0;n<t.length;n++)r+=t[n];return r/t.length/255}function ge(e){if(!e.detected||!e.quality)return "no_document";let t=e.quality;return !Number.isFinite(t.docFillRatio)||t.docFillRatio<k.fillMin?"too_small":!Number.isFinite(t.brightness)||t.brightness<k.brightnessMin?"too_dark":!Number.isFinite(t.glareRatio)||t.glareRatio>k.glareMax||t.brightness>k.brightnessMax?"glare":!Number.isFinite(t.blurScore)||t.blurScore<k.blurMin?"blurry":e.stableFrames<e.stableFramesRequired?"hold_still":"ready"}var Xt=k.brightnessMin;function Ve(e){return !e.torchSupported||e.torchOn?false:(e.quality?e.quality.brightness:e.frameBrightness)<Xt}var xe=Object.freeze({idle:"Toca para activar la c\xE1mara",starting:"Abriendo la c\xE1mara\u2026",loading_detector:"Preparando la c\xE1mara\u2026",no_document:"Coloca tu identificaci\xF3n dentro del recuadro",too_small:"Acerca m\xE1s tu identificaci\xF3n",too_dark:"Hay poca luz, busca un lugar m\xE1s iluminado",glare:"Hay un reflejo, inclina un poco tu identificaci\xF3n",blurry:"Espera a que la c\xE1mara enfoque",hold_still:"Mant\xE9n la c\xE1mara quieta",ready:"\xA1Perfecto! Toma la foto",capturing:"Tomando la foto\u2026",uploading:"Revisando tu identificaci\xF3n\u2026",done:"\xA1Listo!",error:"Algo sali\xF3 mal, int\xE9ntalo de nuevo",detector_unavailable:"Toma la foto con el bot\xF3n",retake:"Tomar otra vez",capture:"Tomar foto",tip_light:"Busca un lugar con buena luz",tip_glare:"Evita reflejos: no apuntes una l\xE1mpara directo a tu identificaci\xF3n",tip_focus:"Espera a que la c\xE1mara enfoque y luego toca el bot\xF3n",tips_dismiss:"Entendido"}),Nt=Object.freeze({idle:"Ready to start",starting:"Starting camera\u2026",loading_detector:"Loading detector\u2026",no_document:"Place the document inside the frame",too_small:"Move closer to the document",too_dark:"Find more light",glare:"Tilt the document to avoid glare",blurry:"Hold still to focus",hold_still:"Hold the camera steady",ready:"Perfect! Take the photo",capturing:"Capturing\u2026",uploading:"Processing document\u2026",done:"Done",error:"Something went wrong \u2014 try again",detector_unavailable:"Detector unavailable \u2014 capture manually",retake:"Capture again",capture:"Capture now",tip_light:"Find a well-lit place",tip_glare:"Avoid glare: don't point a lamp straight at your ID",tip_focus:"Wait for the camera to focus, then tap the button",tips_dismiss:"Got it"}),qt=["loading_detector","capturing","uploading","done","error"];function Wt(e){return qt.includes(e)}function j(e,t){return t?.[e]??xe[e]}function Se(e){let t={...xe};for(let r of Object.keys(t))t[r]=j(r,e);return t}function ee(e,t,r){return e==="idle"||e==="stopped"?j("idle",r):e==="starting"?j("starting",r):Wt(e)?j(e,r):j(t??"no_document",r)}var jt=.05;function zt(e,t,r){let n=r.width/t.width,o=r.height/t.height;return e.map(a=>({x:a.x*n,y:a.y*o}))}function Vt(e,t){return e.map(r=>({x:Math.min(t.width,Math.max(0,r.x)),y:Math.min(t.height,Math.max(0,r.y))}))}function Ge(e,t,r){let n=Vt(zt(e,t,r),r);return !Z(n)||D(n)<jt*r.width*r.height?null:n}var Ye={stableFrames:0,isStable:false,quad:null,typeHint:null},z=class{required;maxRatio;switchFrames;current=Ye;candidate=null;constructor(t={}){this.required=t.stableFramesRequired??10,this.maxRatio=t.maxDisplacementRatio??.015,this.switchFrames=Math.max(1,t.hintSwitchFrames??3);}get snapshot(){return this.current}reset(){this.current=Ye,this.candidate=null;}update(t,r){if(!t)return this.reset(),this.current;let n=Math.hypot(r.width,r.height)*this.maxRatio,o=this.current,a=o.quad!==null&&o.quad.every((u,c)=>Math.hypot(t.quad[c].x-u.x,t.quad[c].y-u.y)<=n),i=o.typeHint??t.typeHint,s=a?o.stableFrames+1:1;if(t.typeHint===i)this.candidate=null;else {let u=this.candidate?.typeHint===t.typeHint?this.candidate.frames+1:1;this.candidate={typeHint:t.typeHint,frames:u},u>=this.switchFrames&&(i=t.typeHint,s=1,this.candidate=null);}return this.current={stableFrames:s,isStable:s>=this.required,quad:t.quad,typeHint:i},this.current}};var Yt=640,Kt=10,Ke=1500,$t=35e3,Zt=5,Jt={createWorkerClient:e=>new Q(e),attachCamera:e=>ie(e),detachCamera:se,sampleFrame:ce,cropFrame:Pe,snapshotToBlob:ue,supportsTorch:le,setTorch:de,now:()=>performance.now()},$e=e=>e.provenance==="reduced"||e.provenance==="lowres",Ze=e=>e instanceof Error?e:new Error(String(e)),Je=e=>e.map(t=>({x:t.x,y:t.y})),V=class{opts;deps;stream=null;track=null;cv=null;generation=0;timer=null;frameCallback=null;warmupUntil=0;capturing=false;autoShutterSpent=false;torchSupported=false;torchOn=false;torchRejected=false;weakRun=false;prior=null;stability;state={status:"idle",lastFrame:null,lastResult:null,lastError:null};constructor(t,r={}){this.opts={videoElement:t.videoElement,documentTypes:t.documentTypes??["INE","PASSPORT_MX"],cropToGuide:t.cropToGuide??false,guideRatio:t.guideRatio,autoCapture:t.autoCapture??false,stableFramesRequired:t.stableFramesRequired??10,captureQuality:t.captureQuality??.92,captureResolution:t.captureResolution??"standard",opencvUrl:t.opencvUrl,workerUrl:t.workerUrl,onUpload:t.onUpload,onFrameAnalyzed:t.onFrameAnalyzed,onCaptured:t.onCaptured,onResult:t.onResult,onError:t.onError},this.deps={...Jt,...r},this.stability=new z({stableFramesRequired:this.opts.stableFramesRequired});}async start(){if(!["idle","stopped","error"].includes(this.state.status))throw new Error(`Cannot start session from status=${this.state.status}`);this.release();let t=++this.generation;this.setStatus("starting"),this.state.lastError=null;try{let r=await this.deps.attachCamera(this.opts.videoElement);if(t!==this.generation){this.deps.detachCamera(this.opts.videoElement,r);return}this.stream=r,this.track=r.getVideoTracks()[0]??null,this.torchSupported=this.track?this.deps.supportsTorch(this.track):!1,this.warmupUntil=0,this.setStatus("loading_detector");let n=this.deps.createWorkerClient({initTimeoutMs:$t});this.cv=n,n.init(this.opts.opencvUrl,this.opts.workerUrl).then(()=>{t!==this.generation||this.cv!==n||(this.state.status==="loading_detector"&&this.setStatus("streaming"),this.scheduleNext(t,0));},o=>this.detectorUnavailable(t,n,o));}catch(r){throw t===this.generation&&this.emitError(r),r}}stop(){this.generation++,this.release(),this.setStatus("stopped");}async captureNow(){if(this.capturing)return;let t=this.state.status;if(t!=="streaming"&&t!=="loading_detector"&&!(t==="done"&&this.stream))throw new Error(`Cannot capture from status=${this.state.status}`);let r=this.stability.snapshot,n=this.state.lastFrame?.frameSize??null,o=r.quad&&n?this.fullFrameQuad(r.quad,n):null;await this.doCapture(this.generation,o?r.typeHint:null);}getState(){return {...this.state}}scheduleNext(t,r){this.timer=setTimeout(()=>{if(this.timer=null,t!==this.generation)return;let n=this.opts.videoElement;typeof n.requestVideoFrameCallback=="function"?this.frameCallback=n.requestVideoFrameCallback(()=>{this.frameCallback=null,this.tick(t);}):this.tick(t);},r);}async tick(t){if(t!==this.generation)return;let r=this.deps.now();try{await this.analyzeFrame(t);}catch(n){t===this.generation&&console.warn("[xid-camera-ocr] analyzeFrame error:",n);}t!==this.generation||!this.cv||this.scheduleNext(t,Math.max(0,1e3/Kt-(this.deps.now()-r)));}async analyzeFrame(t){let r=this.cv;if(this.capturing||!r?.isReady())return;let n=this.deps.sampleFrame(this.opts.videoElement,Yt);if(!n)return;let o={width:n.width,height:n.height};this.warmupUntil===0&&(this.warmupUntil=this.deps.now()+Ke);let a=this.prior&&this.prior.width===n.width&&this.prior.height===n.height?this.prior.quad:null,i;try{i=await r.analyze(n,a?{prior:a}:{});}catch(m){if(t===this.generation&&this.cv===r&&!r.isReady()){this.detectorUnavailable(t,r,m);return}throw m}if(t!==this.generation||this.capturing)return;this.prior=i.detected&&i.corners?{quad:Je(i.corners),...o}:null;let u=!(this.deps.now()<this.warmupUntil)&&i.detected&&i.corners&&i.documentType?{quad:i.corners,typeHint:i.documentType}:null,c=this.stability.update(u,o);this.weakRun=c.stableFrames<=1?u!==null&&$e(i):this.weakRun||$e(i);let d=this.opts.stableFramesRequired+(this.weakRun?Zt:0);if(await this.updateTorch(t,i),t!==this.generation)return;let p={detected:i.detected,documentType:i.documentType,confidence:Math.min(c.stableFrames/d,1),aspectRatio:i.aspectRatio,quality:i.quality,corners:i.corners?Je(i.corners):null,frameSize:o,hint:ge({detected:i.detected,quality:i.quality,stableFrames:c.stableFrames,stableFramesRequired:d}),...this.torchSupported?{torch:this.torchOn}:{}};if(this.state.lastFrame=p,this.opts.onFrameAnalyzed?.(p),t===this.generation&&this.opts.autoCapture&&!this.autoShutterSpent&&c.quad&&c.stableFrames>=d&&i.quality?.ok){if(!this.fullFrameQuad(c.quad,o)){this.stability.reset(),this.weakRun=false;return}await this.doCapture(t,c.typeHint);}}detectorUnavailable(t,r,n){if(t!==this.generation||this.cv!==r)return;r.terminate(),this.cv=null,this.prior=null,this.stability.reset(),this.weakRun=false,this.autoShutterSpent=true,this.state.status==="loading_detector"&&this.setStatus("streaming");let o=Ze(n);this.state.lastError=o;let a={detected:false,documentType:null,confidence:0,aspectRatio:null,quality:null,corners:null,frameSize:null,hint:"detector_unavailable",...this.torchSupported?{torch:this.torchOn}:{}};this.state.lastFrame=a,this.opts.onFrameAnalyzed?.(a),t===this.generation&&this.opts.onError?.(o);}async updateTorch(t,r){if(!this.track||this.torchRejected||!Ve({torchSupported:this.torchSupported,torchOn:this.torchOn,quality:r.quality,frameBrightness:r.frameBrightness}))return;let n=await this.deps.setTorch(this.track,true);t===this.generation&&(this.torchOn=n,n||(this.torchRejected=true));}fullFrameQuad(t,r){let n=this.opts.videoElement;return !n.videoWidth||!n.videoHeight?null:Ge(t,r,{width:n.videoWidth,height:n.videoHeight})}async doCapture(t,r){if(!this.capturing){this.capturing=true,this.autoShutterSpent=true,this.prior=null,this.stability.reset(),this.weakRun=false,this.setStatus("capturing");try{let{blob:n,type:o}=await this.captureBlob(t,r);if(t!==this.generation)return;this.opts.onCaptured?.(n,o),this.setStatus("uploading");let a=await this.opts.onUpload(n,o);if(t!==this.generation)return;this.state.lastResult=a,this.setStatus("done"),this.opts.onResult?.(a);}catch(n){t===this.generation&&this.emitError(n);}finally{t===this.generation&&(this.stability.reset(),this.weakRun=false,this.warmupUntil=this.deps.now()+Ke,this.capturing=false);}}}async captureBlob(t,r){let n=this.opts.videoElement,o=async()=>({blob:await this.deps.snapshotToBlob(n,this.opts.captureQuality),type:null});if(!this.opts.cropToGuide)return {blob:await this.deps.snapshotToBlob(n,this.opts.captureQuality),type:r};let a={width:n.clientWidth,height:n.clientHeight},i=this.opts.guideRatio?.()??H(this.opts.documentTypes),s=We({width:n.videoWidth,height:n.videoHeight},a,q(a,i));if(!s)return o();try{let u=this.opts.captureResolution==="high"?Qe:N;return {blob:await this.deps.cropFrame(n,s,je(s,u),this.opts.captureQuality),type:r}}catch(u){if(t!==this.generation)throw u;return console.warn("[xid-camera-ocr] guide crop failed, using plain snapshot:",u),o()}}release(){this.prior=null,this.timer!==null&&clearTimeout(this.timer),this.timer=null,this.frameCallback!==null&&(this.opts.videoElement.cancelVideoFrameCallback?.(this.frameCallback),this.frameCallback=null),this.track&&this.torchOn&&this.deps.setTorch(this.track,false),this.torchOn=false,this.torchRejected=false,this.stream&&this.deps.detachCamera(this.opts.videoElement,this.stream),this.stream=null,this.track=null,this.cv?.terminate(),this.cv=null,this.stability.reset(),this.weakRun=false,this.capturing=false,this.autoShutterSpent=false;}setStatus(t){this.state.status=t;}emitError(t){let r=Ze(t);this.state.lastError=r,this.setStatus("error"),this.opts.onError?.(r);}};var et=.08,er=.95,tr=.02,B=8,rr=2,tt=8,rt=.33,te=2,nr=2,or=1,ar=nr+te,ir=2,sr=2*(te+1),ur=10,nt=1.1,st=te+1,cr=6,ut=.92,lr=1/ut,dr=.85,pr=2,mr=.05,ot=2,at=64;function ct(e){return {detected:false,documentType:null,aspectRatio:null,corners:null,boundingBox:null,quality:null,frameBrightness:e,score:null}}function hr(e,t,r,n={}){let o={brightness:0};try{return yr(e,t,o,n.prior??null)}catch(a){return console.warn("[xid-camera-ocr] detectDocumentCV failed:",a),ct(o.brightness)}}function yr(e,t,r,n){let{width:o,height:a}=t,i=[],s=u=>(i.push(u),u);try{let u=s(e.matFromImageData(t)),c=s(new e.Mat),d=s(new e.Mat),p={equalized:s(new e.Mat),filtered:s(new e.Mat),padded:s(new e.Mat),edges:s(new e.Mat),dilated:s(new e.Mat),kernel:s(e.Mat.ones(3,3,e.CV_8U)),contours:s(new e.MatVector),hierarchy:s(new e.Mat),hull:s(new e.Mat),approx:s(new e.Mat),clahe:s(new e.CLAHE(rr,new e.Size(tt,tt)))};e.cvtColor(u,c,e.COLOR_RGBA2GRAY),r.brightness=ze(we(c,o,a));let m=[],l=it(e,c,p,o,a,m,n),x=!1,S=Math.round(o/ot),y=Math.round(a/ot);if(!l&&S>=at&&y>=at&&(e.resize(c,d,new e.Size(S,y),0,0,e.INTER_AREA),l=it(e,d,p,o,a,m,n),x=l!==null),l&&wr(l,m,we(c,o,a))&&(l=null),!l)return ct(r.brightness);let b=x?"lowres":l.reduced?"reduced":"direct",h=l.quad.map(C=>C.x),f=l.quad.map(C=>C.y),T=Math.min(...h),R=Math.max(...h),M=Math.min(...f),v=Math.max(...f);return {detected:!0,documentType:J(l.aspect),aspectRatio:l.aspect,corners:l.quad,boundingBox:{x:T/o,y:M/a,width:(R-T)/o,height:(v-M)/a},quality:be(we(c,o,a),pt(l.quad,st*l.scale)),frameBrightness:r.brightness,score:b==="direct"?l.score:l.score*dr,provenance:b}}finally{for(let u of i)u.delete();}}function it(e,t,r,n,o,a,i){let s=t.cols,u=t.rows,c=n/s,d=o/u,p=s*u,m=h=>({x:h.x*c,y:h.y*d}),{hull:l,approx:x,contours:S}=r;r.clahe.apply(t,r.equalized),e.bilateralFilter(r.equalized,r.filtered,9,75,75,e.BORDER_DEFAULT),e.copyMakeBorder(r.filtered,r.padded,B,B,B,B,e.BORDER_CONSTANT,new e.Scalar(0));let y=Mr(r.padded.data);e.Canny(r.padded,r.edges,Math.max(10,(1-rt)*y),Math.min(255,(1+rt)*y)),e.dilate(r.edges,r.dilated,r.kernel,new e.Point(-1,-1),te),e.findContours(r.dilated,S,r.hierarchy,e.RETR_LIST,e.CHAIN_APPROX_SIMPLE);let b=null;for(let h=0;h<S.size();h++){let f=S.get(h);try{let T=e.boundingRect(f);if(T.width*T.height<p*et)continue;e.convexHull(f,l,!1,!0);let R=e.contourArea(l);if(R<p*et||R>p*er||(e.approxPolyDP(l,x,tr*e.arcLength(l,!0),!0),x.rows<4||x.rows>cr||!e.isContourConvex(x)))continue;let M=x.rows!==4,v;if(!M)v=br(x,s,u);else {let _e=gr(lt(x));if(!_e)continue;v=_e.map(Rt=>dt(Rt,s,u));let Ae=R/D(v);if(!(Ae>=ut&&Ae<=lr))continue}let C=R*c*d,E=v.map(m),_=ar*c;if(Tr(E,n,o,_)>or){Sr(E,n,o,_)||a.push({pts:E,area:C});continue}let P=he(E);if(!Z(P))continue;let O=e.minAreaRect(M?l:x),Ee=O.size.width*O.size.height,Ct=Ee>0?Math.min(1,R/Ee):0,oe=X(P);if(!ye(oe))continue;let ae=Ue({areaRatio:R/p,rectangularity:Ct,aspect:oe}),ke=i?ae-fr(P,i,n,o):ae;(!b||ke>b.rank)&&(b={quad:P,score:ae,rank:ke,aspect:oe,area:C,scale:c,reduced:M});}finally{f.delete();}}return b}function fr(e,t,r,n){let o=1/0;for(let a=0;a<4;a++){let i=0;for(let s=0;s<4;s++){let u=e[(s+a)%4];i=Math.max(i,Math.hypot(u.x-t[s].x,u.y-t[s].y));}o=Math.min(o,i);}return pr*Math.min(o/Math.hypot(r,n),mr)}function we(e,t,r){return {data:e.data,width:t,height:r}}function lt(e){let t=e.data32S,r=[];for(let n=0;n<e.rows;n++)r.push({x:t[n*2]-B,y:t[n*2+1]-B});return r}function dt(e,t,r){return {x:Math.min(t,Math.max(0,e.x)),y:Math.min(r,Math.max(0,e.y))}}function br(e,t,r){return lt(e).map(n=>dt(n,t,r))}function gr(e){let t=e;for(;t.length>4;){let r=t.length,n=-1,o=1/0,a=null;for(let s=0;s<r;s++){let u=t[(s+r-1)%r],c=t[s],d=t[(s+1)%r],p=t[(s+2)%r],m=xr(u,c,p,d);if(!m)continue;let l=Math.abs((m.x-c.x)*(d.y-c.y)-(m.y-c.y)*(d.x-c.x))/2;l<o&&(o=l,n=s,a=m);}if(n<0||!a)return null;let i=[];for(let s=0;s<r;s++)s===n?i.push(a):s!==(n+1)%r&&i.push(t[s]);t=i;}return t}function xr(e,t,r,n){let o=t.x-e.x,a=t.y-e.y,i=n.x-r.x,s=n.y-r.y,u=o*s-a*i;if(Math.abs(u)<1e-9)return null;let c=((r.x-e.x)*s-(r.y-e.y)*i)/u,d=((r.x-e.x)*a-(r.y-e.y)*o)/u;return c<1||d<1?null:{x:e.x+c*o,y:e.y+c*a}}function Sr(e,t,r,n){let o=e.map(i=>i.x),a=e.map(i=>i.y);return Math.min(...o)<=n&&Math.max(...o)>=t-n||Math.min(...a)<=n&&Math.max(...a)>=r-n}function wr(e,t,r){let n=sr*e.scale;if(!t.some(s=>s.area>=ir*e.area&&e.quad.every(u=>Rr(s.pts,u,n))))return false;if(J(e.aspect)==="OTHER")return true;let{inner:a,ring:i}=Cr(r,pt(e.quad,st*e.scale),e.quad);return a<i-ur}function Cr(e,t,r){let{data:n,width:o,height:a}=e,i=(r[0].x+r[1].x+r[2].x+r[3].x)/4,s=(r[0].y+r[1].y+r[2].y+r[3].y)/4,u=r.map(y=>({x:i+(y.x-i)*nt,y:s+(y.y-s)*nt})),c=W(u,o,a),d=W(r,o,a),p=W(t,o,a),m=0,l=0,x=0,S=0;for(let y=0;y<a;y++){let b=c[y*2],h=c[y*2+1];if(b>=h)continue;let f=d[y*2],T=d[y*2+1],R=p[y*2],M=p[y*2+1],v=y*o;for(let C=b;C<h;C++){let E=n[v+C];C>=R&&C<M?(m+=E,l++):(C<f||C>=T)&&(x+=E,S++);}}return {inner:l>0?m/l:0,ring:S>0?x/S:0}}function Rr(e,t,r){let n=0;for(let a=0;a<e.length;a++){let i=e[a],s=e[(a+1)%e.length];n+=i.x*s.y-s.x*i.y;}let o=Math.sign(n);if(o===0)return false;for(let a=0;a<e.length;a++){let i=e[a],s=e[(a+1)%e.length],u=Math.hypot(s.x-i.x,s.y-i.y);if(u===0)continue;if(o*((s.x-i.x)*(t.y-i.y)-(s.y-i.y)*(t.x-i.x))/u<r)return false}return true}function pt(e,t){return e.map((r,n)=>{let o=e[(n+3)%4],a=e[(n+1)%4],i=o.x-r.x,s=o.y-r.y,u=a.x-r.x,c=a.y-r.y,d=Math.hypot(i,s),p=Math.hypot(u,c),m=i/d+u/p,l=s/d+c/p,x=Math.hypot(m,l),S=Math.sin(Math.acos(Math.min(1,Math.max(-1,(i*u+s*c)/(d*p))))/2),y=t/S/x;return {x:r.x+m*y,y:r.y+l*y}})}function Tr(e,t,r,n){let o=0;for(let a of e)(a.x<=n||a.x>=t-n||a.y<=n||a.y>=r-n)&&o++;return o}function Mr(e){let t=new Uint32Array(256);for(let n=0;n<e.length;n++)t[e[n]]++;let r=0;for(let n=0;n<256;n++)if(r+=t[n],r>=e.length/2)return n;return 128}function Re(e){let t=react.useRef(null),r=react.useRef(null),[n,o]=react.useState("idle"),[a,i]=react.useState(null),[s,u]=react.useState(null),[c,d]=react.useState(null),p=react.useRef(e);p.current=e;let m=react.useCallback(()=>{if(r.current)return r.current;if(!t.current)throw new Error("videoRef not attached yet");let b=new V({videoElement:t.current,documentTypes:p.current.documentTypes,cropToGuide:p.current.cropToGuide,guideRatio:()=>H(p.current.documentTypes),autoCapture:p.current.autoCapture,stableFramesRequired:p.current.stableFramesRequired,captureQuality:p.current.captureQuality,captureResolution:p.current.captureResolution,opencvUrl:p.current.opencvUrl,workerUrl:p.current.workerUrl,onUpload:(h,f)=>p.current.onUpload(h,f),onFrameAnalyzed:h=>{i(h),r.current===b&&o(b.getState().status),p.current.onFrameAnalyzed?.(h);},onCaptured:(h,f)=>{o("capturing"),p.current.onCaptured?.(h,f);},onResult:h=>{u(h),o("done"),p.current.onResult?.(h);},onError:h=>{d(h),r.current===b&&o(b.getState().status),p.current.onError?.(h);}});return r.current=b,b},[]),l=react.useCallback(async()=>{let b=m();await b.start(),r.current===b&&o(b.getState().status);},[m]),x=react.useCallback(()=>{r.current?.stop(),o("stopped");},[]),S=react.useCallback(async()=>{await r.current?.captureNow();},[]),y=react.useCallback(async()=>{x(),u(null),d(null),i(null),await l();},[x,l]);return react.useEffect(()=>(e.autoStart!==false&&t.current&&l().catch(()=>{}),()=>{r.current?.stop(),r.current=null;}),[]),{videoRef:t,status:n,frame:a,result:s,error:c,start:l,stop:x,captureNow:S,retake:y}}function kr({status:e,showTips:t,dismissed:r,completedOnce:n}){return t&&!r&&(e==="error"||!n&&(e==="starting"||e==="loading_detector"))}function mt(e,t){let[r,n]=react.useState(false),[o,a]=react.useState(e==="done"),[i,s]=react.useState(e),u=r,c=o;i!==e&&(s(e),e==="error"&&(u=false,n(false)),e==="done"&&(c=true,a(true)));let d=react.useCallback(()=>n(true),[]);return {visible:kr({status:e,showTips:t,dismissed:u,completedOnce:c}),dismiss:d}}var ne={accent:{name:"--xco-accent",fallback:"#22c55e"},warning:{name:"--xco-warning",fallback:"#eab308"},danger:{name:"--xco-danger",fallback:"#ef4444"},background:{name:"--xco-background",fallback:"#000"},mask:{name:"--xco-mask",fallback:"rgba(0,0,0,0.4)"},hintBg:{name:"--xco-hint-bg",fallback:"rgba(0,0,0,0.7)"},hintFg:{name:"--xco-hint-fg",fallback:"white"},buttonBg:{name:"--xco-button-bg",fallback:"rgba(255,255,255,0.92)"},buttonFg:{name:"--xco-button-fg",fallback:"#111"},shutter:{name:"--xco-shutter",fallback:"rgba(255,255,255,0.9)"},overlayBg:{name:"--xco-overlay-bg",fallback:"rgba(0,0,0,0.78)"},overlayFg:{name:"--xco-overlay-fg",fallback:"white"},fontFamily:{name:"--xco-font-family",fallback:"system-ui, -apple-system, sans-serif"},radius:{name:"--xco-radius",fallback:"12px"}};function g(e){let{name:t,fallback:r}=ne[e];return `var(${t}, ${r})`}function ht(e){let t={};if(!e)return t;for(let r of Object.keys(e)){if(!Object.prototype.hasOwnProperty.call(ne,r))continue;let n=e[r];typeof n!="string"||n===""||(t[ne[r].name]=n);}return t}function yt(e,t){return e==="done"?g("accent"):e==="error"?g("danger"):e==="uploading"||e==="capturing"?g("accent"):t?.detected?t.confidence>=1?g("accent"):g("warning"):g("danger")}var Me={width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",style:{flex:"0 0 auto"}},_r=()=>jsxRuntime.jsxs("svg",{...Me,children:[jsxRuntime.jsx("circle",{cx:"12",cy:"12",r:"4"}),jsxRuntime.jsx("path",{d:"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"})]}),Ar=()=>jsxRuntime.jsxs("svg",{...Me,children:[jsxRuntime.jsx("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),jsxRuntime.jsx("path",{d:"M14 5l-6 14M18 5l-6 14"})]}),Pr=()=>jsxRuntime.jsxs("svg",{...Me,children:[jsxRuntime.jsx("path",{d:"M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3"}),jsxRuntime.jsx("circle",{cx:"12",cy:"12",r:"2"})]});function ft({texts:e,onDismiss:t}){let r=[{Icon:_r,text:e.tip_light},{Icon:Ar,text:e.tip_glare},{Icon:Pr,text:e.tip_focus}];return jsxRuntime.jsxs("div",{className:"xco-tips",style:Fr,children:[jsxRuntime.jsx("ul",{style:Or,children:r.map(({Icon:n,text:o})=>jsxRuntime.jsxs("li",{style:Ir,children:[jsxRuntime.jsx(n,{}),jsxRuntime.jsx("span",{children:o})]},o))}),jsxRuntime.jsx("button",{type:"button",className:"xco-tips-dismiss",onClick:t,style:Dr,children:e.tips_dismiss})]})}var Fr={position:"absolute",top:"calc(16px + env(safe-area-inset-top, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"calc(100% - 32px)",maxWidth:360,padding:16,background:g("overlayBg"),color:g("overlayFg"),borderRadius:g("radius"),fontFamily:g("fontFamily"),fontSize:15,lineHeight:1.35,display:"flex",flexDirection:"column",gap:12,pointerEvents:"auto",zIndex:5},Or={listStyle:"none",margin:0,padding:0,display:"flex",flexDirection:"column",gap:10},Ir={display:"flex",alignItems:"center",gap:12},Dr={alignSelf:"flex-end",minHeight:44,padding:"10px 20px",borderRadius:g("radius"),background:g("buttonBg"),color:g("buttonFg"),border:"none",fontFamily:g("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",WebkitTapHighlightColor:"transparent"};var Qr=typeof window>"u"?react.useEffect:react.useLayoutEffect;function gt({videoRef:e,status:t,frame:r,texts:n,documentTypes:o,theme:a,className:i,style:s,hideStatusOverlay:u,hideShutter:c,tipsVisible:d,onCapture:p,onRetake:m,onStart:l,onDismissTips:x}){let S=t==="streaming"||t==="loading_detector",y=t==="done"||t==="error",b=t==="idle"||t==="stopped",h=t==="capturing"||t==="uploading",f=react.useRef(null),[T,R]=react.useState({width:0,height:0}),M=H(o);Qr(()=>{let _=f.current;if(!_)return;let P=()=>R(q({width:_.clientWidth,height:_.clientHeight},M));P();let O=new ResizeObserver(P);return O.observe(_),()=>O.disconnect()},[M]);let v=yt(t,r),C=ee(t,r?.hint,n),E=i?`xid-camera-ocr ${i}`:"xid-camera-ocr";return jsxRuntime.jsxs("div",{ref:f,className:E,"data-status":t,"data-hint":r?.hint??"",style:{...Xr,...ht(a),...s},children:[jsxRuntime.jsx("style",{children:"@keyframes xco-spin { to { transform: rotate(360deg); } }"}),jsxRuntime.jsx("video",{ref:e,playsInline:true,muted:true,autoPlay:true,style:Nr}),!u&&jsxRuntime.jsx("div",{style:qr,children:jsxRuntime.jsx("div",{className:"xco-guide",style:{...Wr,width:T.width,height:T.height,borderColor:v}})}),!u&&(b?jsxRuntime.jsx("button",{type:"button",className:"xco-hint",onClick:l,style:$r,children:C}):jsxRuntime.jsx("p",{className:"xco-hint",style:St,role:"status","aria-live":"polite",children:C})),!u&&!c&&S&&jsxRuntime.jsx("button",{type:"button",className:"xco-shutter",onClick:p,"aria-label":n.capture,style:Gr,children:jsxRuntime.jsx("span",{style:Yr})}),!u&&y&&jsxRuntime.jsx("button",{type:"button",className:"xco-retake",onClick:m,"aria-label":n.retake,style:Kr,children:n.retake}),!u&&h&&jsxRuntime.jsxs("div",{className:"xco-loader",style:jr,"aria-busy":"true","aria-live":"polite",children:[jsxRuntime.jsx("div",{style:zr}),jsxRuntime.jsx("p",{style:Vr,children:ee(t,void 0,n)})]}),d&&!u&&jsxRuntime.jsx(ft,{texts:n,onDismiss:x})]})}var xt="calc(104px + env(safe-area-inset-bottom, 0px))",Xr={position:"relative",width:"100%",height:"100%",overflow:"hidden",background:g("background"),fontFamily:g("fontFamily"),touchAction:"none"},Nr={position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",display:"block"},qr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",pointerEvents:"none"},Wr={borderRadius:g("radius"),boxSizing:"content-box",borderWidth:4,borderStyle:"solid",boxShadow:`0 0 0 9999px ${g("mask")}`,transition:"border-color 200ms ease-in-out"},jr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:20,background:g("overlayBg"),backdropFilter:"blur(6px)",WebkitBackdropFilter:"blur(6px)",pointerEvents:"auto",zIndex:10},zr={width:56,height:56,borderRadius:"50%",border:"5px solid rgba(255, 255, 255, 0.18)",borderTopColor:g("accent"),animation:"xco-spin 0.85s linear infinite"},Vr={color:g("overlayFg"),fontFamily:g("fontFamily"),fontSize:15,fontWeight:500,margin:0,textAlign:"center",padding:"0 24px"},Gr={position:"absolute",bottom:xt,left:"50%",transform:"translateX(-50%)",width:68,height:68,borderRadius:"50%",background:"rgba(255,255,255,0.18)",border:`4px solid ${g("shutter")}`,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"auto",WebkitTapHighlightColor:"transparent",padding:0},Yr={width:52,height:52,borderRadius:"50%",background:"white",display:"block"},Kr={position:"absolute",bottom:xt,left:"50%",transform:"translateX(-50%)",minHeight:44,padding:"10px 20px",borderRadius:22,background:g("buttonBg"),color:g("buttonFg"),border:"none",fontFamily:g("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"},St={position:"absolute",bottom:"calc(16px + env(safe-area-inset-bottom, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"max-content",maxWidth:"calc(100% - 32px)",background:g("hintBg"),color:g("hintFg"),padding:"10px 16px",borderRadius:g("radius"),fontFamily:g("fontFamily"),fontSize:16,lineHeight:1.35,margin:0,whiteSpace:"normal",textAlign:"center"},$r={...St,border:"none",minHeight:44,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"};var nn=["INE","PASSPORT_MX"],ve=()=>{},wt=react.forwardRef(function({className:t,style:r,hideStatusOverlay:n,texts:o,theme:a,showTips:i,hideShutter:s,onStatusChange:u,...c},d){let{videoRef:p,status:m,frame:l,start:x,captureNow:S,retake:y}=Re({...c,cropToGuide:!n}),b=mt(m,i??true),h=react.useMemo(()=>Se(o),[o]),f=m==="streaming"||m==="loading_detector",T=m==="done"||m==="error",R=async()=>{f&&await S().catch(ve);},M=()=>{T&&y().catch(ve);},v=async()=>{await x().catch(ve);};react.useImperativeHandle(d,()=>({capture:R,retake:M,start:v}));let C=react.useRef(u);return C.current=u,react.useEffect(()=>{C.current?.(m);},[m]),jsxRuntime.jsx(gt,{videoRef:p,status:m,frame:l,texts:h,documentTypes:c.documentTypes??nn,theme:a,className:t,style:r,hideStatusOverlay:n,hideShutter:s,tipsVisible:b.visible,onCapture:()=>{R();},onRetake:M,onStart:()=>{v();},onDismissTips:b.dismiss})});wt.displayName="XidCameraOcr";exports.CVWorkerClient=Q;exports.DEFAULT_TEXTS_EN=Nt;exports.DEFAULT_TEXTS_ES=xe;exports.ID1_RATIO=I;exports.QUALITY_THRESHOLDS=k;exports.StabilityTracker=z;exports.TD3_RATIO=U;exports.XCO_VARS=ne;exports.XidCameraOcr=wt;exports.XidCameraOcrSession=V;exports.attachCamera=ie;exports.copyFor=ee;exports.decideHint=ge;exports.defaultOpencvUrl=pe;exports.detachCamera=se;exports.detectDocumentCV=hr;exports.guideBox=q;exports.guideRatioFor=H;exports.isCapturableAspect=ye;exports.measureQuality=be;exports.orderCorners=he;exports.rectifiedAspect=X;exports.resolveTexts=Se;exports.sampleFrame=ce;exports.setTorch=de;exports.snapshotToBlob=ue;exports.supportsTorch=le;exports.typeHintFromAspect=J;exports.useXidCameraOcr=Re;exports.warpDocument=Ne;exports.warpDocumentImageData=Xe;exports.warpedSnapshotToBlob=Ht;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map