@asteby/storefront-react 0.22.0 → 0.24.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.css CHANGED
@@ -341,3 +341,106 @@
341
341
  [data-sf-invoice-actions] {
342
342
  align-items: center;
343
343
  }
344
+
345
+ /* ---- Scan a tax document: entry buttons, bottom sheet and live viewfinder ---- */
346
+ [data-sf-scan] {
347
+ display: grid;
348
+ gap: 0.75rem;
349
+ }
350
+ [data-sf-scan-open],
351
+ [data-sf-scan-manual],
352
+ [data-sf-reader-scan] button {
353
+ min-height: 44px;
354
+ }
355
+ [data-sf-reader-scan] {
356
+ display: flex;
357
+ flex-wrap: wrap;
358
+ gap: 0.75rem;
359
+ }
360
+ [data-sf-scan-sheet] {
361
+ position: fixed;
362
+ inset: auto 0 0 0;
363
+ margin: 0;
364
+ width: 100%;
365
+ max-width: none;
366
+ max-height: 92dvh;
367
+ padding: 0;
368
+ border: 0;
369
+ border-radius: 1.25rem 1.25rem 0 0;
370
+ overflow: auto;
371
+ background: var(--sf-fiscal-sheet-bg, Canvas);
372
+ color: var(--sf-fiscal-sheet-fg, CanvasText);
373
+ box-shadow: 0 -8px 32px color-mix(in srgb, #000 22%, transparent);
374
+ animation: sf-scan-rise 180ms ease-out;
375
+ }
376
+ [data-sf-scan-sheet]::backdrop {
377
+ background: color-mix(in srgb, #000 45%, transparent);
378
+ }
379
+ @media (min-width: 40rem) {
380
+ [data-sf-scan-sheet] {
381
+ inset: 50% auto auto 50%;
382
+ transform: translate(-50%, -50%);
383
+ width: min(32rem, calc(100vw - 2rem));
384
+ border-radius: 1.25rem;
385
+ animation: none;
386
+ }
387
+ }
388
+ [data-sf-scan-panel] {
389
+ display: grid;
390
+ gap: 1rem;
391
+ padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom));
392
+ }
393
+ [data-sf-scan-header] {
394
+ display: flex;
395
+ align-items: center;
396
+ justify-content: space-between;
397
+ gap: 1rem;
398
+ }
399
+ [data-sf-scan-title] {
400
+ margin: 0;
401
+ font-size: 1.125rem;
402
+ }
403
+ [data-sf-scan-close] {
404
+ min-width: 44px;
405
+ min-height: 44px;
406
+ border: 0;
407
+ background: transparent;
408
+ color: inherit;
409
+ font: inherit;
410
+ cursor: pointer;
411
+ }
412
+ [data-sf-reader-viewfinder] {
413
+ position: relative;
414
+ overflow: hidden;
415
+ border-radius: 1rem;
416
+ background: #000;
417
+ aspect-ratio: 4 / 3;
418
+ }
419
+ [data-sf-reader-video] {
420
+ display: block;
421
+ width: 100%;
422
+ height: 100%;
423
+ object-fit: cover;
424
+ }
425
+ [data-sf-reader-frame] {
426
+ position: absolute;
427
+ inset: 18%;
428
+ border: 3px solid #fff;
429
+ border-radius: 0.75rem;
430
+ box-shadow: 0 0 0 9999px color-mix(in srgb, #000 35%, transparent);
431
+ pointer-events: none;
432
+ }
433
+ [data-sf-suggested] {
434
+ font-weight: 600;
435
+ }
436
+ @keyframes sf-scan-rise {
437
+ from {
438
+ transform: translateY(24px);
439
+ opacity: 0;
440
+ }
441
+ }
442
+ @media (prefers-reduced-motion: reduce) {
443
+ [data-sf-scan-sheet] {
444
+ animation: none;
445
+ }
446
+ }
package/dist/fiscal.d.cts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react from 'react';
2
- import { ReactNode } from 'react';
2
+ import { ReactNode, RefObject } from 'react';
3
3
  import { F as FieldErrors, a as CheckoutFieldClassNames } from './fields-vnMUi2HB.cjs';
4
4
  import { Region, RegionFiscalId, RegionFiscalEntry, InvoiceRequest, FiscalDocumentEvidence, IdentityDocumentSpec, InvoicingCapabilities, FiscalIdentity, InvoiceSummary } from '@asteby/storefront';
5
- import { f as FiscalReadError, d as FiscalFieldValues, c as FiscalFieldName, F as FiscalActionData, b as FiscalExtractionSummary } from './types-BnvSbV6t.cjs';
6
- export { a as FiscalErrorCode, e as FiscalIntent } from './types-BnvSbV6t.cjs';
5
+ import { f as FiscalReadError, d as FiscalFieldValues, c as FiscalFieldName, F as FiscalActionData, g as FiscalReason, b as FiscalExtractionSummary } from './types-Cgx_65eM.cjs';
6
+ export { a as FiscalErrorCode, e as FiscalIntent } from './types-Cgx_65eM.cjs';
7
7
  import { IdentityExtraction } from '@asteby/storefront/fiscal-document';
8
8
 
9
9
  /** Texts of the fiscal components. Spanish (es-MX) by default, English with `en*`, any locale with `messages`. */
@@ -30,6 +30,8 @@ type FiscalMessages = {
30
30
  useChoose: string;
31
31
  /** `{document}` = the document's name. */
32
32
  fromDocument: string;
33
+ /** Mark on an invoice use the region suggested (an editable preselection). */
34
+ suggested: string;
33
35
  errors: {
34
36
  required: string;
35
37
  taxIdFormat: string;
@@ -64,6 +66,26 @@ type FiscalMessages = {
64
66
  stale: string;
65
67
  regimeMissing: string;
66
68
  fieldsMissing: string;
69
+ qrPartial: string;
70
+ };
71
+ /** Reading a photo or the camera (the region's `image_mode`). `{document}` where noted. */
72
+ scan: {
73
+ title: string;
74
+ photo: string;
75
+ photoHint: string;
76
+ camera: string;
77
+ cameraTitle: string;
78
+ cameraGuide: string;
79
+ cameraStarting: string;
80
+ cameraRead: string;
81
+ cameraDenied: string;
82
+ cameraUnavailable: string;
83
+ closeCamera: string;
84
+ choosePhoto: string;
85
+ /** Button that opens the sheet; `{document}` is the document's label. */
86
+ open: string;
87
+ manual: string;
88
+ close: string;
67
89
  };
68
90
  errors: Record<FiscalReadError, string>;
69
91
  summaryTitleOne: string;
@@ -114,6 +136,17 @@ type FiscalMessages = {
114
136
  windowBody: string;
115
137
  unavailableTitle: string;
116
138
  unavailableBody: string;
139
+ /** The server says the store has no invoicing active (`capabilities.invoicing.available: false`). */
140
+ notEnabledTitle: string;
141
+ notEnabledBody: string;
142
+ /** The server does not say (older server) or could not be asked: never claims the store does not invoice. */
143
+ unknownTitle: string;
144
+ unknownBody: string;
145
+ unreachableBody: string;
146
+ /** Invoicing in test mode (sandbox): invoices have no fiscal validity. */
147
+ sandbox: string;
148
+ /** `{days}`: how long after the purchase an invoice can be requested. */
149
+ windowNote: string;
117
150
  cancelledTitle: string;
118
151
  cancelledBody: string;
119
152
  /** `reason_code` -> cause for the buyer. `default` when unknown. */
@@ -147,13 +180,26 @@ declare function postalCodeProblem(region: FiscalRegion, raw: string): 'required
147
180
  * are not narrowed by person type (the server still checks the combination).
148
181
  */
149
182
  declare function personTypeByLength(lengths: Record<string, number>): (taxId: string) => string | null;
183
+ /**
184
+ * Tells a person type from a tax id with the region's own patterns (`fiscal_id.person_patterns`, DATA of the region
185
+ * pack). `null` when the region publishes none or none matches. A pattern that does not compile is ignored.
186
+ */
187
+ declare function personTypeFromPatterns(fid: RegionFiscalId | undefined, taxId: string): string | null;
188
+ /** The function to use for the person type: the store's override, else the region's patterns. */
189
+ declare function personTypeResolver(fid: RegionFiscalId | undefined, override?: (taxId: string) => string | null): (taxId: string) => string | null;
190
+ /**
191
+ * The invoice use to suggest for a regime, from region data only: the organization's `default_invoice_use` when the
192
+ * regime admits it, else the first use whose `suggested_for_regimes` lists the regime (and whose `allowed_regimes`
193
+ * admits it). `null` when the region suggests nothing: then nothing is preselected. A suggestion, never a rule.
194
+ */
195
+ declare function suggestInvoiceUse(fid: RegionFiscalId | undefined, regime: string | null | undefined): string | null;
150
196
  /** Regimes that fit a person type (all when the type is unknown). */
151
197
  declare function regimesFor(fid: RegionFiscalId | undefined, personType: string | null): RegionFiscalEntry[];
152
198
  /** Invoice uses a regime admits (all when no regime is chosen yet). */
153
199
  declare function usesFor(fid: RegionFiscalId | undefined, regime: string | null | undefined): RegionFiscalEntry[];
154
200
  type FiscalProblem = 'required' | 'format' | 'unknown' | 'person_type' | 'use_not_allowed';
155
201
  /** Client-side check of the whole form against the region; the server stays the authority. */
156
- declare function validateFiscalValues(region: FiscalRegion, v: Partial<FiscalFieldValues>, personTypeOf?: (taxId: string) => string | null): Partial<Record<FiscalFieldName, FiscalProblem>>;
202
+ declare function validateFiscalValues(region: FiscalRegion, v: Partial<FiscalFieldValues>, personTypeOverride?: (taxId: string) => string | null): Partial<Record<FiscalFieldName, FiscalProblem>>;
157
203
  /** Form values -> the API's `InvoiceRequest` (without `document`). */
158
204
  declare function toInvoiceRequest(v: Partial<FiscalFieldValues>, countryCode?: string): InvoiceRequest;
159
205
  /** `label_en` for English locales when the region has it. */
@@ -176,8 +222,13 @@ type FiscalIdentityFieldsProps = {
176
222
  namePrefix?: string;
177
223
  /** Prefix of the control ids (default: generated). */
178
224
  idPrefix?: string;
179
- /** Tells a person type from a tax id, to narrow the regimes (`personTypeByLength`). */
225
+ /**
226
+ * Overrides how a person type is told from a tax id (to narrow the regimes). Default: the region's own patterns
227
+ * (`fiscal_id.person_patterns`); with neither, the regimes are not narrowed (the server still checks).
228
+ */
180
229
  personTypeOf?: (taxId: string) => string | null;
230
+ /** The invoice use in `values` came from the region's suggestion (a document was read): it gets the "Suggested" mark. */
231
+ suggestedUse?: string | null;
181
232
  disabled?: boolean;
182
233
  locale?: string;
183
234
  messages?: DeepPartial<FiscalMessages>;
@@ -185,7 +236,7 @@ type FiscalIdentityFieldsProps = {
185
236
  /** Hides the fieldset legend (when the caller already has a heading). */
186
237
  hideLegend?: boolean;
187
238
  };
188
- declare function FiscalIdentityFields({ region, values, onChange, fromDocument, documentName, regimeCandidates, errors, namePrefix, idPrefix, personTypeOf, disabled, locale: localeProp, messages, classNames: cx, hideLegend, }: FiscalIdentityFieldsProps): react.JSX.Element;
239
+ declare function FiscalIdentityFields({ region, values, onChange, fromDocument, documentName, regimeCandidates, errors, namePrefix, idPrefix, personTypeOf: personTypeOverride, suggestedUse, disabled, locale: localeProp, messages, classNames: cx, hideLegend, }: FiscalIdentityFieldsProps): react.JSX.Element;
189
240
 
190
241
  type FiscalReaderResult = {
191
242
  values: FiscalFieldValues;
@@ -230,6 +281,50 @@ type IdentityDocumentReaderProps = {
230
281
  };
231
282
  declare function IdentityDocumentReader(props: IdentityDocumentReaderProps): react.JSX.Element | null;
232
283
 
284
+ type ScanTaxDocumentClassNames = IdentityDocumentReaderProps['classNames'] & Partial<Record<'actions' | 'trigger' | 'manual' | 'sheet' | 'sheetPanel' | 'sheetHeader' | 'sheetTitle' | 'sheetClose', string>>;
285
+ type ScanTaxDocumentProps = Omit<IdentityDocumentReaderProps, 'onConfirm' | 'onManual' | 'classNames' | 'confirmLabel'> & {
286
+ /** The buyer confirmed the reviewed data (the sheet is already closed). */
287
+ onConfirm: (result: FiscalReaderResult) => void;
288
+ /** The buyer chose to type their data (the sheet is already closed). */
289
+ onManual: () => void;
290
+ /** Label of the confirm button inside the sheet. */
291
+ confirmLabel?: ReactNode;
292
+ classNames?: ScanTaxDocumentClassNames;
293
+ };
294
+ declare function ScanTaxDocument(props: ScanTaxDocumentProps): react.JSX.Element | null;
295
+
296
+ /**
297
+ * Live QR reading with the device camera. Nothing is recorded or stored: the frames are read in memory by
298
+ * `decodeImageQr` (loaded on demand, so a page that never opens the camera pays 0 bytes for it) and the stream is
299
+ * stopped when the scanner closes, when the component unmounts or when the page is hidden.
300
+ */
301
+
302
+ type CameraQrStatus =
303
+ /** Not running. */
304
+ 'idle'
305
+ /** Waiting for the permission or for the first frame. */
306
+ | 'starting' | 'scanning'
307
+ /** The buyer (or the browser) refused the camera. */
308
+ | 'denied'
309
+ /** No `getUserMedia` here (old browser, insecure page). */
310
+ | 'unsupported';
311
+ type UseCameraQrOptions = {
312
+ /** Start (true) or stop (false) the camera. */
313
+ active: boolean;
314
+ /** The QR text read. Called once; the camera stops right after. */
315
+ onCode: (text: string) => void;
316
+ /** Milliseconds between two reading attempts (default 250). */
317
+ intervalMs?: number;
318
+ };
319
+ type UseCameraQr = {
320
+ videoRef: RefObject<HTMLVideoElement | null>;
321
+ status: CameraQrStatus;
322
+ /** Stops the stream now. */
323
+ stop: () => void;
324
+ };
325
+ declare function cameraSupported(): boolean;
326
+ declare function useCameraQr({ active, onCode, intervalMs }: UseCameraQrOptions): UseCameraQr;
327
+
233
328
  type InvoiceToggleState = {
234
329
  requested: boolean;
235
330
  /** The data to send as `CheckoutInput.invoice` / `carts.setInvoice`; `null` when none is requested or it is not ready. */
@@ -273,14 +368,28 @@ type InvoiceToggleProps = {
273
368
  };
274
369
  declare function InvoiceToggle(props: InvoiceToggleProps): react.JSX.Element | null;
275
370
 
276
- type InvoiceCardState = 'not_requested' | 'awaiting_payment' | 'processing' | 'issued' | 'needs_data' | 'needs_review' | 'window_closed' | 'unavailable' | 'cancelled';
277
- /** Which of the card's states an invoice is in. `available: false` (the store does not invoice) wins over everything. */
278
- declare function invoiceCardState(invoice: InvoiceSummary | null | undefined, available?: boolean): InvoiceCardState;
371
+ type InvoiceCardState = 'not_requested' | 'awaiting_payment' | 'processing' | 'issued' | 'needs_data' | 'needs_review' | 'window_closed' | 'unavailable' | 'not_enabled' | 'unknown' | 'unreachable' | 'cancelled';
372
+ /**
373
+ * Which of the card's states an invoice is in.
374
+ *
375
+ * `available` / `reason` come from `loadFiscalContext`. Only a server that SAYS the store does not invoice
376
+ * (`reason` `off` / `no_region`) wins over the order: `not_enabled`. When the server says nothing (`unknown`, an older
377
+ * server), could not be asked (`unreachable`) or the caller gave no `reason`, the order's own summary still decides
378
+ * (an order that `can_request`, is being issued or already has its invoice is shown as such) and, with nothing to show,
379
+ * the card is neutral: it never claims that the store does not issue invoices.
380
+ */
381
+ declare function invoiceCardState(invoice: InvoiceSummary | null | undefined, available?: boolean, reason?: FiscalReason): InvoiceCardState;
279
382
  type InvoiceStatusCardClassNames = Partial<Record<'root' | 'title' | 'body' | 'actions' | 'primary' | 'secondary' | 'link' | 'meta', string>>;
280
383
  type InvoiceStatusCardProps = {
281
384
  invoice?: InvoiceSummary | null;
282
- /** `capabilities.invoicing.available`. `false`: "Invoice not available". */
385
+ /** `loadFiscalContext(...).available`. `false` alone is read as "unknown": see `availability`. */
283
386
  available?: boolean;
387
+ /** `loadFiscalContext(...).reason`: why it is (not) available. Lets the card say the true thing (not active / unknown / could not check). */
388
+ availability?: FiscalReason;
389
+ /** Invoicing is in test mode (sandbox): shows a badge saying invoices have no fiscal validity. */
390
+ testMode?: boolean;
391
+ /** `capabilities.invoicing.window_days`: shown next to the request button. */
392
+ windowDays?: number;
284
393
  /** The buyer taps "Request invoice". Shown when `invoice.can_request !== false`. Without it, `requestHref` is a link. */
285
394
  onRequest?: () => void;
286
395
  requestHref?: string;
@@ -310,4 +419,4 @@ declare function InvoiceStatusCard(props: InvoiceStatusCardProps): react.JSX.Ele
310
419
  /** `evidence` comes from `buildDocumentEvidence`. Only the conventional fields are kept: nothing else can leak. */
311
420
  declare function summarizeExtraction(x: IdentityExtraction, evidence: FiscalDocumentEvidence, validRegimes?: Iterable<string>): FiscalExtractionSummary;
312
421
 
313
- export { type DeepPartial, FiscalActionData, FiscalExtractionSummary, FiscalFieldName, FiscalFieldValues, FiscalIdentityFields, type FiscalIdentityFieldsClassNames, type FiscalIdentityFieldsProps, type FiscalMessages, type FiscalProblem, FiscalReadError, type FiscalReaderResult, type FiscalRegion, IdentityDocumentReader, type IdentityDocumentReaderClassNames, type IdentityDocumentReaderProps, type InvoiceCardState, InvoiceStatusCard, type InvoiceStatusCardClassNames, type InvoiceStatusCardProps, InvoiceToggle, type InvoiceToggleClassNames, type InvoiceToggleProps, type InvoiceToggleState, entryLabel, fiscalMessages, invoiceCardState, maskTaxId, normalizeTaxId, personTypeByLength, postalCodeProblem, regimesFor, summarizeExtraction, taxIdProblem, toInvoiceRequest, usesFor, validateFiscalValues };
422
+ export { type CameraQrStatus, type DeepPartial, FiscalActionData, FiscalExtractionSummary, FiscalFieldName, FiscalFieldValues, FiscalIdentityFields, type FiscalIdentityFieldsClassNames, type FiscalIdentityFieldsProps, type FiscalMessages, type FiscalProblem, FiscalReadError, type FiscalReaderResult, type FiscalRegion, IdentityDocumentReader, type IdentityDocumentReaderClassNames, type IdentityDocumentReaderProps, type InvoiceCardState, InvoiceStatusCard, type InvoiceStatusCardClassNames, type InvoiceStatusCardProps, InvoiceToggle, type InvoiceToggleClassNames, type InvoiceToggleProps, type InvoiceToggleState, ScanTaxDocument, type ScanTaxDocumentClassNames, type ScanTaxDocumentProps, type UseCameraQr, type UseCameraQrOptions, cameraSupported, entryLabel, fiscalMessages, invoiceCardState, maskTaxId, normalizeTaxId, personTypeByLength, personTypeFromPatterns, personTypeResolver, postalCodeProblem, regimesFor, suggestInvoiceUse, summarizeExtraction, taxIdProblem, toInvoiceRequest, useCameraQr, usesFor, validateFiscalValues };
package/dist/fiscal.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react from 'react';
2
- import { ReactNode } from 'react';
2
+ import { ReactNode, RefObject } from 'react';
3
3
  import { F as FieldErrors, a as CheckoutFieldClassNames } from './fields-vnMUi2HB.js';
4
4
  import { Region, RegionFiscalId, RegionFiscalEntry, InvoiceRequest, FiscalDocumentEvidence, IdentityDocumentSpec, InvoicingCapabilities, FiscalIdentity, InvoiceSummary } from '@asteby/storefront';
5
- import { f as FiscalReadError, d as FiscalFieldValues, c as FiscalFieldName, F as FiscalActionData, b as FiscalExtractionSummary } from './types-BnvSbV6t.js';
6
- export { a as FiscalErrorCode, e as FiscalIntent } from './types-BnvSbV6t.js';
5
+ import { f as FiscalReadError, d as FiscalFieldValues, c as FiscalFieldName, F as FiscalActionData, g as FiscalReason, b as FiscalExtractionSummary } from './types-Cgx_65eM.js';
6
+ export { a as FiscalErrorCode, e as FiscalIntent } from './types-Cgx_65eM.js';
7
7
  import { IdentityExtraction } from '@asteby/storefront/fiscal-document';
8
8
 
9
9
  /** Texts of the fiscal components. Spanish (es-MX) by default, English with `en*`, any locale with `messages`. */
@@ -30,6 +30,8 @@ type FiscalMessages = {
30
30
  useChoose: string;
31
31
  /** `{document}` = the document's name. */
32
32
  fromDocument: string;
33
+ /** Mark on an invoice use the region suggested (an editable preselection). */
34
+ suggested: string;
33
35
  errors: {
34
36
  required: string;
35
37
  taxIdFormat: string;
@@ -64,6 +66,26 @@ type FiscalMessages = {
64
66
  stale: string;
65
67
  regimeMissing: string;
66
68
  fieldsMissing: string;
69
+ qrPartial: string;
70
+ };
71
+ /** Reading a photo or the camera (the region's `image_mode`). `{document}` where noted. */
72
+ scan: {
73
+ title: string;
74
+ photo: string;
75
+ photoHint: string;
76
+ camera: string;
77
+ cameraTitle: string;
78
+ cameraGuide: string;
79
+ cameraStarting: string;
80
+ cameraRead: string;
81
+ cameraDenied: string;
82
+ cameraUnavailable: string;
83
+ closeCamera: string;
84
+ choosePhoto: string;
85
+ /** Button that opens the sheet; `{document}` is the document's label. */
86
+ open: string;
87
+ manual: string;
88
+ close: string;
67
89
  };
68
90
  errors: Record<FiscalReadError, string>;
69
91
  summaryTitleOne: string;
@@ -114,6 +136,17 @@ type FiscalMessages = {
114
136
  windowBody: string;
115
137
  unavailableTitle: string;
116
138
  unavailableBody: string;
139
+ /** The server says the store has no invoicing active (`capabilities.invoicing.available: false`). */
140
+ notEnabledTitle: string;
141
+ notEnabledBody: string;
142
+ /** The server does not say (older server) or could not be asked: never claims the store does not invoice. */
143
+ unknownTitle: string;
144
+ unknownBody: string;
145
+ unreachableBody: string;
146
+ /** Invoicing in test mode (sandbox): invoices have no fiscal validity. */
147
+ sandbox: string;
148
+ /** `{days}`: how long after the purchase an invoice can be requested. */
149
+ windowNote: string;
117
150
  cancelledTitle: string;
118
151
  cancelledBody: string;
119
152
  /** `reason_code` -> cause for the buyer. `default` when unknown. */
@@ -147,13 +180,26 @@ declare function postalCodeProblem(region: FiscalRegion, raw: string): 'required
147
180
  * are not narrowed by person type (the server still checks the combination).
148
181
  */
149
182
  declare function personTypeByLength(lengths: Record<string, number>): (taxId: string) => string | null;
183
+ /**
184
+ * Tells a person type from a tax id with the region's own patterns (`fiscal_id.person_patterns`, DATA of the region
185
+ * pack). `null` when the region publishes none or none matches. A pattern that does not compile is ignored.
186
+ */
187
+ declare function personTypeFromPatterns(fid: RegionFiscalId | undefined, taxId: string): string | null;
188
+ /** The function to use for the person type: the store's override, else the region's patterns. */
189
+ declare function personTypeResolver(fid: RegionFiscalId | undefined, override?: (taxId: string) => string | null): (taxId: string) => string | null;
190
+ /**
191
+ * The invoice use to suggest for a regime, from region data only: the organization's `default_invoice_use` when the
192
+ * regime admits it, else the first use whose `suggested_for_regimes` lists the regime (and whose `allowed_regimes`
193
+ * admits it). `null` when the region suggests nothing: then nothing is preselected. A suggestion, never a rule.
194
+ */
195
+ declare function suggestInvoiceUse(fid: RegionFiscalId | undefined, regime: string | null | undefined): string | null;
150
196
  /** Regimes that fit a person type (all when the type is unknown). */
151
197
  declare function regimesFor(fid: RegionFiscalId | undefined, personType: string | null): RegionFiscalEntry[];
152
198
  /** Invoice uses a regime admits (all when no regime is chosen yet). */
153
199
  declare function usesFor(fid: RegionFiscalId | undefined, regime: string | null | undefined): RegionFiscalEntry[];
154
200
  type FiscalProblem = 'required' | 'format' | 'unknown' | 'person_type' | 'use_not_allowed';
155
201
  /** Client-side check of the whole form against the region; the server stays the authority. */
156
- declare function validateFiscalValues(region: FiscalRegion, v: Partial<FiscalFieldValues>, personTypeOf?: (taxId: string) => string | null): Partial<Record<FiscalFieldName, FiscalProblem>>;
202
+ declare function validateFiscalValues(region: FiscalRegion, v: Partial<FiscalFieldValues>, personTypeOverride?: (taxId: string) => string | null): Partial<Record<FiscalFieldName, FiscalProblem>>;
157
203
  /** Form values -> the API's `InvoiceRequest` (without `document`). */
158
204
  declare function toInvoiceRequest(v: Partial<FiscalFieldValues>, countryCode?: string): InvoiceRequest;
159
205
  /** `label_en` for English locales when the region has it. */
@@ -176,8 +222,13 @@ type FiscalIdentityFieldsProps = {
176
222
  namePrefix?: string;
177
223
  /** Prefix of the control ids (default: generated). */
178
224
  idPrefix?: string;
179
- /** Tells a person type from a tax id, to narrow the regimes (`personTypeByLength`). */
225
+ /**
226
+ * Overrides how a person type is told from a tax id (to narrow the regimes). Default: the region's own patterns
227
+ * (`fiscal_id.person_patterns`); with neither, the regimes are not narrowed (the server still checks).
228
+ */
180
229
  personTypeOf?: (taxId: string) => string | null;
230
+ /** The invoice use in `values` came from the region's suggestion (a document was read): it gets the "Suggested" mark. */
231
+ suggestedUse?: string | null;
181
232
  disabled?: boolean;
182
233
  locale?: string;
183
234
  messages?: DeepPartial<FiscalMessages>;
@@ -185,7 +236,7 @@ type FiscalIdentityFieldsProps = {
185
236
  /** Hides the fieldset legend (when the caller already has a heading). */
186
237
  hideLegend?: boolean;
187
238
  };
188
- declare function FiscalIdentityFields({ region, values, onChange, fromDocument, documentName, regimeCandidates, errors, namePrefix, idPrefix, personTypeOf, disabled, locale: localeProp, messages, classNames: cx, hideLegend, }: FiscalIdentityFieldsProps): react.JSX.Element;
239
+ declare function FiscalIdentityFields({ region, values, onChange, fromDocument, documentName, regimeCandidates, errors, namePrefix, idPrefix, personTypeOf: personTypeOverride, suggestedUse, disabled, locale: localeProp, messages, classNames: cx, hideLegend, }: FiscalIdentityFieldsProps): react.JSX.Element;
189
240
 
190
241
  type FiscalReaderResult = {
191
242
  values: FiscalFieldValues;
@@ -230,6 +281,50 @@ type IdentityDocumentReaderProps = {
230
281
  };
231
282
  declare function IdentityDocumentReader(props: IdentityDocumentReaderProps): react.JSX.Element | null;
232
283
 
284
+ type ScanTaxDocumentClassNames = IdentityDocumentReaderProps['classNames'] & Partial<Record<'actions' | 'trigger' | 'manual' | 'sheet' | 'sheetPanel' | 'sheetHeader' | 'sheetTitle' | 'sheetClose', string>>;
285
+ type ScanTaxDocumentProps = Omit<IdentityDocumentReaderProps, 'onConfirm' | 'onManual' | 'classNames' | 'confirmLabel'> & {
286
+ /** The buyer confirmed the reviewed data (the sheet is already closed). */
287
+ onConfirm: (result: FiscalReaderResult) => void;
288
+ /** The buyer chose to type their data (the sheet is already closed). */
289
+ onManual: () => void;
290
+ /** Label of the confirm button inside the sheet. */
291
+ confirmLabel?: ReactNode;
292
+ classNames?: ScanTaxDocumentClassNames;
293
+ };
294
+ declare function ScanTaxDocument(props: ScanTaxDocumentProps): react.JSX.Element | null;
295
+
296
+ /**
297
+ * Live QR reading with the device camera. Nothing is recorded or stored: the frames are read in memory by
298
+ * `decodeImageQr` (loaded on demand, so a page that never opens the camera pays 0 bytes for it) and the stream is
299
+ * stopped when the scanner closes, when the component unmounts or when the page is hidden.
300
+ */
301
+
302
+ type CameraQrStatus =
303
+ /** Not running. */
304
+ 'idle'
305
+ /** Waiting for the permission or for the first frame. */
306
+ | 'starting' | 'scanning'
307
+ /** The buyer (or the browser) refused the camera. */
308
+ | 'denied'
309
+ /** No `getUserMedia` here (old browser, insecure page). */
310
+ | 'unsupported';
311
+ type UseCameraQrOptions = {
312
+ /** Start (true) or stop (false) the camera. */
313
+ active: boolean;
314
+ /** The QR text read. Called once; the camera stops right after. */
315
+ onCode: (text: string) => void;
316
+ /** Milliseconds between two reading attempts (default 250). */
317
+ intervalMs?: number;
318
+ };
319
+ type UseCameraQr = {
320
+ videoRef: RefObject<HTMLVideoElement | null>;
321
+ status: CameraQrStatus;
322
+ /** Stops the stream now. */
323
+ stop: () => void;
324
+ };
325
+ declare function cameraSupported(): boolean;
326
+ declare function useCameraQr({ active, onCode, intervalMs }: UseCameraQrOptions): UseCameraQr;
327
+
233
328
  type InvoiceToggleState = {
234
329
  requested: boolean;
235
330
  /** The data to send as `CheckoutInput.invoice` / `carts.setInvoice`; `null` when none is requested or it is not ready. */
@@ -273,14 +368,28 @@ type InvoiceToggleProps = {
273
368
  };
274
369
  declare function InvoiceToggle(props: InvoiceToggleProps): react.JSX.Element | null;
275
370
 
276
- type InvoiceCardState = 'not_requested' | 'awaiting_payment' | 'processing' | 'issued' | 'needs_data' | 'needs_review' | 'window_closed' | 'unavailable' | 'cancelled';
277
- /** Which of the card's states an invoice is in. `available: false` (the store does not invoice) wins over everything. */
278
- declare function invoiceCardState(invoice: InvoiceSummary | null | undefined, available?: boolean): InvoiceCardState;
371
+ type InvoiceCardState = 'not_requested' | 'awaiting_payment' | 'processing' | 'issued' | 'needs_data' | 'needs_review' | 'window_closed' | 'unavailable' | 'not_enabled' | 'unknown' | 'unreachable' | 'cancelled';
372
+ /**
373
+ * Which of the card's states an invoice is in.
374
+ *
375
+ * `available` / `reason` come from `loadFiscalContext`. Only a server that SAYS the store does not invoice
376
+ * (`reason` `off` / `no_region`) wins over the order: `not_enabled`. When the server says nothing (`unknown`, an older
377
+ * server), could not be asked (`unreachable`) or the caller gave no `reason`, the order's own summary still decides
378
+ * (an order that `can_request`, is being issued or already has its invoice is shown as such) and, with nothing to show,
379
+ * the card is neutral: it never claims that the store does not issue invoices.
380
+ */
381
+ declare function invoiceCardState(invoice: InvoiceSummary | null | undefined, available?: boolean, reason?: FiscalReason): InvoiceCardState;
279
382
  type InvoiceStatusCardClassNames = Partial<Record<'root' | 'title' | 'body' | 'actions' | 'primary' | 'secondary' | 'link' | 'meta', string>>;
280
383
  type InvoiceStatusCardProps = {
281
384
  invoice?: InvoiceSummary | null;
282
- /** `capabilities.invoicing.available`. `false`: "Invoice not available". */
385
+ /** `loadFiscalContext(...).available`. `false` alone is read as "unknown": see `availability`. */
283
386
  available?: boolean;
387
+ /** `loadFiscalContext(...).reason`: why it is (not) available. Lets the card say the true thing (not active / unknown / could not check). */
388
+ availability?: FiscalReason;
389
+ /** Invoicing is in test mode (sandbox): shows a badge saying invoices have no fiscal validity. */
390
+ testMode?: boolean;
391
+ /** `capabilities.invoicing.window_days`: shown next to the request button. */
392
+ windowDays?: number;
284
393
  /** The buyer taps "Request invoice". Shown when `invoice.can_request !== false`. Without it, `requestHref` is a link. */
285
394
  onRequest?: () => void;
286
395
  requestHref?: string;
@@ -310,4 +419,4 @@ declare function InvoiceStatusCard(props: InvoiceStatusCardProps): react.JSX.Ele
310
419
  /** `evidence` comes from `buildDocumentEvidence`. Only the conventional fields are kept: nothing else can leak. */
311
420
  declare function summarizeExtraction(x: IdentityExtraction, evidence: FiscalDocumentEvidence, validRegimes?: Iterable<string>): FiscalExtractionSummary;
312
421
 
313
- export { type DeepPartial, FiscalActionData, FiscalExtractionSummary, FiscalFieldName, FiscalFieldValues, FiscalIdentityFields, type FiscalIdentityFieldsClassNames, type FiscalIdentityFieldsProps, type FiscalMessages, type FiscalProblem, FiscalReadError, type FiscalReaderResult, type FiscalRegion, IdentityDocumentReader, type IdentityDocumentReaderClassNames, type IdentityDocumentReaderProps, type InvoiceCardState, InvoiceStatusCard, type InvoiceStatusCardClassNames, type InvoiceStatusCardProps, InvoiceToggle, type InvoiceToggleClassNames, type InvoiceToggleProps, type InvoiceToggleState, entryLabel, fiscalMessages, invoiceCardState, maskTaxId, normalizeTaxId, personTypeByLength, postalCodeProblem, regimesFor, summarizeExtraction, taxIdProblem, toInvoiceRequest, usesFor, validateFiscalValues };
422
+ export { type CameraQrStatus, type DeepPartial, FiscalActionData, FiscalExtractionSummary, FiscalFieldName, FiscalFieldValues, FiscalIdentityFields, type FiscalIdentityFieldsClassNames, type FiscalIdentityFieldsProps, type FiscalMessages, type FiscalProblem, FiscalReadError, type FiscalReaderResult, type FiscalRegion, IdentityDocumentReader, type IdentityDocumentReaderClassNames, type IdentityDocumentReaderProps, type InvoiceCardState, InvoiceStatusCard, type InvoiceStatusCardClassNames, type InvoiceStatusCardProps, InvoiceToggle, type InvoiceToggleClassNames, type InvoiceToggleProps, type InvoiceToggleState, ScanTaxDocument, type ScanTaxDocumentClassNames, type ScanTaxDocumentProps, type UseCameraQr, type UseCameraQrOptions, cameraSupported, entryLabel, fiscalMessages, invoiceCardState, maskTaxId, normalizeTaxId, personTypeByLength, personTypeFromPatterns, personTypeResolver, postalCodeProblem, regimesFor, suggestInvoiceUse, summarizeExtraction, taxIdProblem, toInvoiceRequest, useCameraQr, usesFor, validateFiscalValues };