@asteby/storefront-react 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/fiscal.js CHANGED
@@ -1,11 +1,12 @@
1
- import { validateFiscalValues, regimesFor, usesFor, normalizeTaxId, entryLabel, summarizeExtraction, toInvoiceRequest, maskTaxId } from './chunk-Q7UTJIKY.js';
2
- export { entryLabel, maskTaxId, normalizeTaxId, personTypeByLength, postalCodeProblem, regimesFor, summarizeExtraction, taxIdProblem, toInvoiceRequest, usesFor, validateFiscalValues } from './chunk-Q7UTJIKY.js';
3
- import { fiscalMessages, fill } from './chunk-PPQEUTXJ.js';
4
- export { fiscalMessages } from './chunk-PPQEUTXJ.js';
1
+ import { personTypeResolver, validateFiscalValues, regimesFor, usesFor, normalizeTaxId, entryLabel, suggestInvoiceUse, summarizeExtraction, toInvoiceRequest, maskTaxId } from './chunk-D5L7UZIA.js';
2
+ export { entryLabel, maskTaxId, normalizeTaxId, personTypeByLength, personTypeFromPatterns, personTypeResolver, postalCodeProblem, regimesFor, suggestInvoiceUse, summarizeExtraction, taxIdProblem, toInvoiceRequest, usesFor, validateFiscalValues } from './chunk-D5L7UZIA.js';
3
+ import { useModalDialog } from './chunk-ZBH7JYU4.js';
4
+ import { fiscalMessages, fill } from './chunk-VE7WQPMY.js';
5
+ export { fiscalMessages } from './chunk-VE7WQPMY.js';
5
6
  import { CheckoutField, ErrorSummary } from './chunk-DFGLCIEG.js';
6
7
  import { useResolvedLocale } from './chunk-T52H5HL3.js';
7
8
  import './chunk-DQBL2DFJ.js';
8
- import { useId, useState, useRef, useEffect, useMemo, useCallback } from 'react';
9
+ import { useId, useState, useMemo, useRef, useEffect, useCallback } from 'react';
9
10
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
11
 
11
12
  var FIELDS = ["tax_id", "legal_name", "postal_code", "tax_regime", "use"];
