@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.
- package/dist/components/scanner-camera-overlay.css +1 -1
- package/dist/react/types.d.ts +12 -1
- package/dist/react.js +186 -156
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
|
@@ -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*/
|
package/dist/react/types.d.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
|
42
|
-
return h(
|
|
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 ||
|
|
54
|
-
let n =
|
|
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 =
|
|
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(
|
|
66
|
-
let r =
|
|
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
|
-
},
|
|
79
|
+
}, te = a(null);
|
|
80
80
|
//#endregion
|
|
81
81
|
//#region src/react/context.tsx
|
|
82
|
-
function v(
|
|
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:
|
|
95
|
+
onCapture: f,
|
|
85
96
|
onCancel: m,
|
|
86
97
|
onError: h,
|
|
87
98
|
onSettings: g,
|
|
88
|
-
onFinderStatus:
|
|
89
|
-
}), M = u(null), [N,
|
|
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
|
-
}), [
|
|
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:
|
|
111
|
+
onCapture: f,
|
|
96
112
|
onCancel: m,
|
|
97
113
|
onError: h,
|
|
98
114
|
onSettings: g,
|
|
99
|
-
onFinderStatus:
|
|
115
|
+
onFinderStatus: _
|
|
100
116
|
};
|
|
101
117
|
}, [
|
|
102
|
-
|
|
118
|
+
f,
|
|
103
119
|
m,
|
|
104
120
|
h,
|
|
105
121
|
g,
|
|
106
|
-
|
|
122
|
+
_
|
|
107
123
|
]);
|
|
108
|
-
let
|
|
109
|
-
|
|
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
|
-
|
|
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 &&
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
164
|
-
} else k.current.clear(),
|
|
165
|
-
e.state !== "captured" && !A.current &&
|
|
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
|
-
|
|
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,
|
|
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),
|
|
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
|
|
234
|
+
let Y = {
|
|
217
235
|
open: n,
|
|
218
|
-
phase:
|
|
236
|
+
phase: re,
|
|
219
237
|
autoCapture: a,
|
|
220
|
-
finderStatus:
|
|
221
|
-
displayQuad:
|
|
222
|
-
previewSize:
|
|
223
|
-
settings:
|
|
224
|
-
captureMethod:
|
|
225
|
-
error:
|
|
226
|
-
diagnostics:
|
|
227
|
-
shutterDiagnostics:
|
|
228
|
-
copyState:
|
|
229
|
-
guidanceHint:
|
|
230
|
-
detectorStatus:
|
|
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 =
|
|
252
|
+
M.current = Y;
|
|
234
253
|
});
|
|
235
|
-
let
|
|
254
|
+
let X = o(() => {
|
|
236
255
|
j.current.onCancel();
|
|
237
|
-
}, []),
|
|
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),
|
|
263
|
+
n && H(n), D.current?.diagnostics && U(D.current.diagnostics), F("error"), j.current.onError?.(t);
|
|
245
264
|
}
|
|
246
|
-
}, []),
|
|
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
|
-
|
|
250
|
-
}, []),
|
|
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
|
-
}, []),
|
|
272
|
+
}, []), ve = o((e) => {
|
|
254
273
|
T.current?.setAutoCapture(e);
|
|
255
|
-
}, []),
|
|
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
|
-
}, []),
|
|
287
|
-
capture:
|
|
288
|
-
cancel:
|
|
289
|
-
retry:
|
|
290
|
-
setTorch:
|
|
291
|
-
setAutoCapture:
|
|
292
|
-
copyReport:
|
|
293
|
-
getState:
|
|
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
|
-
|
|
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
|
|
309
|
-
...
|
|
327
|
+
let xe = {
|
|
328
|
+
...Y,
|
|
310
329
|
...$,
|
|
311
|
-
bindPreview:
|
|
330
|
+
bindPreview: ge
|
|
312
331
|
};
|
|
313
|
-
return /* @__PURE__ */
|
|
314
|
-
value:
|
|
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
|
|
339
|
+
function b() {
|
|
321
340
|
return u(null);
|
|
322
341
|
}
|
|
323
|
-
function
|
|
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
|
|
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
|
|
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__ */
|
|
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__ */
|
|
381
|
+
children: [/* @__PURE__ */ m("svg", {
|
|
363
382
|
viewBox: "0 0 72 72",
|
|
364
383
|
"aria-hidden": "true",
|
|
365
|
-
children: [/* @__PURE__ */
|
|
384
|
+
children: [/* @__PURE__ */ p("circle", {
|
|
366
385
|
className: "track",
|
|
367
386
|
cx: "36",
|
|
368
387
|
cy: "36",
|
|
369
388
|
r: 28
|
|
370
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
397
|
+
}), n === null ? /* @__PURE__ */ p("strong", {
|
|
379
398
|
className: "model-download-ring__pending",
|
|
380
399
|
children: "…"
|
|
381
|
-
}) : /* @__PURE__ */
|
|
400
|
+
}) : /* @__PURE__ */ m("strong", { children: [n, "%"] })]
|
|
382
401
|
});
|
|
383
402
|
}
|
|
384
403
|
//#endregion
|
|
385
404
|
//#region src/react/parts.tsx
|
|
386
|
-
var
|
|
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
|
|
413
|
+
function T(e) {
|
|
395
414
|
if (!e) return;
|
|
396
415
|
let t = {};
|
|
397
|
-
for (let [n, r] of Object.entries(
|
|
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
|
|
404
|
-
let i =
|
|
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 =
|
|
425
|
+
let a = T(e), o = a ? {
|
|
407
426
|
...t,
|
|
408
427
|
...a
|
|
409
428
|
} : t;
|
|
410
|
-
return /* @__PURE__ */
|
|
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
|
|
420
|
-
let { bindPreview: e } =
|
|
421
|
-
|
|
422
|
-
|
|
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
|
|
432
|
-
let { finderStatus: e, displayQuad: t, previewSize: n } =
|
|
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 =
|
|
435
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
444
|
-
let { phase: t, guidanceHint: n, cancel: r } =
|
|
445
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
464
|
-
let { phase: e, error: t, diagnostics: n, copyState: r, retry: i, copyReport: a, cancel: o } =
|
|
465
|
-
return e === "error" ? /* @__PURE__ */
|
|
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__ */
|
|
470
|
-
/* @__PURE__ */
|
|
471
|
-
/* @__PURE__ */
|
|
472
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
519
|
+
}) : e === "starting" ? /* @__PURE__ */ m("div", {
|
|
490
520
|
className: "scanner-camera-overlay__message",
|
|
491
521
|
"aria-live": "polite",
|
|
492
522
|
children: [
|
|
493
|
-
/* @__PURE__ */
|
|
494
|
-
/* @__PURE__ */
|
|
495
|
-
/* @__PURE__ */
|
|
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
|
|
500
|
-
let { finderStatus: e, detectorStatus: t, settings: n } =
|
|
501
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
534
|
+
children: /* @__PURE__ */ m("div", {
|
|
505
535
|
className: "scanner-camera-overlay__status-line",
|
|
506
536
|
children: [
|
|
507
|
-
/* @__PURE__ */
|
|
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
|
|
518
|
-
let { diagnostics: e, shutterDiagnostics: t, captureMethod: r, copyState: i, copyReport: a } =
|
|
519
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
530
|
-
/* @__PURE__ */
|
|
531
|
-
/* @__PURE__ */
|
|
532
|
-
/* @__PURE__ */
|
|
533
|
-
/* @__PURE__ */
|
|
534
|
-
t ? /* @__PURE__ */
|
|
535
|
-
/* @__PURE__ */
|
|
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
|
|
545
|
-
let { autoCapture: e, phase: t, finderStatus: n, diagnostics: r, captureMethod: i, settings: a, cancel: o, capture: s, setAutoCapture: c, setTorch: l } =
|
|
546
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
585
|
+
/* @__PURE__ */ m("div", {
|
|
556
586
|
className: "scanner-camera-overlay__capture",
|
|
557
|
-
children: [e !== "only" && /* @__PURE__ */
|
|
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__ */
|
|
564
|
-
}), /* @__PURE__ */
|
|
593
|
+
children: /* @__PURE__ */ p("span", {})
|
|
594
|
+
}), /* @__PURE__ */ m("div", {
|
|
565
595
|
className: "scanner-camera-overlay__toggles",
|
|
566
|
-
children: [n?.autoCapture.visible && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
611
|
+
/* @__PURE__ */ m("div", {
|
|
582
612
|
className: "scanner-camera-overlay__quality",
|
|
583
|
-
children: [/* @__PURE__ */
|
|
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
|
|
589
|
-
return
|
|
618
|
+
function P({ snapshot: e }) {
|
|
619
|
+
return x(), e ? /* @__PURE__ */ p(C, { snapshot: e }) : null;
|
|
590
620
|
}
|
|
591
621
|
//#endregion
|
|
592
|
-
export {
|
|
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":"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"}
|
|
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.
|
|
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",
|