@exige/web-scanner-sdk 0.2.10 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- .scanner-camera-overlay{color:#fff;isolation:isolate;overscroll-behavior:none;touch-action:none;--scanner-overlay-primary:#c8ff45;--scanner-overlay-seeking:#ef6a5b;--scanner-overlay-detecting:#ef6a5b;--scanner-overlay-unstable:#ffbe40;--scanner-overlay-ready:#8af25a;--scanner-overlay-captured:#fff;background:#050806;width:100%;height:100%;font-family:Manrope,ui-sans-serif,system-ui,sans-serif;position:relative;overflow:hidden}.scanner-camera-overlay.is-captured:after{content:"";z-index:10;pointer-events:none;background:#fff;animation:.14s ease-out forwards scanner-camera-flash;position:absolute;inset:0}@keyframes scanner-camera-flash{0%{opacity:.92}to{opacity:0}}.scanner-camera-overlay__video,.scanner-camera-overlay__quad{width:100%;height:100%;position:absolute;inset:0}.scanner-camera-overlay__video{object-fit:cover;background:#050806;display:block}.model-download-ring{z-index:6;color:#fff;pointer-events:none;background:#080d0ac7;border-radius:50%;place-items:center;width:96px;height:96px;display:grid;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 10px 30px #00000047}.model-download-ring svg{width:100%;height:100%;position:absolute;inset:0;transform:rotate(-90deg)}.model-download-ring circle{fill:none;stroke-width:6px}.model-download-ring .track{stroke:#ffffff47}.model-download-ring .value{stroke:var(--scanner-overlay-primary,#c8ff45);stroke-linecap:round}.model-download-ring.is-indeterminate svg{animation:.9s linear infinite model-download-spin}.model-download-ring.is-indeterminate .value{stroke-dasharray:48 128}.model-download-ring strong{z-index:1;font:600 13px/1 ui-monospace,SFMono-Regular,Menlo,monospace;position:relative}@keyframes model-download-spin{to{transform:rotate(270deg)}}.scanner-camera-overlay__quad.seeking polygon{fill:color-mix(in srgb, var(--scanner-overlay-seeking,#ef6a5b) 8%, transparent);stroke:var(--scanner-overlay-seeking,#ef6a5b)}.scanner-camera-overlay__quad.detecting polygon{fill:color-mix(in srgb, var(--scanner-overlay-detecting,#ef6a5b) 8%, transparent);stroke:var(--scanner-overlay-detecting,#ef6a5b)}.scanner-camera-overlay__quad{z-index:1;pointer-events:none}.scanner-camera-overlay__quad polygon{fill:color-mix(in srgb, var(--scanner-overlay-detecting,#ef6a5b) 8%, transparent);stroke:var(--scanner-overlay-detecting,#ef6a5b);stroke-width:6px;vector-effect:non-scaling-stroke;transition:stroke .15s,fill .15s}.scanner-camera-overlay__quad.unstable polygon{fill:color-mix(in srgb, var(--scanner-overlay-unstable,#ffbe40) 10%, transparent);stroke:var(--scanner-overlay-unstable,#ffbe40)}.scanner-camera-overlay__quad.ready polygon{fill:color-mix(in srgb, var(--scanner-overlay-ready,#8af25a) 10%, transparent);stroke:var(--scanner-overlay-ready,#8af25a)}.scanner-camera-overlay__quad.captured polygon{fill:color-mix(in srgb, var(--scanner-overlay-captured,#fff) 18%, transparent);stroke:var(--scanner-overlay-captured,#fff)}.scanner-camera-overlay__topbar{z-index:3;padding:max(18px, env(safe-area-inset-top)) max(18px, env(safe-area-inset-right)) 48px max(18px, env(safe-area-inset-left));background:linear-gradient(#030704db,#0000);justify-content:space-between;align-items:flex-start;gap:20px;display:flex;position:absolute;top:0;left:0;right:0}.scanner-camera-overlay__topbar div{gap:5px;display:grid}.scanner-camera-overlay__topbar strong{font-size:clamp(18px,4vw,26px)}.scanner-camera-overlay__topbar span{color:#ffffffb8;font-size:12px}.scanner-camera-overlay__topbar button{color:#fff;background:#050a0799;border:1px solid #ffffff61;border-radius:50%;flex:none;width:46px;height:46px;font-size:28px;line-height:1}.scanner-camera-overlay__message{z-index:4;text-align:center;background:#0a100ceb;border:1px solid #fff3;border-radius:14px;justify-items:center;gap:12px;width:min(420px,100% - 40px);padding:26px;display:grid;position:absolute;top:50%;left:50%;translate:-50% -50%}.scanner-camera-overlay__message p{color:#ffffffb3;margin:0;font-size:13px;line-height:1.5}.scanner-camera-overlay__message div{gap:10px;display:flex}.scanner-camera-overlay__message button{color:#fff;background:0 0;border:1px solid #ffffff6b;border-radius:7px;min-height:44px;padding:0 16px}.scanner-camera-overlay__spinner{border:3px solid #fff3;border-top-color:var(--scanner-overlay-primary,#c8ff45);border-radius:50%;width:28px;height:28px;animation:.8s linear infinite scanner-camera-spin}@keyframes scanner-camera-spin{to{rotate:1turn}}.scanner-camera-overlay__readout{z-index:3;top:max(94px, calc(env(safe-area-inset-top) + 72px));left:max(18px, env(safe-area-inset-left));gap:8px;max-width:calc(100% - 36px);display:grid;position:absolute}.scanner-camera-overlay__status{text-transform:uppercase;background:#050a07c2;border-radius:6px;flex-direction:column;align-items:flex-start;gap:4px;max-width:100%;padding:8px 10px;font:9px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;display:flex}.scanner-camera-overlay__status-line{flex-wrap:wrap;align-items:center;gap:7px;max-width:100%;display:flex}.scanner-camera-overlay__status-line>span{background:var(--scanner-overlay-detecting,#ef6a5b);border-radius:50%;flex:none;width:7px;height:7px}.scanner-camera-overlay__status-line>span.seeking{background:var(--scanner-overlay-seeking,#ef6a5b)}.scanner-camera-overlay__status-line>span.detecting{background:var(--scanner-overlay-detecting,#ef6a5b)}.scanner-camera-overlay__status-line>span.unstable{background:var(--scanner-overlay-unstable,#ffbe40)}.scanner-camera-overlay__status-line>span.ready{background:var(--scanner-overlay-ready,#8af25a)}.scanner-camera-overlay__status-line>span.captured{background:var(--scanner-overlay-captured,#fff)}.scanner-camera-overlay__decoder{color:#d9f7c4;text-transform:none;font-size:12px;line-height:1.2}.scanner-camera-overlay__diagnostics{background:#050a07b8;border-radius:6px;gap:2px;max-width:100%;margin:0;padding:8px 10px;font:9px/1.35 ui-monospace,SFMono-Regular,Menlo,monospace;display:grid}.scanner-camera-overlay__diagnostics>div{gap:6px;display:flex}.scanner-camera-overlay__diagnostics dt{color:#ffffff8c;text-transform:uppercase;min-width:44px}.scanner-camera-overlay__diagnostics dd{color:#d9f7c4;margin:0}.scanner-camera-overlay__copy{color:#fff;font:inherit;text-underline-offset:2px;background:0 0;border:0;margin:0;padding:0;text-decoration:underline}.scanner-camera-overlay__copy:focus-visible{outline:2px solid var(--scanner-overlay-ready,#8af25a);outline-offset:2px}.scanner-camera-overlay__controls{z-index:3;padding:60px max(18px, env(safe-area-inset-right)) max(22px, env(safe-area-inset-bottom)) max(18px, env(safe-area-inset-left));background:linear-gradient(#0000,#030704eb);grid-template-columns:minmax(90px,1fr) minmax(140px,auto) minmax(90px,1fr);align-items:end;gap:18px;display:grid;position:absolute;bottom:0;left:0;right:0}.scanner-camera-overlay__cancel{color:#fff;background:#050a0766;border:1px solid #ffffff6b;border-radius:8px;min-height:46px}.scanner-camera-overlay__capture{justify-items:center;gap:10px;display:grid}.scanner-camera-overlay__toggles{flex-wrap:wrap;justify-content:center;align-items:center;gap:8px 14px;display:flex}.scanner-camera-overlay__toggles label{white-space:nowrap;align-items:center;gap:7px;min-height:34px;font-size:11px;display:flex}.scanner-camera-overlay__toggles input{width:22px;height:22px;accent-color:var(--scanner-overlay-primary,#c8ff45)}.scanner-camera-overlay__toggles input:disabled{opacity:.85}.scanner-camera-overlay__shutter{background:0 0;border:3px solid #fff;border-radius:50%;place-items:center;width:74px;height:74px;padding:6px;display:grid}.scanner-camera-overlay__shutter span{background:#fff;border-radius:50%;width:100%;height:100%;display:block}.scanner-camera-overlay__shutter:disabled{opacity:.42}.scanner-camera-overlay__quality{justify-items:end;gap:4px;padding-bottom:8px;font-size:10px;display:grid}.scanner-camera-overlay__quality span{color:#ffffff94;text-transform:uppercase}.scanner-camera-overlay__quality strong{font:10px ui-monospace,SFMono-Regular,Menlo,monospace}@media (width<=560px){.scanner-camera-overlay__controls{grid-template-columns:72px 1fr 72px;gap:10px}.scanner-camera-overlay__quality strong{text-align:right;max-width:72px}}@media (orientation:landscape) and (height<=560px){.scanner-camera-overlay__controls{padding-top:20px}.scanner-camera-overlay__shutter{width:60px;height:60px}}
1
+ .scanner-camera-overlay{color:#fff;isolation:isolate;overscroll-behavior:none;touch-action:none;--scanner-overlay-primary:#c8ff45;--scanner-overlay-seeking:#ef6a5b;--scanner-overlay-detecting:#ef6a5b;--scanner-overlay-unstable:#ffbe40;--scanner-overlay-ready:#8af25a;--scanner-overlay-captured:#fff;background:#050806;width:100%;height:100%;font-family:Manrope,ui-sans-serif,system-ui,sans-serif;position:relative;overflow:hidden}.scanner-camera-overlay.is-captured:after{content:"";z-index:10;pointer-events:none;background:#fff;animation:.14s ease-out forwards scanner-camera-flash;position:absolute;inset:0}@keyframes scanner-camera-flash{0%{opacity:.92}to{opacity:0}}.scanner-camera-overlay__video,.scanner-camera-overlay__quad{width:100%;height:100%;position:absolute;inset:0}.scanner-camera-overlay__video{object-fit:cover;background:#050806;display:block}.scanner-camera-overlay__still{z-index:0;pointer-events:none}.model-download-ring{z-index:6;color:#fff;pointer-events:none;background:#080d0ac7;border-radius:50%;place-items:center;width:96px;height:96px;display:grid;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 10px 30px #00000047}.model-download-ring svg{width:100%;height:100%;position:absolute;inset:0;transform:rotate(-90deg)}.model-download-ring circle{fill:none;stroke-width:6px}.model-download-ring .track{stroke:#ffffff47}.model-download-ring .value{stroke:var(--scanner-overlay-primary,#c8ff45);stroke-linecap:round}.model-download-ring.is-indeterminate svg{animation:.9s linear infinite model-download-spin}.model-download-ring.is-indeterminate .value{stroke-dasharray:48 128}.model-download-ring strong{z-index:1;font:600 13px/1 ui-monospace,SFMono-Regular,Menlo,monospace;position:relative}@keyframes model-download-spin{to{transform:rotate(270deg)}}.scanner-camera-overlay__quad.seeking polygon{fill:color-mix(in srgb, var(--scanner-overlay-seeking,#ef6a5b) 8%, transparent);stroke:var(--scanner-overlay-seeking,#ef6a5b)}.scanner-camera-overlay__quad.detecting polygon{fill:color-mix(in srgb, var(--scanner-overlay-detecting,#ef6a5b) 8%, transparent);stroke:var(--scanner-overlay-detecting,#ef6a5b)}.scanner-camera-overlay__quad{z-index:1;pointer-events:none}.scanner-camera-overlay__quad polygon{fill:color-mix(in srgb, var(--scanner-overlay-detecting,#ef6a5b) 8%, transparent);stroke:var(--scanner-overlay-detecting,#ef6a5b);stroke-width:6px;vector-effect:non-scaling-stroke;transition:stroke .15s,fill .15s}.scanner-camera-overlay__quad.unstable polygon{fill:color-mix(in srgb, var(--scanner-overlay-unstable,#ffbe40) 10%, transparent);stroke:var(--scanner-overlay-unstable,#ffbe40)}.scanner-camera-overlay__quad.ready polygon{fill:color-mix(in srgb, var(--scanner-overlay-ready,#8af25a) 10%, transparent);stroke:var(--scanner-overlay-ready,#8af25a)}.scanner-camera-overlay__quad.captured polygon{fill:color-mix(in srgb, var(--scanner-overlay-captured,#fff) 18%, transparent);stroke:var(--scanner-overlay-captured,#fff)}.scanner-camera-overlay__topbar{z-index:3;padding:max(18px, env(safe-area-inset-top)) max(18px, env(safe-area-inset-right)) 48px max(18px, env(safe-area-inset-left));background:linear-gradient(#030704db,#0000);justify-content:space-between;align-items:flex-start;gap:20px;display:flex;position:absolute;top:0;left:0;right:0}.scanner-camera-overlay__topbar div{gap:5px;display:grid}.scanner-camera-overlay__topbar strong{font-size:clamp(18px,4vw,26px)}.scanner-camera-overlay__topbar span{color:#ffffffb8;font-size:12px}.scanner-camera-overlay__topbar button{color:#fff;background:#050a0799;border:1px solid #ffffff61;border-radius:50%;flex:none;width:46px;height:46px;font-size:28px;line-height:1}.scanner-camera-overlay__message{z-index:4;text-align:center;background:#0a100ceb;border:1px solid #fff3;border-radius:14px;justify-items:center;gap:12px;width:min(420px,100% - 40px);padding:26px;display:grid;position:absolute;top:50%;left:50%;translate:-50% -50%}.scanner-camera-overlay__message p{color:#ffffffb3;margin:0;font-size:13px;line-height:1.5}.scanner-camera-overlay__message div{gap:10px;display:flex}.scanner-camera-overlay__message button{color:#fff;background:0 0;border:1px solid #ffffff6b;border-radius:7px;min-height:44px;padding:0 16px}.scanner-camera-overlay__spinner{border:3px solid #fff3;border-top-color:var(--scanner-overlay-primary,#c8ff45);border-radius:50%;width:28px;height:28px;animation:.8s linear infinite scanner-camera-spin}@keyframes scanner-camera-spin{to{rotate:1turn}}.scanner-camera-overlay__readout{z-index:3;top:max(94px, calc(env(safe-area-inset-top) + 72px));left:max(18px, env(safe-area-inset-left));gap:8px;max-width:calc(100% - 36px);display:grid;position:absolute}.scanner-camera-overlay__status{text-transform:uppercase;background:#050a07c2;border-radius:6px;flex-direction:column;align-items:flex-start;gap:4px;max-width:100%;padding:8px 10px;font:9px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;display:flex}.scanner-camera-overlay__status-line{flex-wrap:wrap;align-items:center;gap:7px;max-width:100%;display:flex}.scanner-camera-overlay__status-line>span{background:var(--scanner-overlay-detecting,#ef6a5b);border-radius:50%;flex:none;width:7px;height:7px}.scanner-camera-overlay__status-line>span.seeking{background:var(--scanner-overlay-seeking,#ef6a5b)}.scanner-camera-overlay__status-line>span.detecting{background:var(--scanner-overlay-detecting,#ef6a5b)}.scanner-camera-overlay__status-line>span.unstable{background:var(--scanner-overlay-unstable,#ffbe40)}.scanner-camera-overlay__status-line>span.ready{background:var(--scanner-overlay-ready,#8af25a)}.scanner-camera-overlay__status-line>span.captured{background:var(--scanner-overlay-captured,#fff)}.scanner-camera-overlay__decoder{color:#d9f7c4;text-transform:none;font-size:12px;line-height:1.2}.scanner-camera-overlay__diagnostics{background:#050a07b8;border-radius:6px;gap:2px;max-width:100%;margin:0;padding:8px 10px;font:9px/1.35 ui-monospace,SFMono-Regular,Menlo,monospace;display:grid}.scanner-camera-overlay__diagnostics>div{gap:6px;display:flex}.scanner-camera-overlay__diagnostics dt{color:#ffffff8c;text-transform:uppercase;min-width:44px}.scanner-camera-overlay__diagnostics dd{color:#d9f7c4;margin:0}.scanner-camera-overlay__copy{color:#fff;font:inherit;text-underline-offset:2px;background:0 0;border:0;margin:0;padding:0;text-decoration:underline}.scanner-camera-overlay__copy:focus-visible{outline:2px solid var(--scanner-overlay-ready,#8af25a);outline-offset:2px}.scanner-camera-overlay__controls{z-index:3;padding:60px max(18px, env(safe-area-inset-right)) max(22px, env(safe-area-inset-bottom)) max(18px, env(safe-area-inset-left));background:linear-gradient(#0000,#030704eb);grid-template-columns:minmax(90px,1fr) minmax(140px,auto) minmax(90px,1fr);align-items:end;gap:18px;display:grid;position:absolute;bottom:0;left:0;right:0}.scanner-camera-overlay__cancel{color:#fff;background:#050a0766;border:1px solid #ffffff6b;border-radius:8px;min-height:46px}.scanner-camera-overlay__capture{justify-items:center;gap:10px;display:grid}.scanner-camera-overlay__toggles{flex-wrap:wrap;justify-content:center;align-items:center;gap:8px 14px;display:flex}.scanner-camera-overlay__toggles label{white-space:nowrap;align-items:center;gap:7px;min-height:34px;font-size:11px;display:flex}.scanner-camera-overlay__toggles input{width:22px;height:22px;accent-color:var(--scanner-overlay-primary,#c8ff45)}.scanner-camera-overlay__toggles input:disabled{opacity:.85}.scanner-camera-overlay__shutter{background:0 0;border:3px solid #fff;border-radius:50%;place-items:center;width:74px;height:74px;padding:6px;display:grid}.scanner-camera-overlay__shutter span{background:#fff;border-radius:50%;width:100%;height:100%;display:block}.scanner-camera-overlay__shutter:disabled{opacity:.42}.scanner-camera-overlay__quality{justify-items:end;gap:4px;padding-bottom:8px;font-size:10px;display:grid}.scanner-camera-overlay__quality span{color:#ffffff94;text-transform:uppercase}.scanner-camera-overlay__quality strong{font:10px ui-monospace,SFMono-Regular,Menlo,monospace}@media (width<=560px){.scanner-camera-overlay__controls{grid-template-columns:72px 1fr 72px;gap:10px}.scanner-camera-overlay__quality strong{text-align:right;max-width:72px}}@media (orientation:landscape) and (height<=560px){.scanner-camera-overlay__controls{padding-top:20px}.scanner-camera-overlay__shutter{width:60px;height:60px}}
2
2
  /*$vite$:1*/
@@ -4,7 +4,7 @@ import type { CameraDiagnostics, CameraPhoto, TorchMode } from '../sdk/camera';
4
4
  import type { AutoCaptureMode, FinderCapture, FinderStatus } from '../sdk/finder';
5
5
  import type { OrtWasmPaths } from '../sdk/ort-runtime';
6
6
  import type { DocumentQuad } from '../sdk/types';
7
- export type ScannerPhase = 'starting' | 'ready' | 'capturing' | 'error';
7
+ export type ScannerPhase = 'starting' | 'ready' | 'capturing' | 'captured' | 'error';
8
8
  export interface ScannerCapture extends FinderCapture {
9
9
  method: CameraPhoto['method'];
10
10
  settings: MediaTrackSettings;
@@ -65,6 +65,12 @@ export interface ScannerState {
65
65
  copyState: 'idle' | 'copied' | 'failed';
66
66
  guidanceHint?: string;
67
67
  detectorStatus: string;
68
+ /**
69
+ * Data or object URL of the captured still drawn over the live video.
70
+ * Present after a successful capture until the host dismisses the session
71
+ * or starts a new capture.
72
+ */
73
+ frozenPreviewUrl?: string;
68
74
  }
69
75
  export interface ScannerApi {
70
76
  capture: () => Promise<void>;
@@ -81,6 +87,11 @@ export interface ScannerProviderProps {
81
87
  autoCapture?: AutoCaptureMode;
82
88
  /** Camera torch policy. Defaults to `defaultOff`. */
83
89
  torch?: TorchMode;
90
+ /**
91
+ * Receives the high-resolution frame after a successful capture.
92
+ * The preview freezes on that still. The provider does not unmount or
93
+ * stop the session. The host dismisses with `onCancel` or `open={false}`.
94
+ */
84
95
  onCapture: (capture: ScannerCapture) => void | Promise<void>;
85
96
  /**
86
97
  * Called when Cancel or Close is tapped. The camera stays mounted.
package/dist/react.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { m as e, o as t, p as n, s as r, v as i } from "./finder-BeINpYm3.js";
3
3
  import { createContext as a, useCallback as o, useContext as s, useEffect as c, useMemo as l, useRef as u, useState as d } from "react";
4
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
4
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
5
5
  //#region src/sdk/display-quad.ts
6
- function m(e) {
6
+ function h(e) {
7
7
  return [
8
8
  e.topLeft,
9
9
  e.topRight,
@@ -11,7 +11,7 @@ function m(e) {
11
11
  e.bottomLeft
12
12
  ];
13
13
  }
14
- function h(e) {
14
+ function g(e) {
15
15
  let [t, n, r, i] = e;
16
16
  return {
17
17
  topLeft: t,
@@ -38,8 +38,8 @@ function h(e) {
38
38
  }
39
39
  };
40
40
  }
41
- function g(e) {
42
- return h(m(e).map((e) => ({ ...e })));
41
+ function _(e) {
42
+ return g(h(e).map((e) => ({ ...e })));
43
43
  }
44
44
  var ee = class {
45
45
  current;
@@ -50,11 +50,11 @@ var ee = class {
50
50
  this.response = e.response ?? 14, this.snapDistance = e.snapDistance ?? .1;
51
51
  }
52
52
  setTarget(e, t, n) {
53
- let r = Math.max(1, Math.hypot(t, n)), i = !this.current || m(e).some((e, t) => {
54
- let n = m(this.current)[t];
53
+ let r = Math.max(1, Math.hypot(t, n)), i = !this.current || h(e).some((e, t) => {
54
+ let n = h(this.current)[t];
55
55
  return Math.hypot(e.x - n.x, e.y - n.y) / r > this.snapDistance;
56
56
  });
57
- return this.target = g(e), i && (this.current = g(e)), {
57
+ return this.target = _(e), i && (this.current = _(e)), {
58
58
  quad: this.current,
59
59
  snapped: i
60
60
  };
@@ -62,8 +62,8 @@ var ee = class {
62
62
  step(e) {
63
63
  if (!this.current || !this.target) return this.current;
64
64
  let t = 1 - Math.exp(-this.response * Math.max(0, e) / 1e3);
65
- return this.current = h(m(this.current).map((e, n) => {
66
- let r = m(this.target)[n];
65
+ return this.current = g(h(this.current).map((e, n) => {
66
+ let r = h(this.target)[n];
67
67
  return {
68
68
  x: e.x + (r.x - e.x) * t,
69
69
  y: e.y + (r.y - e.y) * t
@@ -76,43 +76,59 @@ var ee = class {
76
76
  getCurrent() {
77
77
  return this.current;
78
78
  }
79
- }, _ = a(null);
79
+ }, te = a(null);
80
80
  //#endregion
81
81
  //#region src/react/context.tsx
82
- function v({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onCapture: p, onCancel: m, onError: h, onSettings: g, onFinderStatus: v, modelUrl: y, ortWasmPaths: b, detectionIntervalMs: x, apiRef: S, children: C }) {
82
+ function v(e) {
83
+ e?.startsWith("blob:") && URL.revokeObjectURL(e);
84
+ }
85
+ function ne(e) {
86
+ try {
87
+ let t = e.toDataURL("image/jpeg", .92);
88
+ return t.startsWith("data:image/") ? t : void 0;
89
+ } catch {
90
+ return;
91
+ }
92
+ }
93
+ function y({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onCapture: f, onCancel: m, onError: h, onSettings: g, onFinderStatus: _, modelUrl: y, ortWasmPaths: b, detectionIntervalMs: x, apiRef: S, children: C }) {
83
94
  let w = u(void 0), T = u(void 0), E = u(void 0), D = u(void 0), O = u({}), k = u(new ee()), A = u(!1), j = u({
84
- onCapture: p,
95
+ onCapture: f,
85
96
  onCancel: m,
86
97
  onError: h,
87
98
  onSettings: g,
88
- onFinderStatus: v
89
- }), M = u(null), [N, te] = d(null), [ne, P] = d("starting"), [F, I] = d(), [re, L] = d(), [R, ie] = d({
99
+ onFinderStatus: _
100
+ }), M = u(null), [N, P] = d(null), [re, F] = d("starting"), [I, L] = d(), [ie, R] = d(), [ae, oe] = d({
90
101
  width: 1,
91
102
  height: 1
92
- }), [ae, oe] = d(), [se, z] = d(), [ce, B] = d(""), [V, le] = d(0), [ue, H] = d(), [de, U] = d(), [fe, W] = d("idle");
103
+ }), [se, ce] = d(), [le, z] = d(), [ue, B] = d(""), [V, de] = d(0), [fe, H] = d(), [pe, U] = d(), [me, W] = d("idle"), [he, G] = d(), K = u(void 0), q = o(() => {
104
+ v(K.current), K.current = void 0, G(void 0);
105
+ }, []), J = o((e, t) => {
106
+ let n = ne(e);
107
+ v(K.current), K.current = n, G(n), t?.pause();
108
+ }, []);
93
109
  c(() => {
94
110
  j.current = {
95
- onCapture: p,
111
+ onCapture: f,
96
112
  onCancel: m,
97
113
  onError: h,
98
114
  onSettings: g,
99
- onFinderStatus: v
115
+ onFinderStatus: _
100
116
  };
101
117
  }, [
102
- p,
118
+ f,
103
119
  m,
104
120
  h,
105
121
  g,
106
- v
122
+ _
107
123
  ]);
108
- let pe = o((e) => {
109
- te(e);
124
+ let ge = o((e) => {
125
+ P(e);
110
126
  }, []);
111
127
  c(() => {
112
128
  if (!n || !N) return;
113
129
  let e = () => {
114
130
  let e = N.getBoundingClientRect();
115
- ie({
131
+ oe({
116
132
  width: e.width,
117
133
  height: e.height
118
134
  });
@@ -131,16 +147,16 @@ function v({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onC
131
147
  if (!n) return;
132
148
  let e = 0, t = performance.now(), r = (n) => {
133
149
  let i = k.current.step(n - t);
134
- t = n, i && L(i), e = requestAnimationFrame(r);
150
+ t = n, i && R(i), e = requestAnimationFrame(r);
135
151
  };
136
152
  return e = requestAnimationFrame(r), () => cancelAnimationFrame(e);
137
153
  }, [n]), c(() => {
138
154
  if (!n || !N) return;
139
155
  let e = !1, t = () => {
140
- T.current?.stop(), T.current = void 0, w.current?.stop(), w.current = void 0, D.current = void 0, E.current = void 0, O.current = {};
156
+ T.current?.stop(), T.current = void 0, w.current?.stop(), w.current = void 0, D.current = void 0, E.current = void 0, O.current = {}, q();
141
157
  };
142
158
  return (async () => {
143
- t(), A.current = !1, P("starting"), B(""), I(void 0), z(void 0), U(void 0), W("idle");
159
+ t(), A.current = !1, F("starting"), B(""), L(void 0), z(void 0), U(void 0), W("idle"), q();
144
160
  try {
145
161
  let t = await i(N, { torch: s });
146
162
  if (e) {
@@ -149,7 +165,7 @@ function v({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onC
149
165
  }
150
166
  w.current = t;
151
167
  let n = t.getSettings();
152
- oe(n), j.current.onSettings?.(n), console.info("[ScannerProvider] camera settings", n), T.current = await r({
168
+ ce(n), j.current.onSettings?.(n), console.info("[ScannerProvider] camera settings", n), T.current = await r({
153
169
  source: N,
154
170
  autoCapture: a,
155
171
  intervalMs: x,
@@ -158,24 +174,24 @@ function v({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onC
158
174
  ortWasmPaths: b
159
175
  },
160
176
  onStatus: (e) => {
161
- if (E.current = e, I(e), j.current.onFinderStatus?.(e), e.quad && e.sourceWidth && e.sourceHeight) {
177
+ if (E.current = e, L(e), j.current.onFinderStatus?.(e), e.quad && e.sourceWidth && e.sourceHeight) {
162
178
  let t = k.current.setTarget(e.quad, e.sourceWidth, e.sourceHeight);
163
- L(t.quad);
164
- } else k.current.clear(), L(void 0);
165
- e.state !== "captured" && !A.current && P("ready");
179
+ R(t.quad);
180
+ } else k.current.clear(), R(void 0);
181
+ e.state !== "captured" && !A.current && F("ready");
166
182
  },
167
183
  captureFrame: async () => {
168
- P("capturing"), O.current = {
184
+ F("capturing"), O.current = {
169
185
  quad: k.current.getCurrent(),
170
186
  sourceWidth: E.current?.sourceWidth,
171
187
  sourceHeight: E.current?.sourceHeight
172
188
  };
173
189
  let e = await t.capturePhoto();
174
190
  if (D.current = e, z(e.method), U(e.diagnostics), H(e.diagnostics), e.luminance <= 10) throw Error(`The captured frame was blank (luminance ${e.luminance.toFixed(1)} via ${e.method}). Keep the scanner visible while capturing and retake.`);
175
- return e.frame;
191
+ return J(e.frame, N), F("captured"), e.frame;
176
192
  },
177
193
  onCaptureError: (e) => {
178
- A.current = !0, P("error"), B(e.message);
194
+ A.current = !0, F("error"), B(e.message);
179
195
  let t = w.current?.getDiagnostics();
180
196
  t && H(t), j.current.onError?.(e);
181
197
  },
@@ -198,7 +214,7 @@ function v({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onC
198
214
  if (e) return;
199
215
  t();
200
216
  let r = n instanceof Error ? n : /* @__PURE__ */ Error("Camera access failed.");
201
- B(r.message), P("error"), j.current.onError?.(r);
217
+ B(r.message), F("error"), j.current.onError?.(r);
202
218
  }
203
219
  })(), () => {
204
220
  e = !0, t();
@@ -211,48 +227,51 @@ function v({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onC
211
227
  y,
212
228
  b,
213
229
  x,
214
- V
230
+ V,
231
+ q,
232
+ J
215
233
  ]);
216
- let G = {
234
+ let Y = {
217
235
  open: n,
218
- phase: ne,
236
+ phase: re,
219
237
  autoCapture: a,
220
- finderStatus: F,
221
- displayQuad: re,
222
- previewSize: R,
223
- settings: ae,
224
- captureMethod: se,
225
- error: ce,
226
- diagnostics: ue,
227
- shutterDiagnostics: de,
228
- copyState: fe,
229
- guidanceHint: F ? t(F.guidance, F.lighting) : void 0,
230
- detectorStatus: F?.modelStatus === "failed" ? "ML failed" : F?.detector === "ml" ? `ML ${F.modelProvider ?? ""}`.trim() : "ML loading"
238
+ finderStatus: I,
239
+ displayQuad: ie,
240
+ previewSize: ae,
241
+ settings: se,
242
+ captureMethod: le,
243
+ error: ue,
244
+ diagnostics: fe,
245
+ shutterDiagnostics: pe,
246
+ copyState: me,
247
+ guidanceHint: I ? t(I.guidance, I.lighting) : void 0,
248
+ detectorStatus: I?.modelStatus === "failed" ? "ML failed" : I?.detector === "ml" ? `ML ${I.modelProvider ?? ""}`.trim() : "ML loading",
249
+ frozenPreviewUrl: he
231
250
  };
232
251
  c(() => {
233
- M.current = G;
252
+ M.current = Y;
234
253
  });
235
- let K = o(() => {
254
+ let X = o(() => {
236
255
  j.current.onCancel();
237
- }, []), q = o(async () => {
256
+ }, []), Z = o(async () => {
238
257
  try {
239
258
  await T.current?.capture();
240
259
  } catch (e) {
241
260
  let t = e instanceof Error ? e : /* @__PURE__ */ Error("Could not capture the camera frame.");
242
261
  A.current = !0, B(t.message);
243
262
  let n = w.current?.getDiagnostics();
244
- n && H(n), D.current?.diagnostics && U(D.current.diagnostics), P("error"), j.current.onError?.(t);
263
+ n && H(n), D.current?.diagnostics && U(D.current.diagnostics), F("error"), j.current.onError?.(t);
245
264
  }
246
- }, []), J = o(() => {
247
- A.current = !1, B(""), U(void 0), W("idle");
265
+ }, []), Q = o(() => {
266
+ A.current = !1, B(""), U(void 0), W("idle"), q();
248
267
  let e = w.current;
249
- P(e ? "ready" : "starting"), e || le((e) => e + 1);
250
- }, []), Y = o(async (e) => {
268
+ N?.paused && N.play(), F(e ? "ready" : "starting"), e || de((e) => e + 1);
269
+ }, [q, N]), _e = o(async (e) => {
251
270
  let t = w.current;
252
271
  t && (await t.setTorch(e), H(t.getDiagnostics()));
253
- }, []), X = o((e) => {
272
+ }, []), ve = o((e) => {
254
273
  T.current?.setAutoCapture(e);
255
- }, []), Z = o(async () => {
274
+ }, []), ye = o(async () => {
256
275
  let t = M.current, n = w.current?.getDiagnostics() ?? t.diagnostics, r = t.finderStatus, i = e({
257
276
  error: t.error || void 0,
258
277
  captureMethod: t.captureMethod,
@@ -283,51 +302,51 @@ function v({ open: n, autoCapture: a = "defaultOn", torch: s = "defaultOff", onC
283
302
  } catch {
284
303
  W("failed");
285
304
  }
286
- }, []), Q = o(() => M.current, []), $ = l(() => ({
287
- capture: q,
288
- cancel: K,
289
- retry: J,
290
- setTorch: Y,
291
- setAutoCapture: X,
292
- copyReport: Z,
293
- getState: Q
305
+ }, []), be = o(() => M.current, []), $ = l(() => ({
306
+ capture: Z,
307
+ cancel: X,
308
+ retry: Q,
309
+ setTorch: _e,
310
+ setAutoCapture: ve,
311
+ copyReport: ye,
312
+ getState: be
294
313
  }), [
295
- q,
296
- K,
297
- J,
298
- Y,
299
- X,
300
314
  Z,
301
- Q
315
+ X,
316
+ Q,
317
+ _e,
318
+ ve,
319
+ ye,
320
+ be
302
321
  ]);
303
322
  c(() => {
304
323
  if (S) return S.current = $, () => {
305
324
  S.current = null;
306
325
  };
307
326
  }, [$, S]);
308
- let me = {
309
- ...G,
327
+ let xe = {
328
+ ...Y,
310
329
  ...$,
311
- bindPreview: pe
330
+ bindPreview: ge
312
331
  };
313
- return /* @__PURE__ */ f(_.Provider, {
314
- value: me,
332
+ return /* @__PURE__ */ p(te.Provider, {
333
+ value: xe,
315
334
  children: C
316
335
  });
317
336
  }
318
337
  //#endregion
319
338
  //#region src/react/hooks.ts
320
- function y() {
339
+ function b() {
321
340
  return u(null);
322
341
  }
323
- function b() {
324
- let e = s(_);
342
+ function x() {
343
+ let e = s(te);
325
344
  if (!e) throw Error("useScanner must be used within ScannerProvider.");
326
345
  return e;
327
346
  }
328
347
  //#endregion
329
348
  //#region src/live-overlay-geometry.ts
330
- function x(e, t, n, r, i) {
349
+ function S(e, t, n, r, i) {
331
350
  let a = Math.max(1, e), o = Math.max(1, t), s = Math.max(1, n), c = Math.max(1, r), l = s / a, u = c / o, d = i === "cover" ? Math.max(l, u) : Math.min(l, u), f = (s - a * d) / 2, p = (c - o * d) / 2;
332
351
  if (i === "contain") return {
333
352
  viewBox: `0 0 ${a} ${o}`,
@@ -347,10 +366,10 @@ function x(e, t, n, r, i) {
347
366
  }
348
367
  //#endregion
349
368
  //#region src/components/ModelDownloadRing.tsx
350
- function S({ snapshot: e }) {
369
+ function C({ snapshot: e }) {
351
370
  if (!e.downloading) return null;
352
371
  let t = e.total && e.total > 0 ? Math.min(1, e.loaded / e.total) : null, n = t === null ? null : Math.round(t * 100), r = 2 * Math.PI * 28;
353
- return /* @__PURE__ */ p("div", {
372
+ return /* @__PURE__ */ m("div", {
354
373
  className: `model-download-ring${t === null ? " is-indeterminate" : ""}`,
355
374
  role: "progressbar",
356
375
  "aria-label": "Model download",
@@ -359,15 +378,15 @@ function S({ snapshot: e }) {
359
378
  "aria-valuenow": n ?? void 0,
360
379
  "data-loaded": e.loaded,
361
380
  "data-total": e.total ?? "",
362
- children: [/* @__PURE__ */ p("svg", {
381
+ children: [/* @__PURE__ */ m("svg", {
363
382
  viewBox: "0 0 72 72",
364
383
  "aria-hidden": "true",
365
- children: [/* @__PURE__ */ f("circle", {
384
+ children: [/* @__PURE__ */ p("circle", {
366
385
  className: "track",
367
386
  cx: "36",
368
387
  cy: "36",
369
388
  r: 28
370
- }), /* @__PURE__ */ f("circle", {
389
+ }), /* @__PURE__ */ p("circle", {
371
390
  className: "value",
372
391
  cx: "36",
373
392
  cy: "36",
@@ -375,15 +394,15 @@ function S({ snapshot: e }) {
375
394
  strokeDasharray: t === null ? void 0 : `${r} ${r}`,
376
395
  strokeDashoffset: t === null ? void 0 : r * (1 - t)
377
396
  })]
378
- }), n === null ? /* @__PURE__ */ f("strong", {
397
+ }), n === null ? /* @__PURE__ */ p("strong", {
379
398
  className: "model-download-ring__pending",
380
399
  children: "…"
381
- }) : /* @__PURE__ */ p("strong", { children: [n, "%"] })]
400
+ }) : /* @__PURE__ */ m("strong", { children: [n, "%"] })]
382
401
  });
383
402
  }
384
403
  //#endregion
385
404
  //#region src/react/parts.tsx
386
- var C = {
405
+ var w = {
387
406
  primaryColorHex: "--scanner-overlay-primary",
388
407
  seekingColorHex: "--scanner-overlay-seeking",
389
408
  detectingColorHex: "--scanner-overlay-detecting",
@@ -391,23 +410,23 @@ var C = {
391
410
  readyColorHex: "--scanner-overlay-ready",
392
411
  capturedColorHex: "--scanner-overlay-captured"
393
412
  };
394
- function w(e) {
413
+ function T(e) {
395
414
  if (!e) return;
396
415
  let t = {};
397
- for (let [n, r] of Object.entries(C)) {
416
+ for (let [n, r] of Object.entries(w)) {
398
417
  let i = e[n]?.trim();
399
418
  i && (t[r] = i);
400
419
  }
401
420
  return Object.keys(t).length > 0 ? t : void 0;
402
421
  }
403
- function T({ theme: e, style: t, title: n = "Scan a document", children: r }) {
404
- let i = b();
422
+ function E({ theme: e, style: t, title: n = "Scan a document", children: r }) {
423
+ let i = x();
405
424
  if (!i.open) return null;
406
- let a = w(e), o = a ? {
425
+ let a = T(e), o = a ? {
407
426
  ...t,
408
427
  ...a
409
428
  } : t;
410
- return /* @__PURE__ */ f("div", {
429
+ return /* @__PURE__ */ p("div", {
411
430
  className: `scanner-camera-overlay ${i.finderStatus?.state === "captured" ? "is-captured" : ""}`.trim(),
412
431
  style: o,
413
432
  role: "dialog",
@@ -416,43 +435,54 @@ function T({ theme: e, style: t, title: n = "Scan a document", children: r }) {
416
435
  children: r
417
436
  });
418
437
  }
419
- function E() {
420
- let { bindPreview: e } = b();
421
- return /* @__PURE__ */ f("video", {
422
- ref: e,
438
+ function D() {
439
+ let { bindPreview: e, frozenPreviewUrl: t } = x(), n = u(null), r = o((t) => {
440
+ n.current = t, e(t);
441
+ }, [e]);
442
+ return c(() => {
443
+ t && n.current?.pause();
444
+ }, [t]), /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("video", {
445
+ ref: r,
423
446
  className: "scanner-camera-overlay__video",
424
447
  muted: !0,
425
448
  autoPlay: !0,
426
449
  playsInline: !0,
427
450
  style: { objectFit: "cover" },
451
+ "aria-hidden": !!t,
428
452
  "aria-label": "Rear camera preview"
429
- });
453
+ }), t ? /* @__PURE__ */ p("img", {
454
+ src: t,
455
+ className: "scanner-camera-overlay__video scanner-camera-overlay__still",
456
+ alt: "",
457
+ "aria-label": "Captured document"
458
+ }) : null] });
430
459
  }
431
- function D() {
432
- let { finderStatus: e, displayQuad: t, previewSize: n } = b();
460
+ function O() {
461
+ let { finderStatus: e, displayQuad: t, previewSize: n } = x();
433
462
  if (!t || !e?.sourceWidth || !e.sourceHeight) return null;
434
- let r = x(e.sourceWidth, e.sourceHeight, n.width, n.height, "cover");
435
- return /* @__PURE__ */ f("svg", {
463
+ let r = S(e.sourceWidth, e.sourceHeight, n.width, n.height, "cover");
464
+ return /* @__PURE__ */ p("svg", {
436
465
  className: `scanner-camera-overlay__quad ${e.state}`,
437
466
  viewBox: r.viewBox,
438
467
  preserveAspectRatio: r.preserveAspectRatio,
439
468
  "aria-label": `${e.state} document boundary`,
440
- children: /* @__PURE__ */ f("polygon", { points: `${t.topLeft.x},${t.topLeft.y} ${t.topRight.x},${t.topRight.y} ${t.bottomRight.x},${t.bottomRight.y} ${t.bottomLeft.x},${t.bottomLeft.y}` })
469
+ children: /* @__PURE__ */ p("polygon", { points: `${t.topLeft.x},${t.topLeft.y} ${t.topRight.x},${t.topRight.y} ${t.bottomRight.x},${t.bottomRight.y} ${t.bottomLeft.x},${t.bottomLeft.y}` })
441
470
  });
442
471
  }
443
- function O({ title: e = "Scan a document" }) {
444
- let { phase: t, guidanceHint: n, cancel: r } = b();
445
- return /* @__PURE__ */ p("div", {
472
+ function k({ title: e = "Scan a document" }) {
473
+ let { phase: t, guidanceHint: n, cancel: r } = x();
474
+ return /* @__PURE__ */ m("div", {
446
475
  className: "scanner-camera-overlay__topbar",
447
- children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("strong", { children: e }), /* @__PURE__ */ p("span", {
476
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("strong", { children: e }), /* @__PURE__ */ m("span", {
448
477
  "aria-live": "polite",
449
478
  children: [
450
479
  t === "starting" && "Starting rear camera…",
451
480
  t === "ready" && (n ?? "Place the document in the frame"),
452
481
  t === "capturing" && "Capturing full resolution…",
482
+ t === "captured" && "Document captured",
453
483
  t === "error" && "Camera unavailable"
454
484
  ]
455
- })] }), /* @__PURE__ */ f("button", {
485
+ })] }), /* @__PURE__ */ p("button", {
456
486
  type: "button",
457
487
  onClick: r,
458
488
  "aria-label": "Close camera",
@@ -460,51 +490,51 @@ function O({ title: e = "Scan a document" }) {
460
490
  })]
461
491
  });
462
492
  }
463
- function k() {
464
- let { phase: e, error: t, diagnostics: n, copyState: r, retry: i, copyReport: a, cancel: o } = b();
465
- return e === "error" ? /* @__PURE__ */ p("div", {
493
+ function A() {
494
+ let { phase: e, error: t, diagnostics: n, copyState: r, retry: i, copyReport: a, cancel: o } = x();
495
+ return e === "error" ? /* @__PURE__ */ m("div", {
466
496
  className: "scanner-camera-overlay__message",
467
497
  role: "alert",
468
498
  children: [
469
- /* @__PURE__ */ f("strong", { children: n ? "Capture failed" : "Could not open the camera" }),
470
- /* @__PURE__ */ f("p", { children: t }),
471
- /* @__PURE__ */ p("div", { children: [
472
- /* @__PURE__ */ f("button", {
499
+ /* @__PURE__ */ p("strong", { children: n ? "Capture failed" : "Could not open the camera" }),
500
+ /* @__PURE__ */ p("p", { children: t }),
501
+ /* @__PURE__ */ m("div", { children: [
502
+ /* @__PURE__ */ p("button", {
473
503
  type: "button",
474
504
  onClick: i,
475
505
  children: "Try again"
476
506
  }),
477
- /* @__PURE__ */ f("button", {
507
+ /* @__PURE__ */ p("button", {
478
508
  type: "button",
479
509
  onClick: () => void a(),
480
510
  children: r === "copied" ? "Copied" : r === "failed" ? "Copy failed" : "Copy report"
481
511
  }),
482
- /* @__PURE__ */ f("button", {
512
+ /* @__PURE__ */ p("button", {
483
513
  type: "button",
484
514
  onClick: o,
485
515
  children: "Cancel"
486
516
  })
487
517
  ] })
488
518
  ]
489
- }) : e === "starting" ? /* @__PURE__ */ p("div", {
519
+ }) : e === "starting" ? /* @__PURE__ */ m("div", {
490
520
  className: "scanner-camera-overlay__message",
491
521
  "aria-live": "polite",
492
522
  children: [
493
- /* @__PURE__ */ f("span", { className: "scanner-camera-overlay__spinner" }),
494
- /* @__PURE__ */ f("strong", { children: "Requesting the highest practical resolution" }),
495
- /* @__PURE__ */ f("p", { children: "Allow camera access to continue." })
523
+ /* @__PURE__ */ p("span", { className: "scanner-camera-overlay__spinner" }),
524
+ /* @__PURE__ */ p("strong", { children: "Requesting the highest practical resolution" }),
525
+ /* @__PURE__ */ p("p", { children: "Allow camera access to continue." })
496
526
  ]
497
527
  }) : null;
498
528
  }
499
- function A() {
500
- let { finderStatus: e, detectorStatus: t, settings: n } = b(), r = n?.width, i = n?.height;
501
- return /* @__PURE__ */ f("div", {
529
+ function j() {
530
+ let { finderStatus: e, detectorStatus: t, settings: n } = x(), r = n?.width, i = n?.height;
531
+ return /* @__PURE__ */ p("div", {
502
532
  className: "scanner-camera-overlay__status",
503
533
  "aria-live": "polite",
504
- children: /* @__PURE__ */ p("div", {
534
+ children: /* @__PURE__ */ m("div", {
505
535
  className: "scanner-camera-overlay__status-line",
506
536
  children: [
507
- /* @__PURE__ */ f("span", { className: e?.state ?? "detecting" }),
537
+ /* @__PURE__ */ p("span", { className: e?.state ?? "detecting" }),
508
538
  e?.state ?? "detecting",
509
539
  e ? ` · ${Math.round(e.confidence * 100)}% · ${e.stableFrames}/${e.requiredStableFrames}` : "",
510
540
  ` · ${t}`,
@@ -514,25 +544,25 @@ function A() {
514
544
  })
515
545
  });
516
546
  }
517
- function j() {
518
- let { diagnostics: e, shutterDiagnostics: t, captureMethod: r, copyState: i, copyReport: a } = b(), o = e?.engine ?? n();
519
- return /* @__PURE__ */ p("dl", {
547
+ function M() {
548
+ let { diagnostics: e, shutterDiagnostics: t, captureMethod: r, copyState: i, copyReport: a } = x(), o = e?.engine ?? n();
549
+ return /* @__PURE__ */ m("dl", {
520
550
  className: "scanner-camera-overlay__diagnostics",
521
551
  "aria-label": "Camera diagnostics",
522
552
  children: [
523
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "engine" }), /* @__PURE__ */ p("dd", { children: [
553
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "engine" }), /* @__PURE__ */ m("dd", { children: [
524
554
  o.engine,
525
555
  "/",
526
556
  o.browser,
527
557
  o.iosWebKit ? " ios" : ""
528
558
  ] })] }),
529
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "video" }), /* @__PURE__ */ f("dd", { children: e ? `${e.videoWidth}×${e.videoHeight} rs${e.readyState}${e.paused ? " paused" : ""}${e.rendered ? "" : " hidden"}` : "starting" })] }),
530
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "track" }), /* @__PURE__ */ f("dd", { children: e ? `${e.trackReadyState}${e.trackMuted ? " muted" : ""}${e.trackEnabled ? "" : " disabled"}` : "—" })] }),
531
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "torch" }), /* @__PURE__ */ f("dd", { children: e ? `${e.torch.mode} · ${e.torch.supported ? e.torch.on ? "on" : "off" : "unsupported"}` : "starting" })] }),
532
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "luma" }), /* @__PURE__ */ f("dd", { children: e ? `live ${e.liveLuminance.toFixed(1)} · mirror ${e.mirrorLuminance.toFixed(1)}${Number.isFinite(e.mirrorAgeMs) ? ` (${Math.round(e.mirrorAgeMs)}ms)` : " (none)"}` : "—" })] }),
533
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "path" }), /* @__PURE__ */ f("dd", { children: r ?? "video-frame / live-mirror" })] }),
534
- t ? /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "shutter" }), /* @__PURE__ */ f("dd", { children: `live ${t.liveLuminance.toFixed(1)} · mirror ${t.mirrorLuminance.toFixed(1)}${Number.isFinite(t.mirrorAgeMs) ? ` (${Math.round(t.mirrorAgeMs)}ms)` : " (none)"}` })] }) : null,
535
- /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("dt", { children: "share" }), /* @__PURE__ */ f("dd", { children: /* @__PURE__ */ f("button", {
559
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "video" }), /* @__PURE__ */ p("dd", { children: e ? `${e.videoWidth}×${e.videoHeight} rs${e.readyState}${e.paused ? " paused" : ""}${e.rendered ? "" : " hidden"}` : "starting" })] }),
560
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "track" }), /* @__PURE__ */ p("dd", { children: e ? `${e.trackReadyState}${e.trackMuted ? " muted" : ""}${e.trackEnabled ? "" : " disabled"}` : "—" })] }),
561
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "torch" }), /* @__PURE__ */ p("dd", { children: e ? `${e.torch.mode} · ${e.torch.supported ? e.torch.on ? "on" : "off" : "unsupported"}` : "starting" })] }),
562
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "luma" }), /* @__PURE__ */ p("dd", { children: e ? `live ${e.liveLuminance.toFixed(1)} · mirror ${e.mirrorLuminance.toFixed(1)}${Number.isFinite(e.mirrorAgeMs) ? ` (${Math.round(e.mirrorAgeMs)}ms)` : " (none)"}` : "—" })] }),
563
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "path" }), /* @__PURE__ */ p("dd", { children: r ?? "video-frame / live-mirror" })] }),
564
+ t ? /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "shutter" }), /* @__PURE__ */ p("dd", { children: `live ${t.liveLuminance.toFixed(1)} · mirror ${t.mirrorLuminance.toFixed(1)}${Number.isFinite(t.mirrorAgeMs) ? ` (${Math.round(t.mirrorAgeMs)}ms)` : " (none)"}` })] }) : null,
565
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("dt", { children: "share" }), /* @__PURE__ */ p("dd", { children: /* @__PURE__ */ p("button", {
536
566
  type: "button",
537
567
  className: "scanner-camera-overlay__copy",
538
568
  onClick: () => void a(),
@@ -541,35 +571,35 @@ function j() {
541
571
  ]
542
572
  });
543
573
  }
544
- function M() {
545
- let { autoCapture: e, phase: t, finderStatus: n, diagnostics: r, captureMethod: i, settings: a, cancel: o, capture: s, setAutoCapture: c, setTorch: l } = b(), u = a?.width, d = a?.height;
546
- return /* @__PURE__ */ p("div", {
574
+ function N() {
575
+ let { autoCapture: e, phase: t, finderStatus: n, diagnostics: r, captureMethod: i, settings: a, cancel: o, capture: s, setAutoCapture: c, setTorch: l } = x(), u = a?.width, d = a?.height;
576
+ return /* @__PURE__ */ m("div", {
547
577
  className: "scanner-camera-overlay__controls",
548
578
  children: [
549
- /* @__PURE__ */ f("button", {
579
+ /* @__PURE__ */ p("button", {
550
580
  type: "button",
551
581
  className: "scanner-camera-overlay__cancel",
552
582
  onClick: o,
553
583
  children: "Cancel"
554
584
  }),
555
- /* @__PURE__ */ p("div", {
585
+ /* @__PURE__ */ m("div", {
556
586
  className: "scanner-camera-overlay__capture",
557
- children: [e !== "only" && /* @__PURE__ */ f("button", {
587
+ children: [e !== "only" && /* @__PURE__ */ p("button", {
558
588
  type: "button",
559
589
  className: "scanner-camera-overlay__shutter",
560
590
  onClick: () => void s(),
561
591
  disabled: t !== "ready",
562
592
  "aria-label": "Capture full-resolution photo",
563
- children: /* @__PURE__ */ f("span", {})
564
- }), /* @__PURE__ */ p("div", {
593
+ children: /* @__PURE__ */ p("span", {})
594
+ }), /* @__PURE__ */ m("div", {
565
595
  className: "scanner-camera-overlay__toggles",
566
- children: [n?.autoCapture.visible && /* @__PURE__ */ p("label", { children: [/* @__PURE__ */ f("input", {
596
+ children: [n?.autoCapture.visible && /* @__PURE__ */ m("label", { children: [/* @__PURE__ */ p("input", {
567
597
  type: "checkbox",
568
598
  checked: n.autoCapture.checked,
569
599
  onChange: (e) => c(e.target.checked)
570
- }), "Auto-capture"] }), r?.torch.visible && /* @__PURE__ */ p("label", {
600
+ }), "Auto-capture"] }), r?.torch.visible && /* @__PURE__ */ m("label", {
571
601
  title: r.torch.automatic ? "Torch is controlled automatically from scene brightness" : void 0,
572
- children: [/* @__PURE__ */ f("input", {
602
+ children: [/* @__PURE__ */ p("input", {
573
603
  type: "checkbox",
574
604
  checked: r.torch.on,
575
605
  disabled: !r.torch.mutable,
@@ -578,17 +608,17 @@ function M() {
578
608
  })]
579
609
  })]
580
610
  }),
581
- /* @__PURE__ */ p("div", {
611
+ /* @__PURE__ */ m("div", {
582
612
  className: "scanner-camera-overlay__quality",
583
- children: [/* @__PURE__ */ f("span", { children: i === "live-mirror" ? "Mirror" : "Camera" }), /* @__PURE__ */ f("strong", { children: u && d ? `${u} × ${d}` : "Measuring…" })]
613
+ children: [/* @__PURE__ */ p("span", { children: i === "live-mirror" ? "Mirror" : "Camera" }), /* @__PURE__ */ p("strong", { children: u && d ? `${u} × ${d}` : "Measuring…" })]
584
614
  })
585
615
  ]
586
616
  });
587
617
  }
588
- function N({ snapshot: e }) {
589
- return b(), e ? /* @__PURE__ */ f(S, { snapshot: e }) : null;
618
+ function P({ snapshot: e }) {
619
+ return x(), e ? /* @__PURE__ */ p(C, { snapshot: e }) : null;
590
620
  }
591
621
  //#endregion
592
- export { M as ScannerControls, j as ScannerDiagnostics, T as ScannerFrame, N as ScannerModelDownload, k as ScannerNotice, E as ScannerPreview, v as ScannerProvider, D as ScannerQuad, A as ScannerStatus, O as ScannerTopBar, b as useScanner, y as useScannerRef };
622
+ export { N as ScannerControls, M as ScannerDiagnostics, E as ScannerFrame, P as ScannerModelDownload, A as ScannerNotice, D as ScannerPreview, y as ScannerProvider, O as ScannerQuad, j as ScannerStatus, k as ScannerTopBar, x as useScanner, b as useScannerRef };
593
623
 
594
624
  //# sourceMappingURL=react.js.map
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../src/sdk/display-quad.ts","../src/react/scanner-context.ts","../src/react/context.tsx","../src/react/hooks.ts","../src/live-overlay-geometry.ts","../src/components/ModelDownloadRing.tsx","../src/react/parts.tsx"],"sourcesContent":["import type { DocumentQuad, Point } from './types'\n\nfunction points(quad: DocumentQuad) {\n return [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft]\n}\n\nfunction withPoints(next: Point[]): DocumentQuad {\n const [topLeft, topRight, bottomRight, bottomLeft] = next\n return {\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n edges: {\n top: { start: topLeft, end: topRight },\n right: { start: topRight, end: bottomRight },\n bottom: { start: bottomRight, end: bottomLeft },\n left: { start: bottomLeft, end: topLeft },\n },\n }\n}\n\nfunction cloneQuad(quad: DocumentQuad) {\n return withPoints(points(quad).map((point) => ({ ...point })))\n}\n\nexport interface QuadDisplaySmootherOptions {\n response?: number\n snapDistance?: number\n}\n\n/**\n * Smooths only the displayed quad. Detector stability must continue to use raw\n * detections and must never consume this animated output.\n */\nexport class QuadDisplaySmoother {\n private current?: DocumentQuad\n private target?: DocumentQuad\n private readonly response: number\n private readonly snapDistance: number\n\n constructor(options: QuadDisplaySmootherOptions = {}) {\n this.response = options.response ?? 14\n this.snapDistance = options.snapDistance ?? 0.1\n }\n\n setTarget(quad: DocumentQuad, frameWidth: number, frameHeight: number) {\n const diagonal = Math.max(1, Math.hypot(frameWidth, frameHeight))\n const shouldSnap = !this.current || points(quad).some((point, index) => {\n const previous = points(this.current!)[index]\n return Math.hypot(point.x - previous.x, point.y - previous.y) / diagonal > this.snapDistance\n })\n this.target = cloneQuad(quad)\n if (shouldSnap) this.current = cloneQuad(quad)\n return { quad: this.current, snapped: shouldSnap }\n }\n\n step(deltaMs: number) {\n if (!this.current || !this.target) return this.current\n const alpha = 1 - Math.exp(-this.response * Math.max(0, deltaMs) / 1000)\n this.current = withPoints(points(this.current).map((point, index) => {\n const target = points(this.target!)[index]\n return {\n x: point.x + (target.x - point.x) * alpha,\n y: point.y + (target.y - point.y) * alpha,\n }\n }))\n return this.current\n }\n\n clear() {\n this.current = undefined\n this.target = undefined\n }\n\n getCurrent() {\n return this.current\n }\n}\n","import { createContext } from 'react'\nimport type { ScannerApi, ScannerState } from './types'\n\nexport interface ScannerContextValue extends ScannerState, ScannerApi {\n bindPreview: (node: HTMLVideoElement | null) => void\n}\n\nexport const ScannerContext = createContext<ScannerContextValue | null>(null)\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport {\n formatCaptureDiagnosticsReport,\n NEAR_BLACK_LUMINANCE,\n startCamera,\n type CameraDiagnostics,\n type CameraPhoto,\n type CameraSession,\n} from '../sdk/camera'\nimport {\n selectFinderHint,\n startFinder,\n type FinderSession,\n type FinderStatus,\n} from '../sdk/finder'\nimport { QuadDisplaySmoother } from '../sdk/display-quad'\nimport type { DocumentQuad } from '../sdk/types'\nimport type { ScannerApi, ScannerProviderProps, ScannerState } from './types'\nimport { ScannerContext, type ScannerContextValue } from './scanner-context'\n\nexport function ScannerProvider({\n open,\n autoCapture = 'defaultOn',\n torch = 'defaultOff',\n onCapture,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n apiRef,\n children,\n}: ScannerProviderProps) {\n const cameraRef = useRef<CameraSession | undefined>(undefined)\n const finderRef = useRef<FinderSession | undefined>(undefined)\n const finderStatusRef = useRef<FinderStatus | undefined>(undefined)\n const latestPhotoRef = useRef<CameraPhoto | undefined>(undefined)\n const capturedDisplayRef = useRef<{\n quad?: DocumentQuad\n sourceWidth?: number\n sourceHeight?: number\n }>({})\n const displaySmootherRef = useRef(new QuadDisplaySmoother())\n const captureErrorRef = useRef(false)\n const callbacksRef = useRef({ onCapture, onCancel, onError, onSettings, onFinderStatus })\n const stateRef = useRef<ScannerState>(null!)\n const [preview, setPreview] = useState<HTMLVideoElement | null>(null)\n const [phase, setPhase] = useState<ScannerState['phase']>('starting')\n const [finderStatus, setFinderStatus] = useState<FinderStatus>()\n const [displayQuad, setDisplayQuad] = useState<DocumentQuad>()\n const [previewSize, setPreviewSize] = useState({ width: 1, height: 1 })\n const [settings, setSettings] = useState<MediaTrackSettings>()\n const [captureMethod, setCaptureMethod] = useState<CameraPhoto['method']>()\n const [error, setError] = useState('')\n const [attempt, setAttempt] = useState(0)\n const [diagnostics, setDiagnostics] = useState<CameraDiagnostics>()\n const [shutterDiagnostics, setShutterDiagnostics] = useState<CameraDiagnostics>()\n const [copyState, setCopyState] = useState<ScannerState['copyState']>('idle')\n\n useEffect(() => {\n callbacksRef.current = { onCapture, onCancel, onError, onSettings, onFinderStatus }\n }, [onCapture, onCancel, onError, onSettings, onFinderStatus])\n\n const bindPreview = useCallback((node: HTMLVideoElement | null) => {\n setPreview(node)\n }, [])\n\n useEffect(() => {\n if (!open || !preview) return\n const updateSize = () => {\n const bounds = preview.getBoundingClientRect()\n setPreviewSize({ width: bounds.width, height: bounds.height })\n }\n updateSize()\n if (typeof ResizeObserver === 'undefined') {\n window.addEventListener('resize', updateSize)\n return () => window.removeEventListener('resize', updateSize)\n }\n const observer = new ResizeObserver(updateSize)\n observer.observe(preview)\n return () => observer.disconnect()\n }, [open, preview])\n\n useEffect(() => {\n if (!open) return\n const poll = window.setInterval(() => {\n const current = cameraRef.current?.getDiagnostics()\n if (current) setDiagnostics(current)\n }, 500)\n return () => window.clearInterval(poll)\n }, [open, attempt])\n\n useEffect(() => {\n if (!open) return\n let animationFrame = 0\n let previousTime = performance.now()\n const animate = (time: number) => {\n const next = displaySmootherRef.current.step(time - previousTime)\n previousTime = time\n if (next) setDisplayQuad(next)\n animationFrame = requestAnimationFrame(animate)\n }\n animationFrame = requestAnimationFrame(animate)\n return () => cancelAnimationFrame(animationFrame)\n }, [open])\n\n useEffect(() => {\n if (!open || !preview) return\n let cancelled = false\n\n const stop = () => {\n finderRef.current?.stop()\n finderRef.current = undefined\n cameraRef.current?.stop()\n cameraRef.current = undefined\n latestPhotoRef.current = undefined\n finderStatusRef.current = undefined\n capturedDisplayRef.current = {}\n }\n\n const start = async () => {\n stop()\n captureErrorRef.current = false\n setPhase('starting')\n setError('')\n setFinderStatus(undefined)\n setCaptureMethod(undefined)\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n try {\n const camera = await startCamera(preview, { torch })\n if (cancelled) {\n camera.stop()\n return\n }\n cameraRef.current = camera\n const actualSettings = camera.getSettings()\n setSettings(actualSettings)\n callbacksRef.current.onSettings?.(actualSettings)\n console.info('[ScannerProvider] camera settings', actualSettings)\n finderRef.current = await startFinder({\n source: preview,\n autoCapture,\n intervalMs: detectionIntervalMs,\n detection: {\n modelUrl,\n ortWasmPaths,\n },\n onStatus: (status) => {\n finderStatusRef.current = status\n setFinderStatus(status)\n callbacksRef.current.onFinderStatus?.(status)\n if (status.quad && status.sourceWidth && status.sourceHeight) {\n const update = displaySmootherRef.current.setTarget(\n status.quad,\n status.sourceWidth,\n status.sourceHeight,\n )\n setDisplayQuad(update.quad)\n } else {\n displaySmootherRef.current.clear()\n setDisplayQuad(undefined)\n }\n if (status.state !== 'captured' && !captureErrorRef.current) setPhase('ready')\n },\n captureFrame: async () => {\n setPhase('capturing')\n capturedDisplayRef.current = {\n quad: displaySmootherRef.current.getCurrent(),\n sourceWidth: finderStatusRef.current?.sourceWidth,\n sourceHeight: finderStatusRef.current?.sourceHeight,\n }\n const photo = await camera.capturePhoto()\n latestPhotoRef.current = photo\n setCaptureMethod(photo.method)\n setShutterDiagnostics(photo.diagnostics)\n setDiagnostics(photo.diagnostics)\n if (photo.luminance <= NEAR_BLACK_LUMINANCE) {\n throw new Error(\n `The captured frame was blank (luminance ${photo.luminance.toFixed(1)} via ${photo.method}). Keep the scanner visible while capturing and retake.`,\n )\n }\n return photo.frame\n },\n onCaptureError: (captureError) => {\n captureErrorRef.current = true\n setPhase('error')\n setError(captureError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n callbacksRef.current.onError?.(captureError)\n },\n onCapture: async (capture) => {\n const photo = latestPhotoRef.current\n await new Promise((resolve) => window.setTimeout(resolve, 140))\n await callbacksRef.current.onCapture({\n ...capture,\n method: photo?.method ?? 'video-frame',\n settings: photo?.settings ?? camera.getSettings(),\n fallbackReason: photo?.fallbackReason,\n luminance: photo?.luminance,\n diagnostics: photo?.diagnostics,\n displayedQuad: capturedDisplayRef.current.quad,\n displaySourceWidth: capturedDisplayRef.current.sourceWidth,\n displaySourceHeight: capturedDisplayRef.current.sourceHeight,\n })\n },\n })\n } catch (cause) {\n if (cancelled) return\n stop()\n const nextError = cause instanceof Error ? cause : new Error('Camera access failed.')\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }\n\n void start()\n return () => {\n cancelled = true\n stop()\n }\n }, [\n open,\n preview,\n autoCapture,\n torch,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n attempt,\n ])\n\n const guidanceHint = finderStatus\n ? selectFinderHint(finderStatus.guidance, finderStatus.lighting)\n : undefined\n const detectorStatus = finderStatus?.modelStatus === 'failed'\n ? 'ML failed'\n : finderStatus?.detector === 'ml'\n ? `ML ${finderStatus.modelProvider ?? ''}`.trim()\n : 'ML loading'\n const state: ScannerState = {\n open,\n phase,\n autoCapture,\n finderStatus,\n displayQuad,\n previewSize,\n settings,\n captureMethod,\n error,\n diagnostics,\n shutterDiagnostics,\n copyState,\n guidanceHint,\n detectorStatus,\n }\n useEffect(() => {\n stateRef.current = state\n })\n\n const cancel = useCallback(() => {\n callbacksRef.current.onCancel()\n }, [])\n\n const capture = useCallback(async () => {\n try {\n await finderRef.current?.capture()\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Could not capture the camera frame.')\n captureErrorRef.current = true\n setError(nextError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n if (latestPhotoRef.current?.diagnostics) setShutterDiagnostics(latestPhotoRef.current.diagnostics)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }, [])\n\n const retry = useCallback(() => {\n captureErrorRef.current = false\n setError('')\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n const liveCamera = cameraRef.current\n setPhase(liveCamera ? 'ready' : 'starting')\n if (!liveCamera) setAttempt((value) => value + 1)\n }, [])\n\n const setTorch = useCallback(async (enabled: boolean) => {\n const camera = cameraRef.current\n if (!camera) return\n await camera.setTorch(enabled)\n setDiagnostics(camera.getDiagnostics())\n }, [])\n\n const setAutoCapture = useCallback((enabled: boolean) => {\n finderRef.current?.setAutoCapture(enabled)\n }, [])\n\n const copyReport = useCallback(async () => {\n const current = stateRef.current\n const live = cameraRef.current?.getDiagnostics() ?? current.diagnostics\n const finder = current.finderStatus\n const report = formatCaptureDiagnosticsReport({\n error: current.error || undefined,\n captureMethod: current.captureMethod,\n luminance: latestPhotoRef.current?.luminance,\n fallbackReason: latestPhotoRef.current?.fallbackReason,\n shutter: current.shutterDiagnostics ?? latestPhotoRef.current?.diagnostics,\n live,\n finder: finder\n ? {\n state: finder.state,\n confidence: finder.confidence,\n stableFrames: finder.stableFrames,\n requiredStableFrames: finder.requiredStableFrames,\n detector: finder.detector,\n modelStatus: finder.modelStatus,\n sourceWidth: finder.sourceWidth,\n sourceHeight: finder.sourceHeight,\n }\n : undefined,\n })\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(report)\n } else {\n const field = document.createElement('textarea')\n field.value = report\n field.setAttribute('readonly', '')\n field.style.position = 'fixed'\n field.style.left = '-9999px'\n document.body.append(field)\n field.select()\n const copied = document.execCommand('copy')\n field.remove()\n if (!copied) throw new Error('Clipboard copy is unavailable.')\n }\n setCopyState('copied')\n } catch {\n setCopyState('failed')\n }\n }, [])\n\n const getState = useCallback(() => stateRef.current, [])\n\n const api = useMemo<ScannerApi>(() => ({\n capture,\n cancel,\n retry,\n setTorch,\n setAutoCapture,\n copyReport,\n getState,\n }), [capture, cancel, retry, setTorch, setAutoCapture, copyReport, getState])\n\n useEffect(() => {\n if (!apiRef) return\n apiRef.current = api\n return () => {\n apiRef.current = null\n }\n }, [api, apiRef])\n\n const value: ScannerContextValue = {\n ...state,\n ...api,\n bindPreview,\n }\n\n return (\n <ScannerContext.Provider value={value}>\n {children}\n </ScannerContext.Provider>\n )\n}\n","import { useContext, useRef } from 'react'\nimport type { ScannerApi } from './types'\nimport { ScannerContext } from './scanner-context'\n\nexport function useScannerRef() {\n return useRef<ScannerApi | null>(null)\n}\n\nexport function useScanner() {\n const value = useContext(ScannerContext)\n if (!value) throw new Error('useScanner must be used within ScannerProvider.')\n return value\n}\n","import type { Point } from './sdk/types'\n\nexport type LivePreviewFit = 'contain' | 'cover'\n\nexport interface LiveOverlayTransform {\n viewBox: string\n preserveAspectRatio: 'none' | 'xMidYMid meet'\n scale: number\n offsetX: number\n offsetY: number\n}\n\nexport function liveOverlayTransform(\n sourceWidth: number,\n sourceHeight: number,\n renderedWidth: number,\n renderedHeight: number,\n fit: LivePreviewFit,\n): LiveOverlayTransform {\n const safeSourceWidth = Math.max(1, sourceWidth)\n const safeSourceHeight = Math.max(1, sourceHeight)\n const safeRenderedWidth = Math.max(1, renderedWidth)\n const safeRenderedHeight = Math.max(1, renderedHeight)\n const widthScale = safeRenderedWidth / safeSourceWidth\n const heightScale = safeRenderedHeight / safeSourceHeight\n const scale = fit === 'cover'\n ? Math.max(widthScale, heightScale)\n : Math.min(widthScale, heightScale)\n const offsetX = (safeRenderedWidth - safeSourceWidth * scale) / 2\n const offsetY = (safeRenderedHeight - safeSourceHeight * scale) / 2\n if (fit === 'contain') {\n return {\n viewBox: `0 0 ${safeSourceWidth} ${safeSourceHeight}`,\n preserveAspectRatio: 'xMidYMid meet',\n scale,\n offsetX,\n offsetY,\n }\n }\n const visibleWidth = safeRenderedWidth / scale\n const visibleHeight = safeRenderedHeight / scale\n return {\n viewBox: `${-offsetX / scale} ${-offsetY / scale} ${visibleWidth} ${visibleHeight}`,\n preserveAspectRatio: 'none',\n scale,\n offsetX,\n offsetY,\n }\n}\n\nexport function mapLiveSourcePoint(point: Point, transform: LiveOverlayTransform): Point {\n return {\n x: transform.offsetX + point.x * transform.scale,\n y: transform.offsetY + point.y * transform.scale,\n }\n}\n","import type { ModelDownloadSnapshot } from '../sdk/model-download'\n\nexport function ModelDownloadRing({ snapshot }: { snapshot: ModelDownloadSnapshot }) {\n if (!snapshot.downloading) return null\n const ratio = snapshot.total && snapshot.total > 0\n ? Math.min(1, snapshot.loaded / snapshot.total)\n : null\n const percent = ratio === null ? null : Math.round(ratio * 100)\n const radius = 28\n const circumference = 2 * Math.PI * radius\n return (\n <div\n className={`model-download-ring${ratio === null ? ' is-indeterminate' : ''}`}\n role=\"progressbar\"\n aria-label=\"Model download\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent ?? undefined}\n data-loaded={snapshot.loaded}\n data-total={snapshot.total ?? ''}\n >\n <svg viewBox=\"0 0 72 72\" aria-hidden=\"true\">\n <circle className=\"track\" cx=\"36\" cy=\"36\" r={radius} />\n <circle\n className=\"value\"\n cx=\"36\"\n cy=\"36\"\n r={radius}\n strokeDasharray={ratio === null ? undefined : `${circumference} ${circumference}`}\n strokeDashoffset={ratio === null ? undefined : circumference * (1 - ratio)}\n />\n </svg>\n {percent !== null ? <strong>{percent}%</strong> : <strong className=\"model-download-ring__pending\">…</strong>}\n </div>\n )\n}\n","import type { CSSProperties } from 'react'\nimport { detectBrowserEngine } from '../sdk/camera'\nimport { liveOverlayTransform } from '../live-overlay-geometry'\nimport type { ModelDownloadSnapshot } from '../sdk/model-download'\nimport { ModelDownloadRing } from '../components/ModelDownloadRing'\nimport '../components/scanner-camera-overlay.css'\nimport { useScanner } from './hooks'\nimport type { ScannerFrameProps, ScannerTheme } from './types'\n\nconst themeProperties = {\n primaryColorHex: '--scanner-overlay-primary',\n seekingColorHex: '--scanner-overlay-seeking',\n detectingColorHex: '--scanner-overlay-detecting',\n unstableColorHex: '--scanner-overlay-unstable',\n readyColorHex: '--scanner-overlay-ready',\n capturedColorHex: '--scanner-overlay-captured',\n} as const\n\nfunction themeVars(theme: ScannerTheme | undefined) {\n if (!theme) return undefined\n const vars: Record<string, string> = {}\n for (const [field, property] of Object.entries(themeProperties)) {\n const color = theme[field as keyof ScannerTheme]?.trim()\n if (color) vars[property] = color\n }\n return Object.keys(vars).length > 0 ? vars : undefined\n}\n\nexport function ScannerFrame({ theme, style, title = 'Scan a document', children }: ScannerFrameProps) {\n const scanner = useScanner()\n if (!scanner.open) return null\n const vars = themeVars(theme)\n const frameStyle: CSSProperties | undefined = vars ? { ...style, ...vars } : style\n return (\n <div\n className={`scanner-camera-overlay ${scanner.finderStatus?.state === 'captured' ? 'is-captured' : ''}`.trim()}\n style={frameStyle}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n {children}\n </div>\n )\n}\n\nexport function ScannerPreview() {\n const { bindPreview } = useScanner()\n return (\n <video\n ref={bindPreview}\n className=\"scanner-camera-overlay__video\"\n muted\n autoPlay\n playsInline\n style={{ objectFit: 'cover' }}\n aria-label=\"Rear camera preview\"\n />\n )\n}\n\nexport function ScannerQuad() {\n const { finderStatus, displayQuad, previewSize } = useScanner()\n if (!displayQuad || !finderStatus?.sourceWidth || !finderStatus.sourceHeight) {\n return null\n }\n const overlayTransform = liveOverlayTransform(\n finderStatus.sourceWidth,\n finderStatus.sourceHeight,\n previewSize.width,\n previewSize.height,\n 'cover',\n )\n return (\n <svg\n className={`scanner-camera-overlay__quad ${finderStatus.state}`}\n viewBox={overlayTransform.viewBox}\n preserveAspectRatio={overlayTransform.preserveAspectRatio}\n aria-label={`${finderStatus.state} document boundary`}\n >\n <polygon points={`${displayQuad.topLeft.x},${displayQuad.topLeft.y} ${displayQuad.topRight.x},${displayQuad.topRight.y} ${displayQuad.bottomRight.x},${displayQuad.bottomRight.y} ${displayQuad.bottomLeft.x},${displayQuad.bottomLeft.y}`} />\n </svg>\n )\n}\n\nexport function ScannerTopBar({ title = 'Scan a document' }: { title?: string }) {\n const { phase, guidanceHint, cancel } = useScanner()\n return (\n <div className=\"scanner-camera-overlay__topbar\">\n <div>\n <strong>{title}</strong>\n <span aria-live=\"polite\">\n {phase === 'starting' && 'Starting rear camera…'}\n {phase === 'ready' && (guidanceHint ?? 'Place the document in the frame')}\n {phase === 'capturing' && 'Capturing full resolution…'}\n {phase === 'error' && 'Camera unavailable'}\n </span>\n </div>\n <button type=\"button\" onClick={cancel} aria-label=\"Close camera\">×</button>\n </div>\n )\n}\n\nexport function ScannerNotice() {\n const { phase, error, diagnostics, copyState, retry, copyReport, cancel } = useScanner()\n if (phase === 'error') {\n return (\n <div className=\"scanner-camera-overlay__message\" role=\"alert\">\n <strong>{diagnostics ? 'Capture failed' : 'Could not open the camera'}</strong>\n <p>{error}</p>\n <div>\n <button type=\"button\" onClick={retry}>Try again</button>\n <button type=\"button\" onClick={() => void copyReport()}>\n {copyState === 'copied' ? 'Copied' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n <button type=\"button\" onClick={cancel}>Cancel</button>\n </div>\n </div>\n )\n }\n if (phase === 'starting') {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>Requesting the highest practical resolution</strong>\n <p>Allow camera access to continue.</p>\n </div>\n )\n }\n return null\n}\n\nexport function ScannerStatus() {\n const { finderStatus, detectorStatus, settings } = useScanner()\n const width = settings?.width\n const height = settings?.height\n return (\n <div className=\"scanner-camera-overlay__status\" aria-live=\"polite\">\n <div className=\"scanner-camera-overlay__status-line\">\n <span className={finderStatus?.state ?? 'detecting'} />\n {finderStatus?.state ?? 'detecting'}\n {finderStatus ? ` · ${Math.round(finderStatus.confidence * 100)}% · ${finderStatus.stableFrames}/${finderStatus.requiredStableFrames}` : ''}\n {` · ${detectorStatus}`}\n {finderStatus?.inferenceMs !== undefined ? ` · ${Math.round(finderStatus.inferenceMs)}ms` : ''}\n {width && height ? ` · ${width}×${height}` : ''}\n </div>\n </div>\n )\n}\n\nexport function ScannerDiagnostics() {\n const {\n diagnostics,\n shutterDiagnostics,\n captureMethod,\n copyState,\n copyReport,\n } = useScanner()\n const engine = diagnostics?.engine ?? detectBrowserEngine()\n return (\n <dl className=\"scanner-camera-overlay__diagnostics\" aria-label=\"Camera diagnostics\">\n <div>\n <dt>engine</dt>\n <dd>{engine.engine}/{engine.browser}{engine.iosWebKit ? ' ios' : ''}</dd>\n </div>\n <div>\n <dt>video</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.videoWidth}×${diagnostics.videoHeight} rs${diagnostics.readyState}${diagnostics.paused ? ' paused' : ''}${diagnostics.rendered ? '' : ' hidden'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>track</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.trackReadyState}${diagnostics.trackMuted ? ' muted' : ''}${diagnostics.trackEnabled ? '' : ' disabled'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>torch</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.torch.mode} · ${diagnostics.torch.supported ? (diagnostics.torch.on ? 'on' : 'off') : 'unsupported'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>luma</dt>\n <dd>\n {diagnostics\n ? `live ${diagnostics.liveLuminance.toFixed(1)} · mirror ${diagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(diagnostics.mirrorAgeMs) ? ` (${Math.round(diagnostics.mirrorAgeMs)}ms)` : ' (none)'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>path</dt>\n <dd>{captureMethod ?? 'video-frame / live-mirror'}</dd>\n </div>\n {shutterDiagnostics ? (\n <div>\n <dt>shutter</dt>\n <dd>\n {`live ${shutterDiagnostics.liveLuminance.toFixed(1)} · mirror ${shutterDiagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(shutterDiagnostics.mirrorAgeMs) ? ` (${Math.round(shutterDiagnostics.mirrorAgeMs)}ms)` : ' (none)'}`}\n </dd>\n </div>\n ) : null}\n <div>\n <dt>share</dt>\n <dd>\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__copy\"\n onClick={() => void copyReport()}\n >\n {copyState === 'copied' ? 'Copied report' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n </dd>\n </div>\n </dl>\n )\n}\n\nexport function ScannerControls() {\n const {\n autoCapture,\n phase,\n finderStatus,\n diagnostics,\n captureMethod,\n settings,\n cancel,\n capture,\n setAutoCapture,\n setTorch,\n } = useScanner()\n const width = settings?.width\n const height = settings?.height\n return (\n <div className=\"scanner-camera-overlay__controls\">\n <button type=\"button\" className=\"scanner-camera-overlay__cancel\" onClick={cancel}>Cancel</button>\n <div className=\"scanner-camera-overlay__capture\">\n {autoCapture !== 'only' && (\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__shutter\"\n onClick={() => void capture()}\n disabled={phase !== 'ready'}\n aria-label=\"Capture full-resolution photo\"\n >\n <span />\n </button>\n )}\n <div className=\"scanner-camera-overlay__toggles\">\n {finderStatus?.autoCapture.visible && (\n <label>\n <input\n type=\"checkbox\"\n checked={finderStatus.autoCapture.checked}\n onChange={(event) => setAutoCapture(event.target.checked)}\n />\n Auto-capture\n </label>\n )}\n {diagnostics?.torch.visible && (\n <label title={diagnostics.torch.automatic ? 'Torch is controlled automatically from scene brightness' : undefined}>\n <input\n type=\"checkbox\"\n checked={diagnostics.torch.on}\n disabled={!diagnostics.torch.mutable}\n onChange={(event) => void setTorch(event.target.checked)}\n />\n {diagnostics.torch.automatic ? 'Auto torch' : 'Torch'}\n </label>\n )}\n </div>\n </div>\n <div className=\"scanner-camera-overlay__quality\">\n <span>{captureMethod === 'live-mirror' ? 'Mirror' : 'Camera'}</span>\n <strong>{width && height ? `${width} × ${height}` : 'Measuring…'}</strong>\n </div>\n </div>\n )\n}\n\nexport function ScannerModelDownload({ snapshot }: { snapshot?: ModelDownloadSnapshot }) {\n useScanner()\n if (!snapshot) return null\n return <ModelDownloadRing snapshot={snapshot} />\n}\n"],"mappings":";;;;;AAEA,SAAS,EAAO,GAAoB;CAClC,OAAO;EAAC,EAAK;EAAS,EAAK;EAAU,EAAK;EAAa,EAAK;CAAU;AACxE;AAEA,SAAS,EAAW,GAA6B;CAC/C,IAAM,CAAC,GAAS,GAAU,GAAa,KAAc;CACrD,OAAO;EACL;EACA;EACA;EACA;EACA,OAAO;GACL,KAAK;IAAE,OAAO;IAAS,KAAK;GAAS;GACrC,OAAO;IAAE,OAAO;IAAU,KAAK;GAAY;GAC3C,QAAQ;IAAE,OAAO;IAAa,KAAK;GAAW;GAC9C,MAAM;IAAE,OAAO;IAAY,KAAK;GAAQ;EAC1C;CACF;AACF;AAEA,SAAS,EAAU,GAAoB;CACrC,OAAO,EAAW,EAAO,CAAI,CAAC,CAAC,KAAK,OAAW,EAAE,GAAG,EAAM,EAAE,CAAC;AAC/D;AAWA,IAAa,KAAb,MAAiC;CAC/B;CACA;CACA;CACA;CAEA,YAAY,IAAsC,CAAC,GAAG;EAEpD,AADA,KAAK,WAAW,EAAQ,YAAY,IACpC,KAAK,eAAe,EAAQ,gBAAgB;CAC9C;CAEA,UAAU,GAAoB,GAAoB,GAAqB;EACrE,IAAM,IAAW,KAAK,IAAI,GAAG,KAAK,MAAM,GAAY,CAAW,CAAC,GAC1D,IAAa,CAAC,KAAK,WAAW,EAAO,CAAI,CAAC,CAAC,MAAM,GAAO,MAAU;GACtE,IAAM,IAAW,EAAO,KAAK,OAAQ,CAAC,CAAC;GACvC,OAAO,KAAK,MAAM,EAAM,IAAI,EAAS,GAAG,EAAM,IAAI,EAAS,CAAC,IAAI,IAAW,KAAK;EAClF,CAAC;EAGD,OAFA,KAAK,SAAS,EAAU,CAAI,GACxB,MAAY,KAAK,UAAU,EAAU,CAAI,IACtC;GAAE,MAAM,KAAK;GAAS,SAAS;EAAW;CACnD;CAEA,KAAK,GAAiB;EACpB,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,QAAQ,OAAO,KAAK;EAC/C,IAAM,IAAQ,IAAI,KAAK,IAAI,CAAC,KAAK,WAAW,KAAK,IAAI,GAAG,CAAO,IAAI,GAAI;EAQvE,OAPA,KAAK,UAAU,EAAW,EAAO,KAAK,OAAO,CAAC,CAAC,KAAK,GAAO,MAAU;GACnE,IAAM,IAAS,EAAO,KAAK,MAAO,CAAC,CAAC;GACpC,OAAO;IACL,GAAG,EAAM,KAAK,EAAO,IAAI,EAAM,KAAK;IACpC,GAAG,EAAM,KAAK,EAAO,IAAI,EAAM,KAAK;GACtC;EACF,CAAC,CAAC,GACK,KAAK;CACd;CAEA,QAAQ;EAEN,AADA,KAAK,UAAU,KAAA,GACf,KAAK,SAAS,KAAA;CAChB;CAEA,aAAa;EACX,OAAO,KAAK;CACd;AACF,GCvEa,IAAiB,EAA0C,IAAI;;;ACmB5E,SAAgB,EAAgB,EAC9B,SACA,iBAAc,aACd,WAAQ,cACR,cACA,aACA,YACA,eACA,mBACA,aACA,iBACA,wBACA,WACA,eACuB;CACvB,IAAM,IAAY,EAAkC,KAAA,CAAS,GACvD,IAAY,EAAkC,KAAA,CAAS,GACvD,IAAkB,EAAiC,KAAA,CAAS,GAC5D,IAAiB,EAAgC,KAAA,CAAS,GAC1D,IAAqB,EAIxB,CAAC,CAAC,GACC,IAAqB,EAAO,IAAI,GAAoB,CAAC,GACrD,IAAkB,EAAO,EAAK,GAC9B,IAAe,EAAO;EAAE;EAAW;EAAU;EAAS;EAAY;CAAe,CAAC,GAClF,IAAW,EAAqB,IAAK,GACrC,CAAC,GAAS,MAAc,EAAkC,IAAI,GAC9D,CAAC,IAAO,KAAY,EAAgC,UAAU,GAC9D,CAAC,GAAc,KAAmB,EAAuB,GACzD,CAAC,IAAa,KAAkB,EAAuB,GACvD,CAAC,GAAa,MAAkB,EAAS;EAAE,OAAO;EAAG,QAAQ;CAAE,CAAC,GAChE,CAAC,IAAU,MAAe,EAA6B,GACvD,CAAC,IAAe,KAAoB,EAAgC,GACpE,CAAC,IAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAS,MAAc,EAAS,CAAC,GAClC,CAAC,IAAa,KAAkB,EAA4B,GAC5D,CAAC,IAAoB,KAAyB,EAA4B,GAC1E,CAAC,IAAW,KAAgB,EAAoC,MAAM;CAE5E,QAAgB;EACd,EAAa,UAAU;GAAE;GAAW;GAAU;GAAS;GAAY;EAAe;CACpF,GAAG;EAAC;EAAW;EAAU;EAAS;EAAY;CAAc,CAAC;CAE7D,IAAM,KAAc,GAAa,MAAkC;EACjE,GAAW,CAAI;CACjB,GAAG,CAAC,CAAC;CAyCL,AAvCA,QAAgB;EACd,IAAI,CAAC,KAAQ,CAAC,GAAS;EACvB,IAAM,UAAmB;GACvB,IAAM,IAAS,EAAQ,sBAAsB;GAC7C,GAAe;IAAE,OAAO,EAAO;IAAO,QAAQ,EAAO;GAAO,CAAC;EAC/D;EAEA,IADA,EAAW,GACP,OAAO,iBAAmB,KAE5B,OADA,OAAO,iBAAiB,UAAU,CAAU,SAC/B,OAAO,oBAAoB,UAAU,CAAU;EAE9D,IAAM,IAAW,IAAI,eAAe,CAAU;EAE9C,OADA,EAAS,QAAQ,CAAO,SACX,EAAS,WAAW;CACnC,GAAG,CAAC,GAAM,CAAO,CAAC,GAElB,QAAgB;EACd,IAAI,CAAC,GAAM;EACX,IAAM,IAAO,OAAO,kBAAkB;GACpC,IAAM,IAAU,EAAU,SAAS,eAAe;GAClD,AAAI,KAAS,EAAe,CAAO;EACrC,GAAG,GAAG;EACN,aAAa,OAAO,cAAc,CAAI;CACxC,GAAG,CAAC,GAAM,CAAO,CAAC,GAElB,QAAgB;EACd,IAAI,CAAC,GAAM;EACX,IAAI,IAAiB,GACjB,IAAe,YAAY,IAAI,GAC7B,KAAW,MAAiB;GAChC,IAAM,IAAO,EAAmB,QAAQ,KAAK,IAAO,CAAY;GAGhE,AAFA,IAAe,GACX,KAAM,EAAe,CAAI,GAC7B,IAAiB,sBAAsB,CAAO;EAChD;EAEA,OADA,IAAiB,sBAAsB,CAAO,SACjC,qBAAqB,CAAc;CAClD,GAAG,CAAC,CAAI,CAAC,GAET,QAAgB;EACd,IAAI,CAAC,KAAQ,CAAC,GAAS;EACvB,IAAI,IAAY,IAEV,UAAa;GAOjB,AANA,EAAU,SAAS,KAAK,GACxB,EAAU,UAAU,KAAA,GACpB,EAAU,SAAS,KAAK,GACxB,EAAU,UAAU,KAAA,GACpB,EAAe,UAAU,KAAA,GACzB,EAAgB,UAAU,KAAA,GAC1B,EAAmB,UAAU,CAAC;EAChC;EAqGA,QADA,YAlG0B;GAQxB,AAPA,EAAK,GACL,EAAgB,UAAU,IAC1B,EAAS,UAAU,GACnB,EAAS,EAAE,GACX,EAAgB,KAAA,CAAS,GACzB,EAAiB,KAAA,CAAS,GAC1B,EAAsB,KAAA,CAAS,GAC/B,EAAa,MAAM;GACnB,IAAI;IACF,IAAM,IAAS,MAAM,EAAY,GAAS,EAAE,SAAM,CAAC;IACnD,IAAI,GAAW;KACb,EAAO,KAAK;KACZ;IACF;IACA,EAAU,UAAU;IACpB,IAAM,IAAiB,EAAO,YAAY;IAI1C,AAHA,GAAY,CAAc,GAC1B,EAAa,QAAQ,aAAa,CAAc,GAChD,QAAQ,KAAK,qCAAqC,CAAc,GAChE,EAAU,UAAU,MAAM,EAAY;KACpC,QAAQ;KACR;KACA,YAAY;KACZ,WAAW;MACT;MACA;KACF;KACA,WAAW,MAAW;MAIpB,IAHA,EAAgB,UAAU,GAC1B,EAAgB,CAAM,GACtB,EAAa,QAAQ,iBAAiB,CAAM,GACxC,EAAO,QAAQ,EAAO,eAAe,EAAO,cAAc;OAC5D,IAAM,IAAS,EAAmB,QAAQ,UACxC,EAAO,MACP,EAAO,aACP,EAAO,YACT;OACA,EAAe,EAAO,IAAI;MAC5B,OAEE,AADA,EAAmB,QAAQ,MAAM,GACjC,EAAe,KAAA,CAAS;MAE1B,AAAI,EAAO,UAAU,cAAc,CAAC,EAAgB,WAAS,EAAS,OAAO;KAC/E;KACA,cAAc,YAAY;MAExB,AADA,EAAS,WAAW,GACpB,EAAmB,UAAU;OAC3B,MAAM,EAAmB,QAAQ,WAAW;OAC5C,aAAa,EAAgB,SAAS;OACtC,cAAc,EAAgB,SAAS;MACzC;MACA,IAAM,IAAQ,MAAM,EAAO,aAAa;MAKxC,IAJA,EAAe,UAAU,GACzB,EAAiB,EAAM,MAAM,GAC7B,EAAsB,EAAM,WAAW,GACvC,EAAe,EAAM,WAAW,GAC5B,EAAM,aAAA,IACR,MAAU,MACR,2CAA2C,EAAM,UAAU,QAAQ,CAAC,EAAE,OAAO,EAAM,OAAO,wDAC5F;MAEF,OAAO,EAAM;KACf;KACA,iBAAiB,MAAiB;MAGhC,AAFA,EAAgB,UAAU,IAC1B,EAAS,OAAO,GAChB,EAAS,EAAa,OAAO;MAC7B,IAAM,IAAO,EAAU,SAAS,eAAe;MAE/C,AADI,KAAM,EAAe,CAAI,GAC7B,EAAa,QAAQ,UAAU,CAAY;KAC7C;KACA,WAAW,OAAO,MAAY;MAC5B,IAAM,IAAQ,EAAe;MAE7B,AADA,MAAM,IAAI,SAAS,MAAY,OAAO,WAAW,GAAS,GAAG,CAAC,GAC9D,MAAM,EAAa,QAAQ,UAAU;OACnC,GAAG;OACH,QAAQ,GAAO,UAAU;OACzB,UAAU,GAAO,YAAY,EAAO,YAAY;OAChD,gBAAgB,GAAO;OACvB,WAAW,GAAO;OAClB,aAAa,GAAO;OACpB,eAAe,EAAmB,QAAQ;OAC1C,oBAAoB,EAAmB,QAAQ;OAC/C,qBAAqB,EAAmB,QAAQ;MAClD,CAAC;KACH;IACF,CAAC;GACH,SAAS,GAAO;IACd,IAAI,GAAW;IACf,EAAK;IACL,IAAM,IAAY,aAAiB,QAAQ,IAAQ,gBAAI,MAAM,uBAAuB;IAGpF,AAFA,EAAS,EAAU,OAAO,GAC1B,EAAS,OAAO,GAChB,EAAa,QAAQ,UAAU,CAAS;GAC1C;EACF,EAEK,CAAM,SACE;GAEX,AADA,IAAY,IACZ,EAAK;EACP;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAUD,IAAM,IAAsB;EAC1B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cArBmB,IACjB,EAAiB,EAAa,UAAU,EAAa,QAAQ,IAC7D,KAAA;EAoBF,gBAnBqB,GAAc,gBAAgB,WACjD,cACA,GAAc,aAAa,OACzB,MAAM,EAAa,iBAAiB,KAAK,KAAK,IAC9C;CAgBN;CACA,QAAgB;EACd,EAAS,UAAU;CACrB,CAAC;CAED,IAAM,IAAS,QAAkB;EAC/B,EAAa,QAAQ,SAAS;CAChC,GAAG,CAAC,CAAC,GAEC,IAAU,EAAY,YAAY;EACtC,IAAI;GACF,MAAM,EAAU,SAAS,QAAQ;EACnC,SAAS,GAAO;GACd,IAAM,IAAY,aAAiB,QAAQ,IAAQ,gBAAI,MAAM,qCAAqC;GAElG,AADA,EAAgB,UAAU,IAC1B,EAAS,EAAU,OAAO;GAC1B,IAAM,IAAO,EAAU,SAAS,eAAe;GAI/C,AAHI,KAAM,EAAe,CAAI,GACzB,EAAe,SAAS,eAAa,EAAsB,EAAe,QAAQ,WAAW,GACjG,EAAS,OAAO,GAChB,EAAa,QAAQ,UAAU,CAAS;EAC1C;CACF,GAAG,CAAC,CAAC,GAEC,IAAQ,QAAkB;EAI9B,AAHA,EAAgB,UAAU,IAC1B,EAAS,EAAE,GACX,EAAsB,KAAA,CAAS,GAC/B,EAAa,MAAM;EACnB,IAAM,IAAa,EAAU;EAE7B,AADA,EAAS,IAAa,UAAU,UAAU,GACrC,KAAY,IAAY,MAAU,IAAQ,CAAC;CAClD,GAAG,CAAC,CAAC,GAEC,IAAW,EAAY,OAAO,MAAqB;EACvD,IAAM,IAAS,EAAU;EACpB,MACL,MAAM,EAAO,SAAS,CAAO,GAC7B,EAAe,EAAO,eAAe,CAAC;CACxC,GAAG,CAAC,CAAC,GAEC,IAAiB,GAAa,MAAqB;EACvD,EAAU,SAAS,eAAe,CAAO;CAC3C,GAAG,CAAC,CAAC,GAEC,IAAa,EAAY,YAAY;EACzC,IAAM,IAAU,EAAS,SACnB,IAAO,EAAU,SAAS,eAAe,KAAK,EAAQ,aACtD,IAAS,EAAQ,cACjB,IAAS,EAA+B;GAC5C,OAAO,EAAQ,SAAS,KAAA;GACxB,eAAe,EAAQ;GACvB,WAAW,EAAe,SAAS;GACnC,gBAAgB,EAAe,SAAS;GACxC,SAAS,EAAQ,sBAAsB,EAAe,SAAS;GAC/D;GACA,QAAQ,IACJ;IACA,OAAO,EAAO;IACd,YAAY,EAAO;IACnB,cAAc,EAAO;IACrB,sBAAsB,EAAO;IAC7B,UAAU,EAAO;IACjB,aAAa,EAAO;IACpB,aAAa,EAAO;IACpB,cAAc,EAAO;GACvB,IACE,KAAA;EACN,CAAC;EACD,IAAI;GACF,IAAI,UAAU,WAAW,WACvB,MAAM,UAAU,UAAU,UAAU,CAAM;QACrC;IACL,IAAM,IAAQ,SAAS,cAAc,UAAU;IAM/C,AALA,EAAM,QAAQ,GACd,EAAM,aAAa,YAAY,EAAE,GACjC,EAAM,MAAM,WAAW,SACvB,EAAM,MAAM,OAAO,WACnB,SAAS,KAAK,OAAO,CAAK,GAC1B,EAAM,OAAO;IACb,IAAM,IAAS,SAAS,YAAY,MAAM;IAE1C,IADA,EAAM,OAAO,GACT,CAAC,GAAQ,MAAU,MAAM,gCAAgC;GAC/D;GACA,EAAa,QAAQ;EACvB,QAAQ;GACN,EAAa,QAAQ;EACvB;CACF,GAAG,CAAC,CAAC,GAEC,IAAW,QAAkB,EAAS,SAAS,CAAC,CAAC,GAEjD,IAAM,SAA2B;EACrC;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IAAI;EAAC;EAAS;EAAQ;EAAO;EAAU;EAAgB;EAAY;CAAQ,CAAC;CAE5E,QAAgB;EACT,OAEL,OADA,EAAO,UAAU,SACJ;GACX,EAAO,UAAU;EACnB;CACF,GAAG,CAAC,GAAK,CAAM,CAAC;CAEhB,IAAM,KAA6B;EACjC,GAAG;EACH,GAAG;EACH;CACF;CAEA,OACE,kBAAC,EAAe,UAAhB;EAAgC;EAC7B;CACsB,CAAA;AAE7B;;;AC9XA,SAAgB,IAAgB;CAC9B,OAAO,EAA0B,IAAI;AACvC;AAEA,SAAgB,IAAa;CAC3B,IAAM,IAAQ,EAAW,CAAc;CACvC,IAAI,CAAC,GAAO,MAAU,MAAM,iDAAiD;CAC7E,OAAO;AACT;;;ACAA,SAAgB,EACd,GACA,GACA,GACA,GACA,GACsB;CACtB,IAAM,IAAkB,KAAK,IAAI,GAAG,CAAW,GACzC,IAAmB,KAAK,IAAI,GAAG,CAAY,GAC3C,IAAoB,KAAK,IAAI,GAAG,CAAa,GAC7C,IAAqB,KAAK,IAAI,GAAG,CAAc,GAC/C,IAAa,IAAoB,GACjC,IAAc,IAAqB,GACnC,IAAQ,MAAQ,UAClB,KAAK,IAAI,GAAY,CAAW,IAChC,KAAK,IAAI,GAAY,CAAW,GAC9B,KAAW,IAAoB,IAAkB,KAAS,GAC1D,KAAW,IAAqB,IAAmB,KAAS;CAClE,IAAI,MAAQ,WACV,OAAO;EACL,SAAS,OAAO,EAAgB,GAAG;EACnC,qBAAqB;EACrB;EACA;EACA;CACF;CAEF,IAAM,IAAe,IAAoB,GACnC,IAAgB,IAAqB;CAC3C,OAAO;EACL,SAAS,GAAG,CAAC,IAAU,EAAM,GAAG,CAAC,IAAU,EAAM,GAAG,EAAa,GAAG;EACpE,qBAAqB;EACrB;EACA;EACA;CACF;AACF;;;AC9CA,SAAgB,EAAkB,EAAE,eAAiD;CACnF,IAAI,CAAC,EAAS,aAAa,OAAO;CAClC,IAAM,IAAQ,EAAS,SAAS,EAAS,QAAQ,IAC7C,KAAK,IAAI,GAAG,EAAS,SAAS,EAAS,KAAK,IAC5C,MACE,IAAU,MAAU,OAAO,OAAO,KAAK,MAAM,IAAQ,GAAG,GAExD,IAAgB,IAAI,KAAK,KAAK;CACpC,OACE,kBAAC,OAAD;EACE,WAAW,sBAAsB,MAAU,OAAO,sBAAsB;EACxE,MAAK;EACL,cAAW;EACX,iBAAe;EACf,iBAAe;EACf,iBAAe,KAAW,KAAA;EAC1B,eAAa,EAAS;EACtB,cAAY,EAAS,SAAS;EARhC,UAAA,CAUE,kBAAC,OAAD;GAAK,SAAQ;GAAY,eAAY;GAArC,UAAA,CACE,kBAAC,UAAD;IAAQ,WAAU;IAAQ,IAAG;IAAK,IAAG;IAAK,GAAG;GAAS,CAAA,GACtD,kBAAC,UAAD;IACE,WAAU;IACV,IAAG;IACH,IAAG;IACH,GAAG;IACH,iBAAiB,MAAU,OAAO,KAAA,IAAY,GAAG,EAAc,GAAG;IAClE,kBAAkB,MAAU,OAAO,KAAA,IAAY,KAAiB,IAAI;GACrE,CAAA,CACE;EACJ,CAAA,GAAA,MAAY,OAAqC,kBAAC,UAAD;GAAQ,WAAU;GAA+B,UAAA;EAAS,CAAA,IAAxF,kBAAC,UAAD,EAAA,UAAA,CAAS,GAAQ,GAAS,EAAA,CAAA,CAC3C;;AAET;;;AC1BA,IAAM,IAAkB;CACtB,iBAAiB;CACjB,iBAAiB;CACjB,mBAAmB;CACnB,kBAAkB;CAClB,eAAe;CACf,kBAAkB;AACpB;AAEA,SAAS,EAAU,GAAiC;CAClD,IAAI,CAAC,GAAO;CACZ,IAAM,IAA+B,CAAC;CACtC,KAAK,IAAM,CAAC,GAAO,MAAa,OAAO,QAAQ,CAAe,GAAG;EAC/D,IAAM,IAAQ,EAAM,EAA4B,EAAE,KAAK;EACvD,AAAI,MAAO,EAAK,KAAY;CAC9B;CACA,OAAO,OAAO,KAAK,CAAI,CAAC,CAAC,SAAS,IAAI,IAAO,KAAA;AAC/C;AAEA,SAAgB,EAAa,EAAE,UAAO,UAAO,WAAQ,mBAAmB,eAA+B;CACrG,IAAM,IAAU,EAAW;CAC3B,IAAI,CAAC,EAAQ,MAAM,OAAO;CAC1B,IAAM,IAAO,EAAU,CAAK,GACtB,IAAwC,IAAO;EAAE,GAAG;EAAO,GAAG;CAAK,IAAI;CAC7E,OACE,kBAAC,OAAD;EACE,WAAW,0BAA0B,EAAQ,cAAc,UAAU,aAAa,gBAAgB,KAAK,KAAK;EAC5G,OAAO;EACP,MAAK;EACL,cAAW;EACX,cAAY;EAEX;CACE,CAAA;AAET;AAEA,SAAgB,IAAiB;CAC/B,IAAM,EAAE,mBAAgB,EAAW;CACnC,OACE,kBAAC,SAAD;EACE,KAAK;EACL,WAAU;EACV,OAAA;EACA,UAAA;EACA,aAAA;EACA,OAAO,EAAE,WAAW,QAAQ;EAC5B,cAAW;CACZ,CAAA;AAEL;AAEA,SAAgB,IAAc;CAC5B,IAAM,EAAE,iBAAc,gBAAa,mBAAgB,EAAW;CAC9D,IAAI,CAAC,KAAe,CAAC,GAAc,eAAe,CAAC,EAAa,cAC9D,OAAO;CAET,IAAM,IAAmB,EACvB,EAAa,aACb,EAAa,cACb,EAAY,OACZ,EAAY,QACZ,OACF;CACA,OACE,kBAAC,OAAD;EACE,WAAW,gCAAgC,EAAa;EACxD,SAAS,EAAiB;EAC1B,qBAAqB,EAAiB;EACtC,cAAY,GAAG,EAAa,MAAM;EAElC,UAAA,kBAAC,WAAD,EAAS,QAAQ,GAAG,EAAY,QAAQ,EAAE,GAAG,EAAY,QAAQ,EAAE,GAAG,EAAY,SAAS,EAAE,GAAG,EAAY,SAAS,EAAE,GAAG,EAAY,YAAY,EAAE,GAAG,EAAY,YAAY,EAAE,GAAG,EAAY,WAAW,EAAE,GAAG,EAAY,WAAW,IAAM,CAAA;CAC1O,CAAA;AAET;AAEA,SAAgB,EAAc,EAAE,WAAQ,qBAAyC;CAC/E,IAAM,EAAE,UAAO,iBAAc,cAAW,EAAW;CACnD,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,UAAD,EAAA,UAAS,EAAc,CAAA,GACvB,kBAAC,QAAD;GAAM,aAAU;GAAhB,UAAA;IACG,MAAU,cAAc;IACxB,MAAU,YAAY,KAAgB;IACtC,MAAU,eAAe;IACzB,MAAU,WAAW;GAClB;EACH,CAAA,CAAA,EAAA,CAAA,GACL,kBAAC,UAAD;GAAQ,MAAK;GAAS,SAAS;GAAQ,cAAW;GAAe,UAAA;EAAS,CAAA,CACvE;;AAET;AAEA,SAAgB,IAAgB;CAC9B,IAAM,EAAE,UAAO,UAAO,gBAAa,cAAW,UAAO,eAAY,cAAW,EAAW;CAyBvF,OAxBI,MAAU,UAEV,kBAAC,OAAD;EAAK,WAAU;EAAkC,MAAK;EAAtD,UAAA;GACE,kBAAC,UAAD,EAAA,UAAS,IAAc,mBAAmB,4BAAoC,CAAA;GAC9E,kBAAC,KAAD,EAAA,UAAI,EAAS,CAAA;GACb,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,UAAD;KAAQ,MAAK;KAAS,SAAS;KAAO,UAAA;IAAiB,CAAA;IACvD,kBAAC,UAAD;KAAQ,MAAK;KAAS,eAAe,KAAK,EAAW;KAClD,UAAA,MAAc,WAAW,WAAW,MAAc,WAAW,gBAAgB;IACxE,CAAA;IACR,kBAAC,UAAD;KAAQ,MAAK;KAAS,SAAS;KAAQ,UAAA;IAAc,CAAA;GAClD,EAAA,CAAA;EACF;MAGL,MAAU,aAEV,kBAAC,OAAD;EAAK,WAAU;EAAkC,aAAU;EAA3D,UAAA;GACE,kBAAC,QAAD,EAAM,WAAU,kCAAmC,CAAA;GACnD,kBAAC,UAAD,EAAA,UAAQ,8CAAmD,CAAA;GAC3D,kBAAC,KAAD,EAAA,UAAG,mCAAmC,CAAA;EACnC;MAGF;AACT;AAEA,SAAgB,IAAgB;CAC9B,IAAM,EAAE,iBAAc,mBAAgB,gBAAa,EAAW,GACxD,IAAQ,GAAU,OAClB,IAAS,GAAU;CACzB,OACE,kBAAC,OAAD;EAAK,WAAU;EAAiC,aAAU;EACxD,UAAA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,kBAAC,QAAD,EAAM,WAAW,GAAc,SAAS,YAAc,CAAA;IACrD,GAAc,SAAS;IACvB,IAAe,MAAM,KAAK,MAAM,EAAa,aAAa,GAAG,EAAE,MAAM,EAAa,aAAa,GAAG,EAAa,yBAAyB;IACxI,MAAM;IACN,GAAc,gBAAgB,KAAA,IAA6D,KAAjD,MAAM,KAAK,MAAM,EAAa,WAAW,EAAE;IACrF,KAAS,IAAS,MAAM,EAAM,GAAG,MAAW;GAC1C;;CACF,CAAA;AAET;AAEA,SAAgB,IAAqB;CACnC,IAAM,EACJ,gBACA,uBACA,kBACA,cACA,kBACE,EAAW,GACT,IAAS,GAAa,UAAU,EAAoB;CAC1D,OACE,kBAAC,MAAD;EAAI,WAAU;EAAsC,cAAW;EAA/D,UAAA;GACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,SAAU,CAAA,GACd,kBAAC,MAAD,EAAA,UAAA;IAAK,EAAO;IAAO;IAAE,EAAO;IAAS,EAAO,YAAY,SAAS;GAAO,EAAA,CAAA,CACrE,EAAA,CAAA;GACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,QAAS,CAAA,GACb,kBAAC,MAAD,EAAA,UACG,IACG,GAAG,EAAY,WAAW,GAAG,EAAY,YAAY,KAAK,EAAY,aAAa,EAAY,SAAS,YAAY,KAAK,EAAY,WAAW,KAAK,cACrJ,WACF,CAAA,CACD,EAAA,CAAA;GACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,QAAS,CAAA,GACb,kBAAC,MAAD,EAAA,UACG,IACG,GAAG,EAAY,kBAAkB,EAAY,aAAa,WAAW,KAAK,EAAY,eAAe,KAAK,gBAC1G,IACF,CAAA,CACD,EAAA,CAAA;GACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,QAAS,CAAA,GACb,kBAAC,MAAD,EAAA,UACG,IACG,GAAG,EAAY,MAAM,KAAK,KAAK,EAAY,MAAM,YAAa,EAAY,MAAM,KAAK,OAAO,QAAS,kBACrG,WACF,CAAA,CACD,EAAA,CAAA;GACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,OAAQ,CAAA,GACZ,kBAAC,MAAD,EAAA,UACG,IACG,QAAQ,EAAY,cAAc,QAAQ,CAAC,EAAE,YAAY,EAAY,gBAAgB,QAAQ,CAAC,IAAI,OAAO,SAAS,EAAY,WAAW,IAAI,KAAK,KAAK,MAAM,EAAY,WAAW,EAAE,OAAO,cAC7L,IACF,CAAA,CACD,EAAA,CAAA;GACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,OAAQ,CAAA,GACZ,kBAAC,MAAD,EAAA,UAAK,KAAiB,4BAAgC,CAAA,CACnD,EAAA,CAAA;GACJ,IACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,UAAW,CAAA,GACf,kBAAC,MAAD,EAAA,UACG,QAAQ,EAAmB,cAAc,QAAQ,CAAC,EAAE,YAAY,EAAmB,gBAAgB,QAAQ,CAAC,IAAI,OAAO,SAAS,EAAmB,WAAW,IAAI,KAAK,KAAK,MAAM,EAAmB,WAAW,EAAE,OAAO,YACxN,CAAA,CACD,EAAA,CAAA,IACH;GACJ,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD,EAAA,UAAI,QAAS,CAAA,GACb,kBAAC,MAAD,EAAA,UACE,kBAAC,UAAD;IACE,MAAK;IACL,WAAU;IACV,eAAe,KAAK,EAAW;IAE9B,UAAA,MAAc,WAAW,kBAAkB,MAAc,WAAW,gBAAgB;GAC/E,CAAA,EACN,CAAA,CACD,EAAA,CAAA;EACH;;AAER;AAEA,SAAgB,IAAkB;CAChC,IAAM,EACJ,gBACA,UACA,iBACA,gBACA,kBACA,aACA,WACA,YACA,mBACA,gBACE,EAAW,GACT,IAAQ,GAAU,OAClB,IAAS,GAAU;CACzB,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,kBAAC,UAAD;IAAQ,MAAK;IAAS,WAAU;IAAiC,SAAS;IAAQ,UAAA;GAAc,CAAA;GAChG,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,MAAgB,UACf,kBAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,eAAe,KAAK,EAAQ;KAC5B,UAAU,MAAU;KACpB,cAAW;KAEX,UAAA,kBAAC,QAAD,CAAO,CAAA;IACD,CAAA,GAEV,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,GAAc,YAAY,WACzB,kBAAC,SAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MACE,MAAK;MACL,SAAS,EAAa,YAAY;MAClC,WAAW,MAAU,EAAe,EAAM,OAAO,OAAO;KACzD,CAAA,GAAC,cAEG,EAAA,CAAA,GAER,GAAa,MAAM,WAClB,kBAAC,SAAD;MAAO,OAAO,EAAY,MAAM,YAAY,4DAA4D,KAAA;MAAxG,UAAA,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAY,MAAM;OAC3B,UAAU,CAAC,EAAY,MAAM;OAC7B,WAAW,MAAU,KAAK,EAAS,EAAM,OAAO,OAAO;MACxD,CAAA,GACA,EAAY,MAAM,YAAY,eAAe,OACzC;KAEN,CAAA,CAAA;IACF,CAAA,CAAA;;GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD,EAAA,UAAO,MAAkB,gBAAgB,WAAW,SAAe,CAAA,GACnE,kBAAC,UAAD,EAAA,UAAS,KAAS,IAAS,GAAG,EAAM,KAAK,MAAW,aAAqB,CAAA,CACtE;;EACF;;AAET;AAEA,SAAgB,EAAqB,EAAE,eAAkD;CAGvF,OAFA,EAAW,GACN,IACE,kBAAC,GAAD,EAA6B,YAAW,CAAA,IADzB;AAExB"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/sdk/display-quad.ts","../src/react/scanner-context.ts","../src/react/context.tsx","../src/react/hooks.ts","../src/live-overlay-geometry.ts","../src/components/ModelDownloadRing.tsx","../src/react/parts.tsx"],"sourcesContent":["import type { DocumentQuad, Point } from './types'\n\nfunction points(quad: DocumentQuad) {\n return [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft]\n}\n\nfunction withPoints(next: Point[]): DocumentQuad {\n const [topLeft, topRight, bottomRight, bottomLeft] = next\n return {\n topLeft,\n topRight,\n bottomRight,\n bottomLeft,\n edges: {\n top: { start: topLeft, end: topRight },\n right: { start: topRight, end: bottomRight },\n bottom: { start: bottomRight, end: bottomLeft },\n left: { start: bottomLeft, end: topLeft },\n },\n }\n}\n\nfunction cloneQuad(quad: DocumentQuad) {\n return withPoints(points(quad).map((point) => ({ ...point })))\n}\n\nexport interface QuadDisplaySmootherOptions {\n response?: number\n snapDistance?: number\n}\n\n/**\n * Smooths only the displayed quad. Detector stability must continue to use raw\n * detections and must never consume this animated output.\n */\nexport class QuadDisplaySmoother {\n private current?: DocumentQuad\n private target?: DocumentQuad\n private readonly response: number\n private readonly snapDistance: number\n\n constructor(options: QuadDisplaySmootherOptions = {}) {\n this.response = options.response ?? 14\n this.snapDistance = options.snapDistance ?? 0.1\n }\n\n setTarget(quad: DocumentQuad, frameWidth: number, frameHeight: number) {\n const diagonal = Math.max(1, Math.hypot(frameWidth, frameHeight))\n const shouldSnap = !this.current || points(quad).some((point, index) => {\n const previous = points(this.current!)[index]\n return Math.hypot(point.x - previous.x, point.y - previous.y) / diagonal > this.snapDistance\n })\n this.target = cloneQuad(quad)\n if (shouldSnap) this.current = cloneQuad(quad)\n return { quad: this.current, snapped: shouldSnap }\n }\n\n step(deltaMs: number) {\n if (!this.current || !this.target) return this.current\n const alpha = 1 - Math.exp(-this.response * Math.max(0, deltaMs) / 1000)\n this.current = withPoints(points(this.current).map((point, index) => {\n const target = points(this.target!)[index]\n return {\n x: point.x + (target.x - point.x) * alpha,\n y: point.y + (target.y - point.y) * alpha,\n }\n }))\n return this.current\n }\n\n clear() {\n this.current = undefined\n this.target = undefined\n }\n\n getCurrent() {\n return this.current\n }\n}\n","import { createContext } from 'react'\nimport type { ScannerApi, ScannerState } from './types'\n\nexport interface ScannerContextValue extends ScannerState, ScannerApi {\n bindPreview: (node: HTMLVideoElement | null) => void\n}\n\nexport const ScannerContext = createContext<ScannerContextValue | null>(null)\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport {\n formatCaptureDiagnosticsReport,\n NEAR_BLACK_LUMINANCE,\n startCamera,\n type CameraDiagnostics,\n type CameraPhoto,\n type CameraSession,\n} from '../sdk/camera'\nimport {\n selectFinderHint,\n startFinder,\n type FinderSession,\n type FinderStatus,\n} from '../sdk/finder'\nimport { QuadDisplaySmoother } from '../sdk/display-quad'\nimport type { DocumentQuad } from '../sdk/types'\nimport type { ScannerApi, ScannerProviderProps, ScannerState } from './types'\nimport { ScannerContext, type ScannerContextValue } from './scanner-context'\n\nfunction revokePreviewUrl(url: string | undefined) {\n if (url?.startsWith('blob:')) URL.revokeObjectURL(url)\n}\n\nfunction stillUrlFromCanvas(canvas: HTMLCanvasElement): string | undefined {\n try {\n const url = canvas.toDataURL('image/jpeg', 0.92)\n return url.startsWith('data:image/') ? url : undefined\n } catch {\n return undefined\n }\n}\n\nexport function ScannerProvider({\n open,\n autoCapture = 'defaultOn',\n torch = 'defaultOff',\n onCapture,\n onCancel,\n onError,\n onSettings,\n onFinderStatus,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n apiRef,\n children,\n}: ScannerProviderProps) {\n const cameraRef = useRef<CameraSession | undefined>(undefined)\n const finderRef = useRef<FinderSession | undefined>(undefined)\n const finderStatusRef = useRef<FinderStatus | undefined>(undefined)\n const latestPhotoRef = useRef<CameraPhoto | undefined>(undefined)\n const capturedDisplayRef = useRef<{\n quad?: DocumentQuad\n sourceWidth?: number\n sourceHeight?: number\n }>({})\n const displaySmootherRef = useRef(new QuadDisplaySmoother())\n const captureErrorRef = useRef(false)\n const callbacksRef = useRef({ onCapture, onCancel, onError, onSettings, onFinderStatus })\n const stateRef = useRef<ScannerState>(null!)\n const [preview, setPreview] = useState<HTMLVideoElement | null>(null)\n const [phase, setPhase] = useState<ScannerState['phase']>('starting')\n const [finderStatus, setFinderStatus] = useState<FinderStatus>()\n const [displayQuad, setDisplayQuad] = useState<DocumentQuad>()\n const [previewSize, setPreviewSize] = useState({ width: 1, height: 1 })\n const [settings, setSettings] = useState<MediaTrackSettings>()\n const [captureMethod, setCaptureMethod] = useState<CameraPhoto['method']>()\n const [error, setError] = useState('')\n const [attempt, setAttempt] = useState(0)\n const [diagnostics, setDiagnostics] = useState<CameraDiagnostics>()\n const [shutterDiagnostics, setShutterDiagnostics] = useState<CameraDiagnostics>()\n const [copyState, setCopyState] = useState<ScannerState['copyState']>('idle')\n const [frozenPreviewUrl, setFrozenPreviewUrl] = useState<string>()\n const frozenPreviewUrlRef = useRef<string | undefined>(undefined)\n\n const clearFrozenPreview = useCallback(() => {\n revokePreviewUrl(frozenPreviewUrlRef.current)\n frozenPreviewUrlRef.current = undefined\n setFrozenPreviewUrl(undefined)\n }, [])\n\n const freezePreview = useCallback((frame: HTMLCanvasElement, video?: HTMLVideoElement | null) => {\n const still = stillUrlFromCanvas(frame)\n revokePreviewUrl(frozenPreviewUrlRef.current)\n frozenPreviewUrlRef.current = still\n setFrozenPreviewUrl(still)\n video?.pause()\n }, [])\n\n useEffect(() => {\n callbacksRef.current = { onCapture, onCancel, onError, onSettings, onFinderStatus }\n }, [onCapture, onCancel, onError, onSettings, onFinderStatus])\n\n const bindPreview = useCallback((node: HTMLVideoElement | null) => {\n setPreview(node)\n }, [])\n\n useEffect(() => {\n if (!open || !preview) return\n const updateSize = () => {\n const bounds = preview.getBoundingClientRect()\n setPreviewSize({ width: bounds.width, height: bounds.height })\n }\n updateSize()\n if (typeof ResizeObserver === 'undefined') {\n window.addEventListener('resize', updateSize)\n return () => window.removeEventListener('resize', updateSize)\n }\n const observer = new ResizeObserver(updateSize)\n observer.observe(preview)\n return () => observer.disconnect()\n }, [open, preview])\n\n useEffect(() => {\n if (!open) return\n const poll = window.setInterval(() => {\n const current = cameraRef.current?.getDiagnostics()\n if (current) setDiagnostics(current)\n }, 500)\n return () => window.clearInterval(poll)\n }, [open, attempt])\n\n useEffect(() => {\n if (!open) return\n let animationFrame = 0\n let previousTime = performance.now()\n const animate = (time: number) => {\n const next = displaySmootherRef.current.step(time - previousTime)\n previousTime = time\n if (next) setDisplayQuad(next)\n animationFrame = requestAnimationFrame(animate)\n }\n animationFrame = requestAnimationFrame(animate)\n return () => cancelAnimationFrame(animationFrame)\n }, [open])\n\n useEffect(() => {\n if (!open || !preview) return\n let cancelled = false\n\n const stop = () => {\n finderRef.current?.stop()\n finderRef.current = undefined\n cameraRef.current?.stop()\n cameraRef.current = undefined\n latestPhotoRef.current = undefined\n finderStatusRef.current = undefined\n capturedDisplayRef.current = {}\n clearFrozenPreview()\n }\n\n const start = async () => {\n stop()\n captureErrorRef.current = false\n setPhase('starting')\n setError('')\n setFinderStatus(undefined)\n setCaptureMethod(undefined)\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n clearFrozenPreview()\n try {\n const camera = await startCamera(preview, { torch })\n if (cancelled) {\n camera.stop()\n return\n }\n cameraRef.current = camera\n const actualSettings = camera.getSettings()\n setSettings(actualSettings)\n callbacksRef.current.onSettings?.(actualSettings)\n console.info('[ScannerProvider] camera settings', actualSettings)\n finderRef.current = await startFinder({\n source: preview,\n autoCapture,\n intervalMs: detectionIntervalMs,\n detection: {\n modelUrl,\n ortWasmPaths,\n },\n onStatus: (status) => {\n finderStatusRef.current = status\n setFinderStatus(status)\n callbacksRef.current.onFinderStatus?.(status)\n if (status.quad && status.sourceWidth && status.sourceHeight) {\n const update = displaySmootherRef.current.setTarget(\n status.quad,\n status.sourceWidth,\n status.sourceHeight,\n )\n setDisplayQuad(update.quad)\n } else {\n displaySmootherRef.current.clear()\n setDisplayQuad(undefined)\n }\n if (status.state !== 'captured' && !captureErrorRef.current) setPhase('ready')\n },\n captureFrame: async () => {\n setPhase('capturing')\n capturedDisplayRef.current = {\n quad: displaySmootherRef.current.getCurrent(),\n sourceWidth: finderStatusRef.current?.sourceWidth,\n sourceHeight: finderStatusRef.current?.sourceHeight,\n }\n const photo = await camera.capturePhoto()\n latestPhotoRef.current = photo\n setCaptureMethod(photo.method)\n setShutterDiagnostics(photo.diagnostics)\n setDiagnostics(photo.diagnostics)\n if (photo.luminance <= NEAR_BLACK_LUMINANCE) {\n throw new Error(\n `The captured frame was blank (luminance ${photo.luminance.toFixed(1)} via ${photo.method}). Keep the scanner visible while capturing and retake.`,\n )\n }\n freezePreview(photo.frame, preview)\n setPhase('captured')\n return photo.frame\n },\n onCaptureError: (captureError) => {\n captureErrorRef.current = true\n setPhase('error')\n setError(captureError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n callbacksRef.current.onError?.(captureError)\n },\n onCapture: async (capture) => {\n const photo = latestPhotoRef.current\n await new Promise((resolve) => window.setTimeout(resolve, 140))\n await callbacksRef.current.onCapture({\n ...capture,\n method: photo?.method ?? 'video-frame',\n settings: photo?.settings ?? camera.getSettings(),\n fallbackReason: photo?.fallbackReason,\n luminance: photo?.luminance,\n diagnostics: photo?.diagnostics,\n displayedQuad: capturedDisplayRef.current.quad,\n displaySourceWidth: capturedDisplayRef.current.sourceWidth,\n displaySourceHeight: capturedDisplayRef.current.sourceHeight,\n })\n },\n })\n } catch (cause) {\n if (cancelled) return\n stop()\n const nextError = cause instanceof Error ? cause : new Error('Camera access failed.')\n setError(nextError.message)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }\n\n void start()\n return () => {\n cancelled = true\n stop()\n }\n }, [\n open,\n preview,\n autoCapture,\n torch,\n modelUrl,\n ortWasmPaths,\n detectionIntervalMs,\n attempt,\n clearFrozenPreview,\n freezePreview,\n ])\n\n const guidanceHint = finderStatus\n ? selectFinderHint(finderStatus.guidance, finderStatus.lighting)\n : undefined\n const detectorStatus = finderStatus?.modelStatus === 'failed'\n ? 'ML failed'\n : finderStatus?.detector === 'ml'\n ? `ML ${finderStatus.modelProvider ?? ''}`.trim()\n : 'ML loading'\n const state: ScannerState = {\n open,\n phase,\n autoCapture,\n finderStatus,\n displayQuad,\n previewSize,\n settings,\n captureMethod,\n error,\n diagnostics,\n shutterDiagnostics,\n copyState,\n guidanceHint,\n detectorStatus,\n frozenPreviewUrl,\n }\n useEffect(() => {\n stateRef.current = state\n })\n\n const cancel = useCallback(() => {\n callbacksRef.current.onCancel()\n }, [])\n\n const capture = useCallback(async () => {\n try {\n await finderRef.current?.capture()\n } catch (cause) {\n const nextError = cause instanceof Error ? cause : new Error('Could not capture the camera frame.')\n captureErrorRef.current = true\n setError(nextError.message)\n const live = cameraRef.current?.getDiagnostics()\n if (live) setDiagnostics(live)\n if (latestPhotoRef.current?.diagnostics) setShutterDiagnostics(latestPhotoRef.current.diagnostics)\n setPhase('error')\n callbacksRef.current.onError?.(nextError)\n }\n }, [])\n\n const retry = useCallback(() => {\n captureErrorRef.current = false\n setError('')\n setShutterDiagnostics(undefined)\n setCopyState('idle')\n clearFrozenPreview()\n const liveCamera = cameraRef.current\n if (preview?.paused) void preview.play()\n setPhase(liveCamera ? 'ready' : 'starting')\n if (!liveCamera) setAttempt((value) => value + 1)\n }, [clearFrozenPreview, preview])\n\n const setTorch = useCallback(async (enabled: boolean) => {\n const camera = cameraRef.current\n if (!camera) return\n await camera.setTorch(enabled)\n setDiagnostics(camera.getDiagnostics())\n }, [])\n\n const setAutoCapture = useCallback((enabled: boolean) => {\n finderRef.current?.setAutoCapture(enabled)\n }, [])\n\n const copyReport = useCallback(async () => {\n const current = stateRef.current\n const live = cameraRef.current?.getDiagnostics() ?? current.diagnostics\n const finder = current.finderStatus\n const report = formatCaptureDiagnosticsReport({\n error: current.error || undefined,\n captureMethod: current.captureMethod,\n luminance: latestPhotoRef.current?.luminance,\n fallbackReason: latestPhotoRef.current?.fallbackReason,\n shutter: current.shutterDiagnostics ?? latestPhotoRef.current?.diagnostics,\n live,\n finder: finder\n ? {\n state: finder.state,\n confidence: finder.confidence,\n stableFrames: finder.stableFrames,\n requiredStableFrames: finder.requiredStableFrames,\n detector: finder.detector,\n modelStatus: finder.modelStatus,\n sourceWidth: finder.sourceWidth,\n sourceHeight: finder.sourceHeight,\n }\n : undefined,\n })\n try {\n if (navigator.clipboard?.writeText) {\n await navigator.clipboard.writeText(report)\n } else {\n const field = document.createElement('textarea')\n field.value = report\n field.setAttribute('readonly', '')\n field.style.position = 'fixed'\n field.style.left = '-9999px'\n document.body.append(field)\n field.select()\n const copied = document.execCommand('copy')\n field.remove()\n if (!copied) throw new Error('Clipboard copy is unavailable.')\n }\n setCopyState('copied')\n } catch {\n setCopyState('failed')\n }\n }, [])\n\n const getState = useCallback(() => stateRef.current, [])\n\n const api = useMemo<ScannerApi>(() => ({\n capture,\n cancel,\n retry,\n setTorch,\n setAutoCapture,\n copyReport,\n getState,\n }), [capture, cancel, retry, setTorch, setAutoCapture, copyReport, getState])\n\n useEffect(() => {\n if (!apiRef) return\n apiRef.current = api\n return () => {\n apiRef.current = null\n }\n }, [api, apiRef])\n\n const value: ScannerContextValue = {\n ...state,\n ...api,\n bindPreview,\n }\n\n return (\n <ScannerContext.Provider value={value}>\n {children}\n </ScannerContext.Provider>\n )\n}\n","import { useContext, useRef } from 'react'\nimport type { ScannerApi } from './types'\nimport { ScannerContext } from './scanner-context'\n\nexport function useScannerRef() {\n return useRef<ScannerApi | null>(null)\n}\n\nexport function useScanner() {\n const value = useContext(ScannerContext)\n if (!value) throw new Error('useScanner must be used within ScannerProvider.')\n return value\n}\n","import type { Point } from './sdk/types'\n\nexport type LivePreviewFit = 'contain' | 'cover'\n\nexport interface LiveOverlayTransform {\n viewBox: string\n preserveAspectRatio: 'none' | 'xMidYMid meet'\n scale: number\n offsetX: number\n offsetY: number\n}\n\nexport function liveOverlayTransform(\n sourceWidth: number,\n sourceHeight: number,\n renderedWidth: number,\n renderedHeight: number,\n fit: LivePreviewFit,\n): LiveOverlayTransform {\n const safeSourceWidth = Math.max(1, sourceWidth)\n const safeSourceHeight = Math.max(1, sourceHeight)\n const safeRenderedWidth = Math.max(1, renderedWidth)\n const safeRenderedHeight = Math.max(1, renderedHeight)\n const widthScale = safeRenderedWidth / safeSourceWidth\n const heightScale = safeRenderedHeight / safeSourceHeight\n const scale = fit === 'cover'\n ? Math.max(widthScale, heightScale)\n : Math.min(widthScale, heightScale)\n const offsetX = (safeRenderedWidth - safeSourceWidth * scale) / 2\n const offsetY = (safeRenderedHeight - safeSourceHeight * scale) / 2\n if (fit === 'contain') {\n return {\n viewBox: `0 0 ${safeSourceWidth} ${safeSourceHeight}`,\n preserveAspectRatio: 'xMidYMid meet',\n scale,\n offsetX,\n offsetY,\n }\n }\n const visibleWidth = safeRenderedWidth / scale\n const visibleHeight = safeRenderedHeight / scale\n return {\n viewBox: `${-offsetX / scale} ${-offsetY / scale} ${visibleWidth} ${visibleHeight}`,\n preserveAspectRatio: 'none',\n scale,\n offsetX,\n offsetY,\n }\n}\n\nexport function mapLiveSourcePoint(point: Point, transform: LiveOverlayTransform): Point {\n return {\n x: transform.offsetX + point.x * transform.scale,\n y: transform.offsetY + point.y * transform.scale,\n }\n}\n","import type { ModelDownloadSnapshot } from '../sdk/model-download'\n\nexport function ModelDownloadRing({ snapshot }: { snapshot: ModelDownloadSnapshot }) {\n if (!snapshot.downloading) return null\n const ratio = snapshot.total && snapshot.total > 0\n ? Math.min(1, snapshot.loaded / snapshot.total)\n : null\n const percent = ratio === null ? null : Math.round(ratio * 100)\n const radius = 28\n const circumference = 2 * Math.PI * radius\n return (\n <div\n className={`model-download-ring${ratio === null ? ' is-indeterminate' : ''}`}\n role=\"progressbar\"\n aria-label=\"Model download\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent ?? undefined}\n data-loaded={snapshot.loaded}\n data-total={snapshot.total ?? ''}\n >\n <svg viewBox=\"0 0 72 72\" aria-hidden=\"true\">\n <circle className=\"track\" cx=\"36\" cy=\"36\" r={radius} />\n <circle\n className=\"value\"\n cx=\"36\"\n cy=\"36\"\n r={radius}\n strokeDasharray={ratio === null ? undefined : `${circumference} ${circumference}`}\n strokeDashoffset={ratio === null ? undefined : circumference * (1 - ratio)}\n />\n </svg>\n {percent !== null ? <strong>{percent}%</strong> : <strong className=\"model-download-ring__pending\">…</strong>}\n </div>\n )\n}\n","import { useCallback, useEffect, useRef, type CSSProperties } from 'react'\nimport { detectBrowserEngine } from '../sdk/camera'\nimport { liveOverlayTransform } from '../live-overlay-geometry'\nimport type { ModelDownloadSnapshot } from '../sdk/model-download'\nimport { ModelDownloadRing } from '../components/ModelDownloadRing'\nimport '../components/scanner-camera-overlay.css'\nimport { useScanner } from './hooks'\nimport type { ScannerFrameProps, ScannerTheme } from './types'\n\nconst themeProperties = {\n primaryColorHex: '--scanner-overlay-primary',\n seekingColorHex: '--scanner-overlay-seeking',\n detectingColorHex: '--scanner-overlay-detecting',\n unstableColorHex: '--scanner-overlay-unstable',\n readyColorHex: '--scanner-overlay-ready',\n capturedColorHex: '--scanner-overlay-captured',\n} as const\n\nfunction themeVars(theme: ScannerTheme | undefined) {\n if (!theme) return undefined\n const vars: Record<string, string> = {}\n for (const [field, property] of Object.entries(themeProperties)) {\n const color = theme[field as keyof ScannerTheme]?.trim()\n if (color) vars[property] = color\n }\n return Object.keys(vars).length > 0 ? vars : undefined\n}\n\nexport function ScannerFrame({ theme, style, title = 'Scan a document', children }: ScannerFrameProps) {\n const scanner = useScanner()\n if (!scanner.open) return null\n const vars = themeVars(theme)\n const frameStyle: CSSProperties | undefined = vars ? { ...style, ...vars } : style\n return (\n <div\n className={`scanner-camera-overlay ${scanner.finderStatus?.state === 'captured' ? 'is-captured' : ''}`.trim()}\n style={frameStyle}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n {children}\n </div>\n )\n}\n\nexport function ScannerPreview() {\n const { bindPreview, frozenPreviewUrl } = useScanner()\n const videoRef = useRef<HTMLVideoElement | null>(null)\n const setPreviewNode = useCallback((node: HTMLVideoElement | null) => {\n videoRef.current = node\n bindPreview(node)\n }, [bindPreview])\n\n useEffect(() => {\n if (frozenPreviewUrl) videoRef.current?.pause()\n }, [frozenPreviewUrl])\n\n return (\n <>\n <video\n ref={setPreviewNode}\n className=\"scanner-camera-overlay__video\"\n muted\n autoPlay\n playsInline\n style={{ objectFit: 'cover' }}\n aria-hidden={Boolean(frozenPreviewUrl)}\n aria-label=\"Rear camera preview\"\n />\n {frozenPreviewUrl ? (\n <img\n src={frozenPreviewUrl}\n className=\"scanner-camera-overlay__video scanner-camera-overlay__still\"\n alt=\"\"\n aria-label=\"Captured document\"\n />\n ) : null}\n </>\n )\n}\n\nexport function ScannerQuad() {\n const { finderStatus, displayQuad, previewSize } = useScanner()\n if (!displayQuad || !finderStatus?.sourceWidth || !finderStatus.sourceHeight) {\n return null\n }\n const overlayTransform = liveOverlayTransform(\n finderStatus.sourceWidth,\n finderStatus.sourceHeight,\n previewSize.width,\n previewSize.height,\n 'cover',\n )\n return (\n <svg\n className={`scanner-camera-overlay__quad ${finderStatus.state}`}\n viewBox={overlayTransform.viewBox}\n preserveAspectRatio={overlayTransform.preserveAspectRatio}\n aria-label={`${finderStatus.state} document boundary`}\n >\n <polygon points={`${displayQuad.topLeft.x},${displayQuad.topLeft.y} ${displayQuad.topRight.x},${displayQuad.topRight.y} ${displayQuad.bottomRight.x},${displayQuad.bottomRight.y} ${displayQuad.bottomLeft.x},${displayQuad.bottomLeft.y}`} />\n </svg>\n )\n}\n\nexport function ScannerTopBar({ title = 'Scan a document' }: { title?: string }) {\n const { phase, guidanceHint, cancel } = useScanner()\n return (\n <div className=\"scanner-camera-overlay__topbar\">\n <div>\n <strong>{title}</strong>\n <span aria-live=\"polite\">\n {phase === 'starting' && 'Starting rear camera…'}\n {phase === 'ready' && (guidanceHint ?? 'Place the document in the frame')}\n {phase === 'capturing' && 'Capturing full resolution…'}\n {phase === 'captured' && 'Document captured'}\n {phase === 'error' && 'Camera unavailable'}\n </span>\n </div>\n <button type=\"button\" onClick={cancel} aria-label=\"Close camera\">×</button>\n </div>\n )\n}\n\nexport function ScannerNotice() {\n const { phase, error, diagnostics, copyState, retry, copyReport, cancel } = useScanner()\n if (phase === 'error') {\n return (\n <div className=\"scanner-camera-overlay__message\" role=\"alert\">\n <strong>{diagnostics ? 'Capture failed' : 'Could not open the camera'}</strong>\n <p>{error}</p>\n <div>\n <button type=\"button\" onClick={retry}>Try again</button>\n <button type=\"button\" onClick={() => void copyReport()}>\n {copyState === 'copied' ? 'Copied' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n <button type=\"button\" onClick={cancel}>Cancel</button>\n </div>\n </div>\n )\n }\n if (phase === 'starting') {\n return (\n <div className=\"scanner-camera-overlay__message\" aria-live=\"polite\">\n <span className=\"scanner-camera-overlay__spinner\" />\n <strong>Requesting the highest practical resolution</strong>\n <p>Allow camera access to continue.</p>\n </div>\n )\n }\n return null\n}\n\nexport function ScannerStatus() {\n const { finderStatus, detectorStatus, settings } = useScanner()\n const width = settings?.width\n const height = settings?.height\n return (\n <div className=\"scanner-camera-overlay__status\" aria-live=\"polite\">\n <div className=\"scanner-camera-overlay__status-line\">\n <span className={finderStatus?.state ?? 'detecting'} />\n {finderStatus?.state ?? 'detecting'}\n {finderStatus ? ` · ${Math.round(finderStatus.confidence * 100)}% · ${finderStatus.stableFrames}/${finderStatus.requiredStableFrames}` : ''}\n {` · ${detectorStatus}`}\n {finderStatus?.inferenceMs !== undefined ? ` · ${Math.round(finderStatus.inferenceMs)}ms` : ''}\n {width && height ? ` · ${width}×${height}` : ''}\n </div>\n </div>\n )\n}\n\nexport function ScannerDiagnostics() {\n const {\n diagnostics,\n shutterDiagnostics,\n captureMethod,\n copyState,\n copyReport,\n } = useScanner()\n const engine = diagnostics?.engine ?? detectBrowserEngine()\n return (\n <dl className=\"scanner-camera-overlay__diagnostics\" aria-label=\"Camera diagnostics\">\n <div>\n <dt>engine</dt>\n <dd>{engine.engine}/{engine.browser}{engine.iosWebKit ? ' ios' : ''}</dd>\n </div>\n <div>\n <dt>video</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.videoWidth}×${diagnostics.videoHeight} rs${diagnostics.readyState}${diagnostics.paused ? ' paused' : ''}${diagnostics.rendered ? '' : ' hidden'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>track</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.trackReadyState}${diagnostics.trackMuted ? ' muted' : ''}${diagnostics.trackEnabled ? '' : ' disabled'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>torch</dt>\n <dd>\n {diagnostics\n ? `${diagnostics.torch.mode} · ${diagnostics.torch.supported ? (diagnostics.torch.on ? 'on' : 'off') : 'unsupported'}`\n : 'starting'}\n </dd>\n </div>\n <div>\n <dt>luma</dt>\n <dd>\n {diagnostics\n ? `live ${diagnostics.liveLuminance.toFixed(1)} · mirror ${diagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(diagnostics.mirrorAgeMs) ? ` (${Math.round(diagnostics.mirrorAgeMs)}ms)` : ' (none)'}`\n : '—'}\n </dd>\n </div>\n <div>\n <dt>path</dt>\n <dd>{captureMethod ?? 'video-frame / live-mirror'}</dd>\n </div>\n {shutterDiagnostics ? (\n <div>\n <dt>shutter</dt>\n <dd>\n {`live ${shutterDiagnostics.liveLuminance.toFixed(1)} · mirror ${shutterDiagnostics.mirrorLuminance.toFixed(1)}${Number.isFinite(shutterDiagnostics.mirrorAgeMs) ? ` (${Math.round(shutterDiagnostics.mirrorAgeMs)}ms)` : ' (none)'}`}\n </dd>\n </div>\n ) : null}\n <div>\n <dt>share</dt>\n <dd>\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__copy\"\n onClick={() => void copyReport()}\n >\n {copyState === 'copied' ? 'Copied report' : copyState === 'failed' ? 'Copy failed' : 'Copy report'}\n </button>\n </dd>\n </div>\n </dl>\n )\n}\n\nexport function ScannerControls() {\n const {\n autoCapture,\n phase,\n finderStatus,\n diagnostics,\n captureMethod,\n settings,\n cancel,\n capture,\n setAutoCapture,\n setTorch,\n } = useScanner()\n const width = settings?.width\n const height = settings?.height\n return (\n <div className=\"scanner-camera-overlay__controls\">\n <button type=\"button\" className=\"scanner-camera-overlay__cancel\" onClick={cancel}>Cancel</button>\n <div className=\"scanner-camera-overlay__capture\">\n {autoCapture !== 'only' && (\n <button\n type=\"button\"\n className=\"scanner-camera-overlay__shutter\"\n onClick={() => void capture()}\n disabled={phase !== 'ready'}\n aria-label=\"Capture full-resolution photo\"\n >\n <span />\n </button>\n )}\n <div className=\"scanner-camera-overlay__toggles\">\n {finderStatus?.autoCapture.visible && (\n <label>\n <input\n type=\"checkbox\"\n checked={finderStatus.autoCapture.checked}\n onChange={(event) => setAutoCapture(event.target.checked)}\n />\n Auto-capture\n </label>\n )}\n {diagnostics?.torch.visible && (\n <label title={diagnostics.torch.automatic ? 'Torch is controlled automatically from scene brightness' : undefined}>\n <input\n type=\"checkbox\"\n checked={diagnostics.torch.on}\n disabled={!diagnostics.torch.mutable}\n onChange={(event) => void setTorch(event.target.checked)}\n />\n {diagnostics.torch.automatic ? 'Auto torch' : 'Torch'}\n </label>\n )}\n </div>\n </div>\n <div className=\"scanner-camera-overlay__quality\">\n <span>{captureMethod === 'live-mirror' ? 'Mirror' : 'Camera'}</span>\n <strong>{width && height ? `${width} × ${height}` : 'Measuring…'}</strong>\n </div>\n </div>\n )\n}\n\nexport function ScannerModelDownload({ snapshot }: { snapshot?: ModelDownloadSnapshot }) {\n useScanner()\n if (!snapshot) return null\n return <ModelDownloadRing snapshot={snapshot} />\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exige/web-scanner-sdk",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "@exige/web-scanner-sdk is a client-side web document scanner SDK. ML document finding, OCR, and redaction run in the browser. The public demo is the only path that does not need an account. A hostname you control needs a signed license key.",
5
5
  "type": "module",
6
6
  "license": "MIT",