@@ -35,7 +36,8 @@ function FiscalIdentityFields({
35
36
  errors = {},
36
37
  namePrefix = "invoice",
37
38
  idPrefix,
38
- personTypeOf,
39
+ personTypeOf: personTypeOverride,
40
+ suggestedUse,
39
41
  disabled,
40
42
  locale: localeProp,
41
43
  messages,
@@ -50,6 +52,8 @@ function FiscalIdentityFields({
50
52
  const base = idPrefix ?? `sf-fiscal-${reactId.replace(/:/g, "")}`;
51
53
  const [v, setV] = useState({ ...EMPTY, ...values });
52
54
  const [shown, setShown] = useState(/* @__PURE__ */ new Set());
55
+ const [autoUse, setAutoUse] = useState(null);
56
+ const personTypeOf = useMemo(() => personTypeResolver(region.fiscal_id, personTypeOverride), [region.fiscal_id, personTypeOverride]);
53
57
  const root = useRef(null);
54
58
  const valuesKey = JSON.stringify(values ?? null);
55
59
  const first = useRef(true);
@@ -64,10 +68,17 @@ function FiscalIdentityFields({
64
68
  const set = (patch) => {
65
69
  const next = { ...v, ...patch };
66
70
  if (patch.tax_regime !== void 0 && next.use && !usesFor(fid, next.tax_regime).some((u) => u.code === next.use)) next.use = "";
71
+ if (patch.tax_regime !== void 0 && !next.use) {
72
+ const suggestion = suggestInvoiceUse(fid, next.tax_regime);
73
+ if (suggestion) {
74
+ next.use = suggestion;
75
+ setAutoUse(suggestion);
76
+ } else setAutoUse(null);
77
+ } else if (patch.use !== void 0) setAutoUse(null);
67
78
  setV(next);
68
79
  onChange?.(next);
69
80
  };
70
- const person = personTypeOf?.(v.tax_id) ?? null;
81
+ const person = personTypeOf(v.tax_id);
71
82
  const taxIdOk = !validateFiscalValues(region, { tax_id: v.tax_id }, personTypeOf).tax_id;
72
83
  const problems = useMemo(() => validateFiscalValues(region, v, personTypeOf), [region, v, personTypeOf]);
73
84
  const candidates = regimeCandidates?.length ? regimeCandidates : null;
@@ -235,7 +246,12 @@ function FiscalIdentityFields({
235
246
  name: name("use"),
236
247
  id: `${base}-use`,
237
248
  label: m.use,
238
- hint: m.useHint,
249
+ hint: v.use && (v.use === autoUse || v.use === suggestedUse) ? /* @__PURE__ */ jsxs(Fragment, { children: [
250
+ /* @__PURE__ */ jsx("span", { className: cx.mark, "data-sf-suggested": true, children: m.suggested }),
251
+ " ",
252
+ "\xB7 ",
253
+ m.useHint
254
+ ] }) : m.useHint,
239
255
  value: v.use,
240
256
  onChange: (e) => set({ use: e.target.value }),
241
257
  onBlur: () => touch("use"),
@@ -254,10 +270,93 @@ function FiscalIdentityFields({
254
270
  )
255
271
  ] });
256
272
  }
273
+ function cameraSupported() {
274
+ return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function";
275
+ }
276
+ function useCameraQr({ active, onCode, intervalMs = 250 }) {
277
+ const videoRef = useRef(null);
278
+ const [status, setStatus] = useState("idle");
279
+ const streamRef = useRef(null);
280
+ const onCodeRef = useRef(onCode);
281
+ onCodeRef.current = onCode;
282
+ const stop = useCallback(() => {
283
+ for (const track of streamRef.current?.getTracks() ?? []) track.stop();
284
+ streamRef.current = null;
285
+ const v = videoRef.current;
286
+ if (v) v.srcObject = null;
287
+ setStatus((s) => s === "denied" || s === "unsupported" ? s : "idle");
288
+ }, []);
289
+ useEffect(() => {
290
+ if (!active) return;
291
+ if (!cameraSupported()) {
292
+ setStatus("unsupported");
293
+ return;
294
+ }
295
+ let cancelled = false;
296
+ let timer;
297
+ let busy = false;
298
+ setStatus("starting");
299
+ const onHidden = () => {
300
+ if (document.visibilityState === "hidden") stop();
301
+ };
302
+ document.addEventListener("visibilitychange", onHidden);
303
+ (async () => {
304
+ let stream;
305
+ try {
306
+ stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: { ideal: "environment" } }, audio: false });
307
+ } catch {
308
+ if (!cancelled) setStatus("denied");
309
+ return;
310
+ }
311
+ if (cancelled) {
312
+ for (const t of stream.getTracks()) t.stop();
313
+ return;
314
+ }
315
+ streamRef.current = stream;
316
+ const video = videoRef.current;
317
+ if (!video) {
318
+ for (const t of stream.getTracks()) t.stop();
319
+ streamRef.current = null;
320
+ return;
321
+ }
322
+ video.srcObject = stream;
323
+ video.muted = true;
324
+ void video.play?.().catch(() => void 0);
325
+ setStatus("scanning");
326
+ const eng = await import('@asteby/storefront/fiscal-document');
327
+ timer = setInterval(async () => {
328
+ if (busy || cancelled || !videoRef.current || videoRef.current.readyState < 2) return;
329
+ busy = true;
330
+ try {
331
+ const text = await eng.decodeImageQr(videoRef.current);
332
+ if (text && !cancelled) {
333
+ cancelled = true;
334
+ clearInterval(timer);
335
+ stop();
336
+ onCodeRef.current(text);
337
+ }
338
+ } catch {
339
+ } finally {
340
+ busy = false;
341
+ }
342
+ }, intervalMs);
343
+ })();
344
+ return () => {
345
+ cancelled = true;
346
+ if (timer) clearInterval(timer);
347
+ document.removeEventListener("visibilitychange", onHidden);
348
+ for (const t of streamRef.current?.getTracks() ?? []) t.stop();
349
+ streamRef.current = null;
350
+ if (videoRef.current) videoRef.current.srcObject = null;
351
+ };
352
+ }, [active, intervalMs, stop]);
353
+ return { videoRef, status, stop };
354
+ }
257
355
  var isPdf = (f, accept) => {
258
356
  const okType = f.type ? accept.some((a) => a === f.type) || f.type === "application/pdf" : false;
259
357
  return okType || /\.pdf$/i.test(f.name);
260
358
  };
359
+ var isImage = (f) => f.type.startsWith("image/") || /\.(jpe?g|png|webp|heic|heif)$/i.test(f.name);
261
360
  var mib = (bytes) => `${Math.round(bytes / (1024 * 1024) * 10) / 10} MB`;
262
361
  function IdentityDocumentReader(props) {
263
362
  const { region, workerSrc, onConfirm, onManual, initialValues, data, canSave, serverUpload, personTypeOf, now, namePrefix = "invoice", messages, classNames: cx = {}, confirmLabel } = props;
@@ -289,14 +388,29 @@ function IdentityDocumentReader(props) {
289
388
  useEffect(() => () => abort.current?.abort(), []);
290
389
  useEffect(() => {
291
390
  if (!fromServer) return;
292
- setValues((cur) => ({ ...cur, ...fromServer.values }));
391
+ setValues((cur) => {
392
+ const next = { ...cur, ...fromServer.values };
393
+ const suggestion = next.tax_regime && !next.use ? suggestInvoiceUse(region.fiscal_id, next.tax_regime) : null;
394
+ if (suggestion) {
395
+ next.use = suggestion;
396
+ setSuggestedUse(suggestion);
397
+ }
398
+ return next;
399
+ });
293
400
  setPhase({ kind: "review", extraction: fromServer, revision: 1 });
294
401
  }, [fromServer]);
295
402
  useEffect(() => {
296
403
  if (phase.kind === "error") errorRef.current?.focus();
297
404
  if (phase.kind === "review" && phase.revision > 0) reviewRef.current?.focus();
298
405
  }, [phase]);
299
- const accept = useMemo(() => spec?.accept?.length ? spec.accept.join(",") : "application/pdf", [spec]);
406
+ const accept = useMemo(() => {
407
+ const files = (spec?.accept ?? []).filter((a) => !a.startsWith("image/"));
408
+ return files.length ? files.join(",") : "application/pdf";
409
+ }, [spec]);
410
+ const imageMode = spec?.image_mode && spec.image_mode !== "none" ? spec.image_mode : null;
411
+ const photoInput = useRef(null);
412
+ const [suggestedUse, setSuggestedUse] = useState(null);
413
+ const cameraActive = phase.kind === "camera";
300
414
  const fieldErrors = useMemo(() => {
301
415
  const out = {};
302
416
  for (const [k, v] of Object.entries(data?.fieldErrors ?? {})) out[k] = all.server.errors[v] ?? v;
@@ -313,9 +427,70 @@ function IdentityDocumentReader(props) {
313
427
  setPhase({ kind: "review", extraction: null, revision: 1 });
314
428
  setLive("");
315
429
  }, [onManual]);
430
+ const showExtraction = useCallback(
431
+ (sum) => {
432
+ const base = { tax_id: "", legal_name: "", postal_code: "", tax_regime: "", use: "", ...sum.values };
433
+ const suggestion = base.tax_regime ? suggestInvoiceUse(region.fiscal_id, base.tax_regime) : null;
434
+ if (suggestion && !base.use) base.use = suggestion;
435
+ setSuggestedUse(suggestion && base.use === suggestion ? suggestion : null);
436
+ setValues(base);
437
+ setSummary(null);
438
+ setPhase({ kind: "review", extraction: sum, revision: 1 });
439
+ setLive(m.done);
440
+ },
441
+ [region.fiscal_id, m.done]
442
+ );
443
+ const readQr = useCallback(
444
+ async (text) => {
445
+ if (!spec) return;
446
+ if (!text) return setPhase({ kind: "error", code: "no_qr" });
447
+ const eng = await import('@asteby/storefront/fiscal-document');
448
+ const x = eng.extractIdentityDocument("", spec, {
449
+ catalogs: region.fiscal_id ? eng.catalogsFromRegion(region.fiscal_id) : {},
450
+ qr: text,
451
+ ...now ? { now: now() } : {}
452
+ });
453
+ if (!x.fields.tax_id) return setPhase({ kind: "error", code: "no_qr" });
454
+ const evidence = eng.buildDocumentEvidence(x, { sha256: null, source: "qr" });
455
+ showExtraction(summarizeExtraction(x, evidence, region.fiscal_id?.regimes.map((r) => r.code)));
456
+ },
457
+ [spec, region, now, showExtraction]
458
+ );
459
+ const readImage = useCallback(
460
+ async (file) => {
461
+ if (!spec) return;
462
+ if (file.size > spec.max_bytes) return setPhase({ kind: "error", code: "too_large", sizeLimit: spec.max_bytes });
463
+ const ctl = new AbortController();
464
+ abort.current = ctl;
465
+ setPhase({ kind: "reading", fileName: file.name });
466
+ setLive(fill(m.reading, { document: documentName }));
467
+ try {
468
+ const eng = await import('@asteby/storefront/fiscal-document');
469
+ const text = await eng.decodeImageQr(file, { maxBytes: spec.max_bytes, signal: ctl.signal });
470
+ if (ctl.signal.aborted) return;
471
+ await readQr(text);
472
+ } catch (err) {
473
+ if (ctl.signal.aborted) return;
474
+ const code = err?.code;
475
+ setLive("");
476
+ setPhase({ kind: "error", code: code === "too_large" ? "too_large" : code === "not_image" ? "not_image" : "unreadable", sizeLimit: spec.max_bytes });
477
+ } finally {
478
+ if (abort.current === ctl) abort.current = null;
479
+ if (photoInput.current) photoInput.current.value = "";
480
+ }
481
+ },
482
+ [spec, documentName, m.reading, readQr]
483
+ );
484
+ const camera = useCameraQr({
485
+ active: cameraActive,
486
+ onCode: (text) => {
487
+ void readQr(text).then(() => setLive(`${m.scan.cameraRead}. ${m.done}`)).catch(() => setPhase({ kind: "error", code: "unreadable" }));
488
+ }
489
+ });
316
490
  const read = useCallback(
317
491
  async (file) => {
318
492
  if (!spec) return;
493
+ if (imageMode && isImage(file)) return readImage(file);
319
494
  if (!isPdf(file, spec.accept ?? [])) return setPhase({ kind: "error", code: "not_pdf" });
320
495
  if (file.size > spec.max_bytes) return setPhase({ kind: "error", code: "too_large", sizeLimit: spec.max_bytes });
321
496
  const ctl = new AbortController();
@@ -340,10 +515,7 @@ function IdentityDocumentReader(props) {
340
515
  });
341
516
  const evidence = eng.buildDocumentEvidence(x, { sha256, source: "pdf_client" });
342
517
  const sum = summarizeExtraction(x, evidence, region.fiscal_id?.regimes.map((r) => r.code));
343
- setValues({ tax_id: "", legal_name: "", postal_code: "", tax_regime: "", use: "", ...sum.values });
344
- setSummary(null);
345
- setPhase({ kind: "review", extraction: sum, revision: 1 });
346
- setLive(m.done);
518
+ showExtraction(sum);
347
519
  } catch (err) {
348
520
  if (ctl.signal.aborted) return;
349
521
  const code = err?.code;
@@ -358,7 +530,7 @@ function IdentityDocumentReader(props) {
358
530
  if (fileInput.current) fileInput.current.value = "";
359
531
  }
360
532
  },
361
- [spec, workerSrc, region, now, documentName, m.reading, m.done]
533
+ [spec, workerSrc, region, now, documentName, m.reading, imageMode, readImage, showExtraction]
362
534
  );
363
535
  if (!spec) return null;
364
536
  const onDrop = (e) => {
@@ -368,7 +540,7 @@ function IdentityDocumentReader(props) {
368
540
  if (f) void read(f);
369
541
  };
370
542
  const confirm = () => {
371
- const problems = validateFiscalValues(region, values, personTypeOf);
543
+ const problems = validateFiscalValues(region, values, personTypeResolver(region.fiscal_id, personTypeOf));
372
544
  const keys = Object.keys(problems);
373
545
  if (keys.length) {
374
546
  const labels = {
@@ -433,6 +605,27 @@ function IdentityDocumentReader(props) {
433
605
  ]
434
606
  }
435
607
  ),
608
+ imageMode ? /* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-reader-scan": true, children: [
609
+ /* @__PURE__ */ jsx(
610
+ "input",
611
+ {
612
+ ref: photoInput,
613
+ type: "file",
614
+ accept: "image/*",
615
+ capture: "environment",
616
+ hidden: true,
617
+ tabIndex: -1,
618
+ "aria-label": m.scan.photo,
619
+ "data-sf-reader-photo-input": true,
620
+ onChange: (e) => {
621
+ const f = e.target.files?.[0];
622
+ if (f) void readImage(f);
623
+ }
624
+ }
625
+ ),
626
+ /* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: () => photoInput.current?.click(), "data-sf-reader-photo": true, children: m.scan.photo }),
627
+ hydrated && cameraSupported() ? /* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: () => setPhase({ kind: "camera" }), "data-sf-reader-camera": true, children: m.scan.camera }) : null
628
+ ] }) : null,
436
629
  /* @__PURE__ */ jsx("p", { id: helpId, className: cx.privacy, "data-sf-reader-privacy": true, children: privacy }),
437
630
  serverUpload ? /* @__PURE__ */ jsx("noscript", { children: /* @__PURE__ */ jsx("button", { type: "submit", name: "intent", value: "extract-document", formEncType: "multipart/form-data", formMethod: "post", formNoValidate: true, className: cx.secondary, "data-sf-reader-upload": true, children: m.uploadServer }) }) : null,
438
631
  /* @__PURE__ */ jsxs("p", { "data-sf-reader-links": true, children: [
@@ -449,6 +642,48 @@ function IdentityDocumentReader(props) {
449
642
  ] }),
450
643
  /* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: cancel, "data-sf-reader-cancel": true, children: m.cancel })
451
644
  ] });
645
+ const cameraView = phase.kind === "camera" && /* @__PURE__ */ jsxs("div", { className: cx.root, "data-sf-reader": true, "data-state": "camera", children: [
646
+ /* @__PURE__ */ jsx("h3", { "data-sf-reader-title": true, children: m.scan.cameraTitle }),
647
+ /* @__PURE__ */ jsxs("div", { "data-sf-reader-viewfinder": true, children: [
648
+ /* @__PURE__ */ jsx("video", { ref: camera.videoRef, playsInline: true, muted: true, "aria-label": m.scan.cameraGuide, "data-sf-reader-video": true }),
649
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", "data-sf-reader-frame": true })
650
+ ] }),
651
+ /* @__PURE__ */ jsx("p", { className: cx.status, "data-sf-reader-camera-status": camera.status, children: camera.status === "denied" ? m.scan.cameraDenied : camera.status === "unsupported" ? m.scan.cameraUnavailable : camera.status === "starting" ? m.scan.cameraStarting : m.scan.cameraGuide }),
652
+ /* @__PURE__ */ jsx("p", { className: cx.privacy, "data-sf-reader-privacy": true, children: privacy }),
653
+ /* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-reader-actions": true, children: [
654
+ /* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: () => photoInput.current?.click(), "data-sf-reader-photo": true, children: m.scan.choosePhoto }),
655
+ /* @__PURE__ */ jsx(
656
+ "button",
657
+ {
658
+ type: "button",
659
+ className: cx.primary,
660
+ onClick: () => {
661
+ camera.stop();
662
+ setPhase({ kind: "idle" });
663
+ },
664
+ "data-sf-reader-camera-close": true,
665
+ children: m.scan.closeCamera
666
+ }
667
+ )
668
+ ] }),
669
+ /* @__PURE__ */ jsx(
670
+ "input",
671
+ {
672
+ ref: photoInput,
673
+ type: "file",
674
+ accept: "image/*",
675
+ capture: "environment",
676
+ hidden: true,
677
+ tabIndex: -1,
678
+ "aria-label": m.scan.choosePhoto,
679
+ "data-sf-reader-photo-input": true,
680
+ onChange: (e) => {
681
+ const f = e.target.files?.[0];
682
+ if (f) void readImage(f);
683
+ }
684
+ }
685
+ )
686
+ ] });
452
687
  const errored = phase.kind === "error" && /* @__PURE__ */ jsxs("div", { className: cx.root, "data-sf-reader": true, "data-state": "error", children: [
453
688
  /* @__PURE__ */ jsx("div", { ref: errorRef, role: "alert", tabIndex: -1, className: cx.error, "data-sf-reader-error": phase.code, children: fill(m.errors[phase.code], { size: mib(phase.sizeLimit ?? spec.max_bytes) }) }),
454
689
  /* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-reader-actions": true, children: [
@@ -481,6 +716,7 @@ function IdentityDocumentReader(props) {
481
716
  fromDocument: phase.extraction?.from_document ?? [],
482
717
  documentName,
483
718
  regimeCandidates: phase.extraction && phase.extraction.regime_candidates.length > 1 ? phase.extraction.regime_candidates : void 0,
719
+ suggestedUse,
484
720
  ...personTypeOf ? { personTypeOf } : {},
485
721
  locale,
486
722
  ...messages ? { messages } : {},
@@ -508,6 +744,7 @@ function IdentityDocumentReader(props) {
508
744
  /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", className: cx.status, "data-sf-reader-live": true, style: visuallyHidden, children: live }),
509
745
  phase.kind === "idle" ? idle : null,
510
746
  reading || null,
747
+ cameraView || null,
511
748
  errored || null,
512
749
  review || null
513
750
  ] });
@@ -517,7 +754,8 @@ function Warnings({ x, m, cx }) {
517
754
  const items = [];
518
755
  if (x.qr_match === false) items.push(m.warnings.qrMismatch);
519
756
  if (x.stale === true && x.age_days !== null) items.push(fill(m.warnings.stale, { days: x.age_days }));
520
- if (x.regime_candidates.length === 0 && !x.values.tax_regime) items.push(m.warnings.regimeMissing);
757
+ if (x.evidence.source === "qr") items.push(m.warnings.qrPartial);
758
+ else if (x.regime_candidates.length === 0 && !x.values.tax_regime) items.push(m.warnings.regimeMissing);
521
759
  else if (x.missing.some((k) => k !== "tax_regime" && k !== "document_id" && k !== "issued_on")) items.push(m.warnings.fieldsMissing);
522
760
  if (!items.length) return null;
523
761
  return /* @__PURE__ */ jsx("ul", { className: cx.warning, "data-sf-reader-warnings": true, children: items.map((t) => /* @__PURE__ */ jsxs("li", { "data-sf-reader-warning": true, children: [
@@ -525,6 +763,46 @@ function Warnings({ x, m, cx }) {
525
763
  t
526
764
  ] }, t)) });
527
765
  }
766
+ function ScanTaxDocument(props) {
767
+ const { onConfirm, onManual, classNames: cx = {}, messages, confirmLabel, ...reader } = props;
768
+ const locale = useResolvedLocale(props.locale);
769
+ const m = fiscalMessages(locale, messages).reader;
770
+ const spec = props.document ?? props.region.fiscal_id?.documents?.[0];
771
+ const [open, setOpen] = useState(false);
772
+ const titleId = useId();
773
+ const { ref, onBackdropClick } = useModalDialog({ open, onClose: () => setOpen(false) });
774
+ const opener = useRef(null);
775
+ if (!spec) return null;
776
+ const name = props.documentName ?? spec.label.toLowerCase();
777
+ return /* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-scan": true, children: [
778
+ /* @__PURE__ */ jsx("button", { ref: opener, type: "button", className: cx.trigger ?? cx.primary, onClick: () => setOpen(true), "aria-haspopup": "dialog", "data-sf-scan-open": true, children: fill(m.scan.open, { document: spec.label }) }),
779
+ /* @__PURE__ */ jsx("button", { type: "button", className: cx.manual ?? cx.secondary, onClick: onManual, "data-sf-scan-manual": true, children: m.scan.manual }),
780
+ open ? /* @__PURE__ */ jsx("dialog", { ref, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, onClick: onBackdropClick, onClose: () => setOpen(false), className: cx.sheet, "data-sf-scan-sheet": true, children: /* @__PURE__ */ jsxs("div", { className: cx.sheetPanel, "data-sf-scan-panel": true, children: [
781
+ /* @__PURE__ */ jsxs("div", { className: cx.sheetHeader, "data-sf-scan-header": true, children: [
782
+ /* @__PURE__ */ jsx("h2", { id: titleId, className: cx.sheetTitle, "data-sf-scan-title": true, children: fill(m.scan.title, { document: name }) }),
783
+ /* @__PURE__ */ jsx("button", { type: "button", className: cx.sheetClose, onClick: () => setOpen(false), "aria-label": m.scan.close, "data-sf-scan-close": true, "data-sf-autofocus": true, children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2715" }) })
784
+ ] }),
785
+ /* @__PURE__ */ jsx(
786
+ IdentityDocumentReader,
787
+ {
788
+ ...reader,
789
+ locale,
790
+ ...messages ? { messages } : {},
791
+ ...confirmLabel ? { confirmLabel } : {},
792
+ classNames: cx,
793
+ onConfirm: (result) => {
794
+ setOpen(false);
795
+ onConfirm(result);
796
+ },
797
+ onManual: () => {
798
+ setOpen(false);
799
+ onManual();
800
+ }
801
+ }
802
+ )
803
+ ] }) }) : null
804
+ ] });
805
+ }
528
806
  var profileValues = (p) => ({
529
807
  tax_id: p.tax_id,
530
808
  legal_name: p.legal_name,
@@ -847,6 +1125,6 @@ var ICON = {
847
1125
  cancelled: "\xD7"
848
1126
  };
849
1127
 
850
- export { FiscalIdentityFields, IdentityDocumentReader, InvoiceStatusCard, InvoiceToggle, invoiceCardState };
1128
+ export { FiscalIdentityFields, IdentityDocumentReader, InvoiceStatusCard, InvoiceToggle, ScanTaxDocument, cameraSupported, invoiceCardState, useCameraQr };
851
1129
  //# sourceMappingURL=fiscal.js.map
852
1130
  //# sourceMappingURL=fiscal.js.map