@andresxid/xid_camera_ocr_sdk_react 0.1.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.
@@ -0,0 +1,459 @@
1
+ import * as react from 'react';
2
+
3
+ /** Default `opencv.js` URL (the bundled copy shipped with the package). */
4
+ declare function defaultOpencvUrl(): string;
5
+
6
+ /**
7
+ * Public SDK types.
8
+ */
9
+ /**
10
+ * Shape hint produced by the detector. `INE` = ID-1 card shape (INE, licence,
11
+ * cédula…), `PASSPORT_MX` = TD3 passport shape of any country, `OTHER` = another
12
+ * quadrilateral. The hint is never a nationality or document-type claim; the
13
+ * backend decides the real type.
14
+ */
15
+ type DocumentType = 'INE' | 'PASSPORT_MX' | 'OTHER';
16
+ interface CornerPoint {
17
+ x: number;
18
+ y: number;
19
+ }
20
+ /** User-facing guidance for the current frame. */
21
+ type FrameHint = 'no_document' | 'too_small' | 'too_dark' | 'glare' | 'blurry' | 'hold_still' | 'ready'
22
+ /** OpenCV failed to load or the worker crashed: auto-capture is off, `captureNow()` gives the unwarped frame. */
23
+ | 'detector_unavailable';
24
+ interface XidCameraOcrSessionOptions {
25
+ /** `<video>` element that renders the camera stream. */
26
+ videoElement: HTMLVideoElement;
27
+ /**
28
+ * Shape hints the host is interested in. Detection and capture are NOT
29
+ * filtered by this list (any quadrilateral in [1.25, 1.75] aspect is
30
+ * capturable); wrappers use it to size the fallback guide rectangle.
31
+ */
32
+ documentTypes?: DocumentType[];
33
+ /** When `true`, captures automatically once a stable, good-quality quad is seen. */
34
+ autoCapture?: boolean;
35
+ /** Consecutive stable frames required before auto-capture. Default 10 (≈ 1 s at 10 fps). */
36
+ stableFramesRequired?: number;
37
+ /** JPEG quality of the captured image (0–1). Default 0.92. */
38
+ captureQuality?: number;
39
+ /** Long side of the rectified capture: `standard` = 1024 px, `high` = 1600 px. Default `standard`. */
40
+ captureResolution?: 'standard' | 'high';
41
+ /**
42
+ * URL of the OpenCV.js asset the worker loads lazily. Defaults to the
43
+ * `opencv.js` file shipped next to the SDK bundle.
44
+ */
45
+ opencvUrl?: string;
46
+ /**
47
+ * URL of a self-hosted copy of `dist/cv-worker.js` (spawned as a module worker).
48
+ * Defaults to the worker shipped with the package. Needed, together with
49
+ * `opencvUrl`, for the CJS build and non-Vite bundlers.
50
+ */
51
+ workerUrl?: string;
52
+ /** Implemented by the host: receives the Blob, uploads it, returns the backend JSON. */
53
+ onUpload: (blob: Blob, detectedType: DocumentType | null) => Promise<ExtractResult>;
54
+ /** Optional UI feedback events. */
55
+ onFrameAnalyzed?: (state: FrameState) => void;
56
+ onCaptured?: (blob: Blob, detectedType: DocumentType | null) => void;
57
+ onResult?: (result: ExtractResult) => void;
58
+ onError?: (err: Error) => void;
59
+ }
60
+ interface FrameState {
61
+ detected: boolean;
62
+ documentType: DocumentType | null;
63
+ confidence: number;
64
+ aspectRatio: number | null;
65
+ quality: FrameQuality | null;
66
+ /**
67
+ * Document corners (TL, TR, BR, BL) in analysis-frame pixels. Present only
68
+ * when a quad was detected. Scale by `frameSize` to draw an overlay.
69
+ */
70
+ corners: [CornerPoint, CornerPoint, CornerPoint, CornerPoint] | null;
71
+ /** Size of the analysis frame (NOT the native video size). */
72
+ frameSize: {
73
+ width: number;
74
+ height: number;
75
+ } | null;
76
+ /** Guidance for the user, derived from quality + stability. */
77
+ hint?: FrameHint;
78
+ /** `true` while the camera torch has been enabled by the SDK. Absent when the track has no torch. */
79
+ torch?: boolean;
80
+ }
81
+ interface FrameQuality {
82
+ brightness: number;
83
+ blurScore: number;
84
+ glareRatio: number;
85
+ docFillRatio: number;
86
+ ok: boolean;
87
+ }
88
+ interface ExtractResult {
89
+ [key: string]: unknown;
90
+ }
91
+ interface SessionState {
92
+ status: 'idle' | 'starting' | 'loading_detector' | 'streaming' | 'capturing' | 'uploading' | 'done' | 'stopped' | 'error';
93
+ lastFrame: FrameState | null;
94
+ lastResult: ExtractResult | null;
95
+ lastError: Error | null;
96
+ }
97
+ type SessionStatus = SessionState['status'];
98
+
99
+ /**
100
+ * Pure geometry helpers (no OpenCV, no DOM). Unit-tested in Vitest.
101
+ * Corner order everywhere is TL, TR, BR, BL.
102
+ */
103
+
104
+ interface Point {
105
+ x: number;
106
+ y: number;
107
+ }
108
+ type Quad = [Point, Point, Point, Point];
109
+ declare const ID1_RATIO: number;
110
+ declare const TD3_RATIO: number;
111
+ /**
112
+ * Orders 4 points as TL, TR, BR, BL (y-down). Sorts by angle around the centroid
113
+ * (clockwise on screen), then rotates the cycle so TL is the point with the
114
+ * smallest x + y (ties: smallest y). Robust to a card rotated exactly 45°.
115
+ */
116
+ declare function orderCorners(points: Point[]): Quad;
117
+ /** Aspect ratio of the rectified quad: mean(long sides) / mean(short sides), ≥ 1. */
118
+ declare function rectifiedAspect(quad: Quad): number;
119
+ /** Nearest nominal ratio within ±5 %, else OTHER. Bands: ID-1 1.507–1.665, TD3 1.349–1.491. */
120
+ declare function typeHintFromAspect(aspect: number): DocumentType;
121
+ declare function isCapturableAspect(aspect: number): boolean;
122
+
123
+ /** Messages exchanged between `cv-worker-client.ts` (main thread) and `cv-worker.ts`. */
124
+
125
+ interface ImageDataLike {
126
+ data: Uint8ClampedArray;
127
+ width: number;
128
+ height: number;
129
+ }
130
+ interface CvDetectionResult {
131
+ detected: boolean;
132
+ documentType: DocumentType | null;
133
+ aspectRatio: number | null;
134
+ corners: Quad | null;
135
+ boundingBox: {
136
+ x: number;
137
+ y: number;
138
+ width: number;
139
+ height: number;
140
+ } | null;
141
+ /** Quality measured inside the quad; null when nothing was detected. */
142
+ quality: FrameQuality | null;
143
+ /** Whole-frame mean brightness 0–1 (for the torch decision when no quad). */
144
+ frameBrightness: number;
145
+ score: number | null;
146
+ /**
147
+ * How the winning quad was found: `direct` (a native 4-vertex contour), `reduced`
148
+ * (a 5–6-vertex hull collapsed to a quad) or `lowres` (the half-resolution fallback
149
+ * pass; wins over `reduced`). Non-direct winners are less precise and carry a
150
+ * discounted `score`. Undefined when nothing was detected.
151
+ */
152
+ provenance?: 'direct' | 'reduced' | 'lowres';
153
+ }
154
+
155
+ /**
156
+ * CVWorkerClient — async wrapper over the OpenCV Web Worker.
157
+ * One module worker; request/response by incremental id. No skip-if-busy:
158
+ * the session guarantees a single frame in flight (spec §5.1).
159
+ *
160
+ * Pixel buffers are copied before being transferred, so the caller's frame
161
+ * is never detached and the client never touches a transferred buffer again.
162
+ */
163
+
164
+ interface CVWorkerClientOptions {
165
+ /**
166
+ * Main-thread deadline for `init()`: rejects even if the worker thread hangs
167
+ * and never reports `init-error`. Default 30 s.
168
+ */
169
+ initTimeoutMs?: number;
170
+ }
171
+
172
+ declare class CVWorkerClient {
173
+ private readonly initTimeoutMs;
174
+ private worker;
175
+ private readyPromise;
176
+ private rejectInit;
177
+ private initTimer;
178
+ private ready;
179
+ private pending;
180
+ private nextId;
181
+ constructor(options?: CVWorkerClientOptions);
182
+ /**
183
+ * Spawns the worker (`workerUrl`, default: the packaged `cv-worker.js`) and loads
184
+ * OpenCV from `opencvUrl`. While a load is pending or after it succeeded, returns
185
+ * the same promise (different urls are ignored).
186
+ * After any failure a later call retries with a fresh Worker.
187
+ */
188
+ init(opencvUrl?: string, workerUrl?: string): Promise<void>;
189
+ isReady(): boolean;
190
+ /** `opts.prior`: the previous frame's corners, used by the detector to rank candidates. */
191
+ analyze(img: ImageDataLike, opts?: {
192
+ prior?: Quad;
193
+ }): Promise<CvDetectionResult>;
194
+ warp(img: ImageDataLike, corners: Quad, docType: DocumentType | null, longSide?: number): Promise<ImageData>;
195
+ /**
196
+ * Stops the worker and rejects every pending request. Idempotent. A pending
197
+ * `init()` is left unsettled (callers that stop mid-load are not told it failed).
198
+ */
199
+ terminate(): void;
200
+ /** Failure path: shuts down, then rejects a pending `init()` with the same error. */
201
+ private fail;
202
+ private clearInitTimer;
203
+ private shutdown;
204
+ private request;
205
+ }
206
+
207
+ type WorkerClient = Pick<CVWorkerClient, 'init' | 'isReady' | 'analyze' | 'warp' | 'terminate'>;
208
+ /**
209
+ * @internal Test seam (second constructor argument). Not part of the public,
210
+ * documented API and may change without notice.
211
+ */
212
+ interface XidCameraOcrSessionDeps {
213
+ createWorkerClient(opts: {
214
+ initTimeoutMs: number;
215
+ }): WorkerClient;
216
+ attachCamera(video: HTMLVideoElement): Promise<MediaStream>;
217
+ detachCamera(video: HTMLVideoElement, stream: MediaStream | null): void;
218
+ sampleFrame(video: HTMLVideoElement, targetWidth: number): ImageDataLike | null;
219
+ grabFrame(video: HTMLVideoElement): ImageDataLike | null;
220
+ encodeJpeg(img: ImageData, quality: number): Promise<Blob>;
221
+ snapshotToBlob(video: HTMLVideoElement, quality: number): Promise<Blob>;
222
+ supportsTorch(track: MediaStreamTrack): boolean;
223
+ setTorch(track: MediaStreamTrack, on: boolean): Promise<boolean>;
224
+ now(): number;
225
+ }
226
+ declare class XidCameraOcrSession {
227
+ private readonly opts;
228
+ private readonly deps;
229
+ private stream;
230
+ private track;
231
+ private cv;
232
+ /** Bumped by start()/stop(); any async continuation from an older generation is dropped. */
233
+ private generation;
234
+ private timer;
235
+ private frameCallback;
236
+ /** The in-flight analyze request, so a manual capture never overlaps it. */
237
+ private inFlight;
238
+ /** 0 = not armed yet (armed on the first analysed frame and after each capture). */
239
+ private warmupUntil;
240
+ private capturing;
241
+ /** Set once a capture has been taken; the auto-shutter stays off until the next start(). */
242
+ private autoShutterSpent;
243
+ private torchSupported;
244
+ private torchOn;
245
+ private torchRejected;
246
+ /** True when any frame of the current stable run came from a weak (`reduced`/`lowres`) winner. */
247
+ private weakRun;
248
+ /**
249
+ * Temporal prior for the detector: the previous analysed frame's corners and the size
250
+ * of that frame. Cleared on a frame without detection, a frame-size change, start(),
251
+ * stop() and after a capture.
252
+ */
253
+ private prior;
254
+ private readonly stability;
255
+ state: SessionState;
256
+ constructor(options: XidCameraOcrSessionOptions, deps?: Partial<XidCameraOcrSessionDeps>);
257
+ start(): Promise<void>;
258
+ stop(): void;
259
+ captureNow(): Promise<void>;
260
+ getState(): SessionState;
261
+ /** Waits `delayMs`, then for the next video frame when the browser exposes rVFC. */
262
+ private scheduleNext;
263
+ private tick;
264
+ private analyzeFrame;
265
+ /** Non-fatal detector failure: drop the worker, stop the loop, keep the camera and manual capture. */
266
+ private detectorUnavailable;
267
+ private updateTorch;
268
+ /** Reprojects a sample-frame quad onto the full video frame; null when degenerate. */
269
+ private fullFrameQuad;
270
+ /** `fullQuad` is already in full-frame pixels; null means "unwarped frame". */
271
+ private doCapture;
272
+ private captureBlob;
273
+ /** Clears every timer and frame callback, turns the torch off, closes the camera and drops the worker. */
274
+ private release;
275
+ private setStatus;
276
+ private emitError;
277
+ }
278
+
279
+ /**
280
+ * Document detection with OpenCV (worker side). Mat work only — geometry and
281
+ * quality are pure modules. Every Mat is `.delete()`d in `finally`.
282
+ * Pipeline (spec §5.2): grey → CLAHE → bilateral → auto-Canny → dilate →
283
+ * findContours(RETR_LIST) → convex hull → approxPolyDP (ε = 2 % perimeter) → 4 convex
284
+ * vertices, ≤ 1 corner on the frame border, angles ∈ [70°, 110°] → score
285
+ * 0.5·area + 0.3·rectangularity + 0.2·aspect → veto a winner nested in a border-cut
286
+ * outline → quality on the winner inset by the dilation band.
287
+ *
288
+ * RETR_LIST, not RETR_EXTERNAL: the zero padding draws an edge around the whole
289
+ * frame, and RETR_EXTERNAL would return only that outer contour (area > 95 %,
290
+ * rejected) and hide the document inside it.
291
+ */
292
+
293
+ interface DetectOptions {
294
+ /** Previous frame's corners (TL, TR, BR, BL) in analysed-frame pixels; ranking only. */
295
+ prior?: Quad;
296
+ }
297
+ declare function detectDocumentCV(cv: any, imageData: ImageDataLike, _acceptedTypes?: DocumentType[], opts?: DetectOptions): CvDetectionResult;
298
+
299
+ /**
300
+ * Perspective warp with OpenCV: rectifies the document to its canonical rectangle.
301
+ *
302
+ * - warpDocumentImageData: ImageData in / ImageData out, worker-safe (no DOM).
303
+ * - warpDocument / warpedSnapshotToBlob: canvas based, main thread only.
304
+ *
305
+ * Corners are in the full-resolution camera frame (not the analysis sample); OpenCV
306
+ * computes the 3x3 homography and warpPerspective returns the document head-on.
307
+ */
308
+
309
+ /**
310
+ * Pure warp: ImageData → ImageData, no DOM dependency (runs inside the Web Worker).
311
+ * INE / PASSPORT_MX warp to their nominal ratio; OTHER / null warp to the measured
312
+ * rectified aspect, clamped to the capturable range so a degenerate quad cannot yield
313
+ * a 0 px or absurd output.
314
+ */
315
+ declare function warpDocumentImageData(cv: any, source: ImageDataLike, corners: Quad, docType: DocumentType | null, longSide?: number): ImageData;
316
+ /** Canvas-based warp (main thread only): canvas → warpDocumentImageData → new canvas. */
317
+ declare function warpDocument(cv: any, sourceCanvas: HTMLCanvasElement, corners: Quad, docType: DocumentType | null, longSide?: number): HTMLCanvasElement;
318
+ /** Rectified snapshot as a JPEG Blob; without corners, a plain snapshot of the canvas. */
319
+ declare function warpedSnapshotToBlob(cv: any, sourceCanvas: HTMLCanvasElement, corners: Quad | null, docType: DocumentType | null, quality?: number, longSide?: number): Promise<Blob>;
320
+
321
+ /**
322
+ * Frame quality measured INSIDE the detected quad (spec §5.4). Pure TS over a
323
+ * grayscale buffer so it runs in the worker right after detection (one round
324
+ * trip) and in Vitest without OpenCV.
325
+ */
326
+
327
+ interface GrayFrame {
328
+ data: Uint8Array | Uint8ClampedArray;
329
+ width: number;
330
+ height: number;
331
+ }
332
+ declare const QUALITY_THRESHOLDS: {
333
+ readonly brightnessMin: 0.18;
334
+ readonly brightnessMax: 0.9;
335
+ readonly blurMin: 60;
336
+ readonly glareMax: 0.04;
337
+ readonly fillMin: 0.25;
338
+ readonly glarePixel: 248;
339
+ };
340
+ declare function measureQuality(gray: GrayFrame, quad: Quad): FrameQuality;
341
+
342
+ /**
343
+ * Camera helpers — getUserMedia + video element wiring.
344
+ */
345
+ declare function attachCamera(videoElement: HTMLVideoElement, constraints?: MediaStreamConstraints): Promise<MediaStream>;
346
+ declare function detachCamera(videoElement: HTMLVideoElement, stream: MediaStream | null): void;
347
+ /** Captura un snapshot del video y devuelve un Blob JPEG. */
348
+ declare function snapshotToBlob(videoElement: HTMLVideoElement, quality?: number): Promise<Blob>;
349
+ /** Downscaled RGBA frame for analysis (default 640 px wide). Reuses one canvas. */
350
+ declare function sampleFrame(videoElement: HTMLVideoElement, targetWidth?: number): ImageData | null;
351
+ declare function supportsTorch(track: MediaStreamTrack): boolean;
352
+ /** Best-effort torch toggle. Resolves `true` when the constraint was accepted. */
353
+ declare function setTorch(track: MediaStreamTrack, on: boolean): Promise<boolean>;
354
+
355
+ declare function decideHint(a: {
356
+ detected: boolean;
357
+ quality: FrameQuality | null;
358
+ stableFrames: number;
359
+ stableFramesRequired: number;
360
+ }): FrameHint;
361
+ /** Every user-visible text of the component. `retake`, `capture`, `tip_*` and `tips_dismiss` are UI copy that `copyFor` never returns. */
362
+ type HintCopyKey = FrameHint | 'loading_detector' | 'capturing' | 'uploading' | 'done' | 'error' | 'retake' | 'idle' | 'starting' | 'capture' | 'tip_light' | 'tip_glare' | 'tip_focus' | 'tips_dismiss';
363
+ type HintCopy = Record<HintCopyKey, string>;
364
+ /** Default texts (es-MX). Product copy: do not reword. */
365
+ declare const DEFAULT_TEXTS_ES: Readonly<HintCopy>;
366
+ /** English texts (the 0.4.0 copy plus the new keys). */
367
+ declare const DEFAULT_TEXTS_EN: Readonly<HintCopy>;
368
+ /** Full text set: es-MX defaults with the given overrides applied per key. */
369
+ declare function resolveTexts(overrides?: Partial<HintCopy>): HintCopy;
370
+ declare function copyFor(status: SessionStatus, hint: FrameHint | undefined, overrides?: Partial<HintCopy>): string;
371
+
372
+ /**
373
+ * Stability tracker (pure). A quad is stable when, frame after frame, every
374
+ * corner moves ≤ 1.5 % of the frame diagonal and the type hint is unchanged.
375
+ * Any frame without a detection resets the count (spec §5.3).
376
+ *
377
+ * The type hint has hysteresis: camera jitter can flick the measured aspect
378
+ * across a band edge (INE ↔ OTHER), so a different hint is only a candidate
379
+ * until it persists `hintSwitchFrames` consecutive frames. While pending,
380
+ * geometry keeps counting and the committed hint is reported; on commit the
381
+ * count restarts at 1 (the document really changed).
382
+ */
383
+
384
+ interface StabilityInput {
385
+ quad: Quad;
386
+ typeHint: DocumentType;
387
+ }
388
+ interface StabilitySnapshot {
389
+ stableFrames: number;
390
+ isStable: boolean;
391
+ quad: Quad | null;
392
+ typeHint: DocumentType | null;
393
+ }
394
+ declare class StabilityTracker {
395
+ private readonly required;
396
+ private readonly maxRatio;
397
+ private readonly switchFrames;
398
+ private current;
399
+ private candidate;
400
+ constructor(opts?: {
401
+ stableFramesRequired?: number;
402
+ maxDisplacementRatio?: number;
403
+ hintSwitchFrames?: number;
404
+ });
405
+ get snapshot(): StabilitySnapshot;
406
+ reset(): void;
407
+ update(input: StabilityInput | null, frameSize: {
408
+ width: number;
409
+ height: number;
410
+ }): StabilitySnapshot;
411
+ }
412
+
413
+ /**
414
+ * Theme variables for the `<XidCameraOcr />` component.
415
+ *
416
+ * The component reads every colour, font and radius as `var(--xco-*, <default>)`
417
+ * and writes a variable only when the `theme` prop sets it, so the stylesheet
418
+ * defaults below are the single source of truth for the fallbacks.
419
+ */
420
+
421
+ type XcoThemeKey = 'accent' | 'warning' | 'danger' | 'background' | 'mask' | 'hintBg' | 'hintFg' | 'buttonBg' | 'buttonFg' | 'shutter' | 'overlayBg' | 'overlayFg' | 'fontFamily' | 'radius';
422
+ type XidCameraOcrTheme = Partial<Record<XcoThemeKey, string>>;
423
+ declare const XCO_VARS: Readonly<Record<XcoThemeKey, {
424
+ name: `--xco-${string}`;
425
+ fallback: string;
426
+ }>>;
427
+
428
+ interface UseXidCameraOcrOptions extends Omit<XidCameraOcrSessionOptions, 'videoElement'> {
429
+ /** When `true`, starts the stream automatically on mount. Default `true`. */
430
+ autoStart?: boolean;
431
+ }
432
+ interface UseXidCameraOcrReturn {
433
+ videoRef: React.RefObject<HTMLVideoElement>;
434
+ status: SessionState['status'];
435
+ frame: FrameState | null;
436
+ result: ExtractResult | null;
437
+ error: Error | null;
438
+ start: () => Promise<void>;
439
+ stop: () => void;
440
+ captureNow: () => Promise<void>;
441
+ /** Stops the current run and starts a new one (re-arms the auto-shutter). */
442
+ retake: () => Promise<void>;
443
+ }
444
+ declare function useXidCameraOcr(options: UseXidCameraOcrOptions): UseXidCameraOcrReturn;
445
+
446
+ interface XidCameraOcrProps extends UseXidCameraOcrOptions {
447
+ className?: string;
448
+ style?: React.CSSProperties;
449
+ hideStatusOverlay?: boolean;
450
+ /** Per-key override of the es-MX default texts. */
451
+ texts?: Partial<HintCopy>;
452
+ /** Theme variables written to the root as `--xco-*` custom properties. */
453
+ theme?: XidCameraOcrTheme;
454
+ /** Show the capture tips card. Default `true`. */
455
+ showTips?: boolean;
456
+ }
457
+ declare function XidCameraOcr({ className, style, hideStatusOverlay, texts: textOverrides, theme, showTips, ...sessionOptions }: XidCameraOcrProps): react.JSX.Element;
458
+
459
+ export { CVWorkerClient, type CornerPoint, type CvDetectionResult, DEFAULT_TEXTS_EN, DEFAULT_TEXTS_ES, type DocumentType, type ExtractResult, type FrameHint, type FrameQuality, type FrameState, type HintCopy, type HintCopyKey, ID1_RATIO, type Point, QUALITY_THRESHOLDS, type Quad, type SessionState, type SessionStatus, StabilityTracker, TD3_RATIO, type UseXidCameraOcrOptions, type UseXidCameraOcrReturn, XCO_VARS, type XcoThemeKey, XidCameraOcr, type XidCameraOcrProps, XidCameraOcrSession, type XidCameraOcrSessionOptions, type XidCameraOcrTheme, attachCamera, copyFor, decideHint, defaultOpencvUrl, detachCamera, detectDocumentCV, isCapturableAspect, measureQuality, orderCorners, rectifiedAspect, resolveTexts, sampleFrame, setTorch, snapshotToBlob, supportsTorch, typeHintFromAspect, useXidCameraOcr, warpDocument, warpDocumentImageData, warpedSnapshotToBlob };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import {useRef,useState,useCallback,useEffect,useMemo,useId,useLayoutEffect}from'react';import {jsx,jsxs}from'react/jsx-runtime';async function ue(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 de(e,t){e.srcObject===t&&(e.srcObject=null),t?.getTracks().forEach(r=>r.stop());}async function pe(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 Q=null;function me(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);Q??=document.createElement("canvas"),(Q.width!==o||Q.height!==i)&&(Q.width=o,Q.height=i);let s=Q.getContext("2d",{willReadFrequently:true});return s?(s.drawImage(e,0,0,o,i),s.getImageData(0,0,o,i)):null}function Ae(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 Fe(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 he(e){let t=e.getCapabilities;return typeof t!="function"?false:t.call(e).torch===true}async function ye(e,t){try{return await e.applyConstraints({advanced:[{torch:t}]}),!0}catch{return false}}var bt="@andresxid/xid_camera_ocr_sdk_react";function Pe(e,t){return e.pathname.endsWith(`/${bt}/${t}`)}function De(e){return new URL(e,import.meta.url)}function Ie(){return new URL("@andresxid/xid_camera_ocr_sdk_react/opencv.js",import.meta.url)}function fe(){let e=Ie();return Pe(e,"opencv.js")?De("./opencv.js").href:e.href}function Oe(e){return e!==void 0?new Worker(e,{type:"module"}):Pe(Ie(),"opencv.js")?new Worker(De("./cv-worker.js"),{type:"module"}):new Worker(new URL("@andresxid/xid_camera_ocr_sdk_react/cv-worker.js",import.meta.url),{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 xt=e=>e instanceof Error?e:new Error(String(e)),W=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=fe(),r){if(this.readyPromise)return this.readyPromise;let n;try{n=Oe(r);}catch(i){return Promise.reject(xt(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=He(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=Le(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=Le(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,O=125/88,St=1.503,Ct=.05,te=1.25,be=1.75,wt=.25;function ge(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 H(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 re(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 Rt(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 ne(e,t=70,r=110){let n=re(e);return n.top<=0||n.right<=0||n.bottom<=0||n.left<=0||!Tt(e)||H(e)<=0?false:Rt(e).every(o=>o>=t&&o<=r)}function Tt(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 j(e){let t=re(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 vt(e){if(!Number.isFinite(e))return 0;let t=Math.min(Math.abs(e-D),Math.abs(e-O));return Math.max(0,1-t/wt)}function Ue(e){return .5*e.areaRatio+.3*e.rectangularity+.2*vt(e.aspect)}function oe(e){let t=e>=St?D:O;return Math.abs(e-t)/t<=Ct?t===D?"INE":"PASSPORT_MX":"OTHER"}function xe(e){return e>=te&&e<=be}function Qe(e,t){return e==="INE"?D:e==="PASSPORT_MX"?O:t}var z=1024,Ne=1600;function qe(e,t,r,n,o=z){let i=Mt(Qe(n,j(r))),s=Math.max(1,Math.round(o/i)),a=re(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)),Et(new Uint8ClampedArray((f??S).data),m,u)}finally{for(let v of [f,h,g,y,S,x])v?.delete();}}function Be(e,t,r,n,o=z){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=qe(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 kt(e,t,r,n,o=.92,i=z){let s=r?Be(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 Mt(e){return Number.isFinite(e)?Math.min(be,Math.max(te,e)):te}function Et(e,t,r){return typeof globalThis.ImageData=="function"?new ImageData(e,t,r):{data:e,width:t,height:r,colorSpace:"srgb"}}var _={brightnessMin:.18,brightnessMax:.9,blurMin:60,glareMax:.04,fillMin:.25,glarePixel:248};function V(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 Se(e,t){let{data:r,width:n,height:o}=e,i=V(t,n,o),s=_.glarePixel,a=0,l=0,c=0,d=0,p=0,m=0;for(let f=0;f<o;f++){let v=i[f*2],k=i[f*2+1];if(v>=k)continue;let E=0,M=0;f>0&&f<o-1&&(E=Math.max(v,i[(f-1)*2],i[(f+1)*2])+1,M=Math.min(k,i[(f-1)*2+1],i[(f+1)*2+1])-1);let w=f*n;for(let T=v;T<k;T++){let A=w+T,F=r[A];if(a+=F,F>=s&&l++,c++,T>=E&&T<M){let C=4*F-r[A-n]-r[A+n]-r[A-1]-r[A+1];d+=C,p+=C*C,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?H(t)/y:0,h=u>=_.brightnessMin&&u<=_.brightnessMax&&S>=_.blurMin&&x<=_.glareMax&&g>=_.fillMin;return {brightness:u,blurScore:S,glareRatio:x,docFillRatio:g,ok:h}}function Xe(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 Ce(e){if(!e.detected||!e.quality)return "no_document";let t=e.quality;return !Number.isFinite(t.docFillRatio)||t.docFillRatio<_.fillMin?"too_small":!Number.isFinite(t.brightness)||t.brightness<_.brightnessMin?"too_dark":!Number.isFinite(t.glareRatio)||t.glareRatio>_.glareMax||t.brightness>_.brightnessMax?"glare":!Number.isFinite(t.blurScore)||t.blurScore<_.blurMin?"blurry":e.stableFrames<e.stableFramesRequired?"hold_still":"ready"}var _t=_.brightnessMin;function We(e){return !e.torchSupported||e.torchOn?false:(e.quality?e.quality.brightness:e.frameBrightness)<_t}var we=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"}),At=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"}),Ft=["loading_detector","capturing","uploading","done","error"];function Pt(e){return Ft.includes(e)}function G(e,t){return t?.[e]??we[e]}function Re(e){let t={...we};for(let r of Object.keys(t))t[r]=G(r,e);return t}function ae(e,t,r){return e==="idle"||e==="stopped"?G("idle",r):e==="starting"?G("starting",r):Pt(e)?G(e,r):G(t??"no_document",r)}var Dt=.05;function It(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 Ot(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 je(e,t,r){let n=Ot(It(e,t,r),r);return !ne(n)||H(n)<Dt*r.width*r.height?null:n}var ze={stableFrames:0,isStable:false,quad:null,typeHint:null},Y=class{required;maxRatio;switchFrames;current=ze;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=ze,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 Lt=640,Ut=10,Ve=1500,Qt=35e3,Nt=5,qt={createWorkerClient:e=>new W(e),attachCamera:e=>ue(e),detachCamera:de,sampleFrame:me,grabFrame:Ae,encodeJpeg:Fe,snapshotToBlob:pe,supportsTorch:he,setTorch:ye,now:()=>performance.now()},Ge=e=>e.provenance==="reduced"||e.provenance==="lowres",Ye=e=>e instanceof Error?e:new Error(String(e)),$e=e=>e.map(t=>({x:t.x,y:t.y})),$=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={...qt,...r},this.stability=new Y({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/Ut-(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,Lt);if(!n)return;let o={width:n.width,height:n.height};this.warmupUntil===0&&(this.warmupUntil=this.deps.now()+Ve);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:$e(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&&Ge(a):this.weakRun||Ge(a);let p=this.opts.stableFramesRequired+(this.weakRun?Nt: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?$e(a.corners):null,frameSize:o,hint:Ce({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=Ye(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||!We({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:je(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()+Ve,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"?Ne:z,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=Ye(t);this.state.lastError=r,this.setStatus("error"),this.opts.onError?.(r);}};var Ke=.08,Bt=.95,Xt=.02,N=8,Wt=2,Je=8,Ze=.33,ie=2,jt=2,zt=1,Vt=jt+ie,Gt=2,Yt=2*(ie+1),$t=10,et=1.1,ot=ie+1,Kt=6,at=.92,Jt=1/at,Zt=.85,er=2,tr=.05,tt=2,rt=64;function it(e){return {detected:false,documentType:null,aspectRatio:null,corners:null,boundingBox:null,quality:null,frameBrightness:e,score:null}}function rr(e,t,r,n={}){let o={brightness:0};try{return nr(e,t,o,n.prior??null)}catch(i){return console.warn("[xid-camera-ocr] detectDocumentCV failed:",i),it(o.brightness)}}function nr(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(Wt,new e.Size(Je,Je)))};e.cvtColor(l,c,e.COLOR_RGBA2GRAY),r.brightness=Xe(Te(c,o,i));let m=[],u=nt(e,c,p,o,i,m,n),x=!1,S=Math.round(o/tt),y=Math.round(i/tt);if(!u&&S>=rt&&y>=rt&&(e.resize(c,d,new e.Size(S,y),0,0,e.INTER_AREA),u=nt(e,d,p,o,i,m,n),x=u!==null),u&&cr(u,m,Te(c,o,i))&&(u=null),!u)return it(r.brightness);let g=x?"lowres":u.reduced?"reduced":"direct",h=u.quad.map(w=>w.x),f=u.quad.map(w=>w.y),v=Math.min(...h),k=Math.max(...h),E=Math.min(...f),M=Math.max(...f);return {detected:!0,documentType:oe(u.aspect),aspectRatio:u.aspect,corners:u.quad,boundingBox:{x:v/o,y:E/i,width:(k-v)/o,height:(M-E)/i},quality:Se(Te(c,o,i),ct(u.quad,ot*u.scale)),frameBrightness:r.brightness,score:g==="direct"?u.score:u.score*Zt,provenance:g}}finally{for(let l of s)l.delete();}}function nt(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,N,N,N,N,e.BORDER_CONSTANT,new e.Scalar(0));let y=mr(r.padded.data);e.Canny(r.padded,r.edges,Math.max(10,(1-Ze)*y),Math.min(255,(1+Ze)*y)),e.dilate(r.edges,r.dilated,r.kernel,new e.Point(-1,-1),ie),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 v=e.boundingRect(f);if(v.width*v.height<p*Ke)continue;e.convexHull(f,u,!1,!0);let k=e.contourArea(u);if(k<p*Ke||k>p*Bt||(e.approxPolyDP(u,x,Xt*e.arcLength(u,!0),!0),x.rows<4||x.rows>Kt||!e.isContourConvex(x)))continue;let E=x.rows!==4,M;if(!E)M=ar(x,a,l);else {let X=ir(st(x));if(!X)continue;M=X.map(U=>lt(U,a,l));let L=k/H(M);if(!(L>=at&&L<=Jt))continue}let w=k*c*d,T=M.map(m),A=Vt*c;if(pr(T,n,o,A)>zt){lr(T,n,o,A)||i.push({pts:T,area:w});continue}let F=ge(T);if(!ne(F))continue;let C=e.minAreaRect(E?u:x),I=C.size.width*C.size.height,Z=I>0?Math.min(1,k/I):0,q=j(F);if(!xe(q))continue;let B=Ue({areaRatio:k/p,rectangularity:Z,aspect:q}),ee=s?B-or(F,s,n,o):B;(!g||ee>g.rank)&&(g={quad:F,score:B,rank:ee,aspect:q,area:w,scale:c,reduced:E});}finally{f.delete();}}return g}function or(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 er*Math.min(o/Math.hypot(r,n),tr)}function Te(e,t,r){return {data:e.data,width:t,height:r}}function st(e){let t=e.data32S,r=[];for(let n=0;n<e.rows;n++)r.push({x:t[n*2]-N,y:t[n*2+1]-N});return r}function lt(e,t,r){return {x:Math.min(t,Math.max(0,e.x)),y:Math.min(r,Math.max(0,e.y))}}function ar(e,t,r){return st(e).map(n=>lt(n,t,r))}function ir(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=sr(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 sr(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 lr(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 cr(e,t,r){let n=Yt*e.scale;if(!t.some(a=>a.area>=Gt*e.area&&e.quad.every(l=>dr(a.pts,l,n))))return false;if(oe(e.aspect)==="OTHER")return true;let{inner:i,ring:s}=ur(r,ct(e.quad,ot*e.scale),e.quad);return i<s-$t}function ur(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)*et,y:a+(y.y-a)*et})),c=V(l,o,i),d=V(r,o,i),p=V(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],v=d[y*2+1],k=p[y*2],E=p[y*2+1],M=y*o;for(let w=g;w<h;w++){let T=n[M+w];w>=k&&w<E?(m+=T,u++):(w<f||w>=v)&&(x+=T,S++);}}return {inner:u>0?m/u:0,ring:S>0?x/S:0}}function dr(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 ct(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 pr(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 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 ke(e){let t=useRef(null),r=useRef(null),[n,o]=useState("idle"),[i,s]=useState(null),[a,l]=useState(null),[c,d]=useState(null),p=useRef(e);p.current=e;let m=useCallback(()=>{if(r.current)return r.current;if(!t.current)throw new Error("videoRef not attached yet");let g=new $({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=useCallback(async()=>{let g=m();await g.start(),r.current===g&&o(g.getState().status);},[m]),x=useCallback(()=>{r.current?.stop(),o("stopped");},[]),S=useCallback(async()=>{await r.current?.captureNow();},[]),y=useCallback(async()=>{x(),l(null),d(null),s(null),await u();},[x,u]);return 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 fr({status:e,showTips:t,dismissed:r,completedOnce:n}){return t&&!r&&(e==="error"||!n&&(e==="starting"||e==="loading_detector"))}function ut(e,t){let[r,n]=useState(false),[o,i]=useState(e==="done"),[s,a]=useState(e),l=r,c=o;s!==e&&(a(e),e==="error"&&(l=false,n(false)),e==="done"&&(c=true,i(true)));let d=useCallback(()=>n(true),[]);return {visible:fr({status:e,showTips:t,dismissed:l,completedOnce:c}),dismiss:d}}var le={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}=le[e];return `var(${t}, ${r})`}function dt(e){let t={};if(!e)return t;for(let r of Object.keys(e)){if(!Object.prototype.hasOwnProperty.call(le,r))continue;let n=e[r];typeof n!="string"||n===""||(t[le[r].name]=n);}return t}function pt(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 Ee={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"}},br=()=>jsxs("svg",{...Ee,children:[jsx("circle",{cx:"12",cy:"12",r:"4"}),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"})]}),gr=()=>jsxs("svg",{...Ee,children:[jsx("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),jsx("path",{d:"M14 5l-6 14M18 5l-6 14"})]}),xr=()=>jsxs("svg",{...Ee,children:[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"}),jsx("circle",{cx:"12",cy:"12",r:"2"})]});function mt({texts:e,onDismiss:t}){let r=[{Icon:br,text:e.tip_light},{Icon:gr,text:e.tip_glare},{Icon:xr,text:e.tip_focus}];return jsxs("div",{className:"xco-tips",style:Sr,children:[jsx("ul",{style:Cr,children:r.map(({Icon:n,text:o})=>jsxs("li",{style:wr,children:[jsx(n,{}),jsx("span",{children:o})]},o))}),jsx("button",{type:"button",className:"xco-tips-dismiss",onClick:t,style:Rr,children:e.tips_dismiss})]})}var Sr={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},Cr={listStyle:"none",margin:0,padding:0,display:"flex",flexDirection:"column",gap:10},wr={display:"flex",alignItems:"center",gap:12},Rr={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 _r=typeof window>"u"?useEffect:useLayoutEffect;function ht({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-"+useId().replace(/[^A-Za-z0-9_-]/g,""),f=useRef(null),[v,k]=useState({width:0,height:0}),E=r?.documentType,M=E==="PASSPORT_MX"?O:E==="INE"?D:o[0]==="PASSPORT_MX"?O:D;_r(()=>{let C=f.current;if(!C)return;let I=()=>{let q=C.clientWidth,B=C.clientHeight,ee=q*.85,X=B*.7,L=ee,U=L/M;U>X&&(U=X,L=U*M),k({width:L,height:U});};I();let Z=new ResizeObserver(I);return Z.observe(C),()=>Z.disconnect()},[M]);let w=!!(r?.corners&&r?.frameSize),T=pt(t,r),A=ae(t,r?.hint,n),F=s?`xid-camera-ocr ${s}`:"xid-camera-ocr";return jsxs("div",{ref:f,className:F,"data-status":t,"data-hint":r?.hint??"",style:{...Ar,...dt(i),...a},children:[jsx("style",{children:"@keyframes xco-spin { to { transform: rotate(360deg); } }"}),jsx("video",{ref:e,playsInline:true,muted:true,autoPlay:true,style:Fr}),!l&&!w&&jsx("div",{style:Dr,children:jsx("div",{className:"xco-guide",style:{...Ir,width:v.width,height:v.height,borderColor:T}})}),!l&&w&&r&&r.corners&&r.frameSize&&jsxs("svg",{style:Pr,viewBox:`0 0 ${r.frameSize.width} ${r.frameSize.height}`,preserveAspectRatio:"xMidYMid slice",children:[jsx("defs",{children:jsxs("mask",{id:h,children:[jsx("rect",{x:"0",y:"0",width:r.frameSize.width,height:r.frameSize.height,fill:"white"}),jsx("polygon",{points:r.corners.map(C=>`${C.x},${C.y}`).join(" "),fill:"black"})]})}),jsx("rect",{x:"0",y:"0",width:r.frameSize.width,height:r.frameSize.height,style:{fill:b("mask")},mask:`url(#${h})`}),jsx("polygon",{points:r.corners.map(C=>`${C.x},${C.y}`).join(" "),style:{fill:"none",stroke:T},strokeWidth:Math.max(2,r.frameSize.width*.006),strokeLinejoin:"round"}),r.corners.map((C,I)=>jsx("circle",{cx:C.x,cy:C.y,r:Math.max(4,r.frameSize.width*.012),style:{fill:T}},I))]}),!l&&(y?jsx("button",{type:"button",className:"xco-hint",onClick:m,style:qr,children:A}):jsx("p",{className:"xco-hint",style:ft,role:"status","aria-live":"polite",children:A})),!l&&x&&jsx("button",{type:"button",className:"xco-shutter",onClick:d,"aria-label":n.capture,style:Ur,children:jsx("span",{style:Qr})}),!l&&S&&jsx("button",{type:"button",className:"xco-retake",onClick:p,"aria-label":n.retake,style:Nr,children:n.retake}),!l&&g&&jsxs("div",{className:"xco-loader",style:Or,"aria-busy":"true","aria-live":"polite",children:[jsx("div",{style:Hr}),jsx("p",{style:Lr,children:ae(t,void 0,n)})]}),c&&!l&&jsx(mt,{texts:n,onDismiss:u})]})}var yt="calc(104px + env(safe-area-inset-bottom, 0px))",Ar={position:"relative",width:"100%",height:"100%",overflow:"hidden",background:b("background"),fontFamily:b("fontFamily"),touchAction:"none"},Fr={position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",display:"block"},Pr={position:"absolute",inset:0,width:"100%",height:"100%",pointerEvents:"none"},Dr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",pointerEvents:"none"},Ir={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"},Or={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},Hr={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"},Lr={color:b("overlayFg"),fontFamily:b("fontFamily"),fontSize:15,fontWeight:500,margin:0,textAlign:"center",padding:"0 24px"},Ur={position:"absolute",bottom:yt,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"},Nr={position:"absolute",bottom:yt,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"},ft={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"},qr={...ft,border:"none",minHeight:44,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"};var Xr=["INE","PASSPORT_MX"],_e=()=>{};function Wr({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}=ke(s),u=ut(l,i??true),x=useMemo(()=>Re(n),[n]),S=l==="streaming"||l==="loading_detector",y=l==="done"||l==="error",g=()=>{S&&p().catch(_e);},h=()=>{y&&m().catch(_e);},f=()=>{d().catch(_e);};return jsx(ht,{videoRef:a,status:l,frame:c,texts:x,documentTypes:s.documentTypes??Xr,theme:o,className:e,style:t,hideStatusOverlay:r,tipsVisible:u.visible,onCapture:g,onRetake:h,onStart:f,onDismissTips:u.dismiss})}export{W as CVWorkerClient,At as DEFAULT_TEXTS_EN,we as DEFAULT_TEXTS_ES,D as ID1_RATIO,_ as QUALITY_THRESHOLDS,Y as StabilityTracker,O as TD3_RATIO,le as XCO_VARS,Wr as XidCameraOcr,$ as XidCameraOcrSession,ue as attachCamera,ae as copyFor,Ce as decideHint,fe as defaultOpencvUrl,de as detachCamera,rr as detectDocumentCV,xe as isCapturableAspect,Se as measureQuality,ge as orderCorners,j as rectifiedAspect,Re as resolveTexts,me as sampleFrame,ye as setTorch,pe as snapshotToBlob,he as supportsTorch,oe as typeHintFromAspect,ke as useXidCameraOcr,Be as warpDocument,qe as warpDocumentImageData,kt as warpedSnapshotToBlob};//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map