@asteby/storefront-react 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,343 @@
1
+ /*
2
+ * Default sheet for the fiscal components (`@asteby/storefront-react/fiscal.css`): <InvoiceToggle>, <IdentityDocumentReader>,
3
+ * <FiscalIdentityFields> and <InvoiceStatusCard>. Optional and neutral; it works next to `checkout.css` (the fields).
4
+ * Colors come from `currentColor` and these variables (set them in light and dark):
5
+ * --sf-fiscal-border hairlines and the drop zone (default currentColor at 30%)
6
+ * --sf-fiscal-muted secondary text (default currentColor at 72%)
7
+ * --sf-fiscal-accent focus ring, primary button (default #1d4ed8)
8
+ * --sf-fiscal-accent-contrast text on the accent (default #fff)
9
+ * --sf-fiscal-warn warning text (default #8a4b00)
10
+ * --sf-fiscal-ok issued (default #166534)
11
+ * Targets are at least 44px; states carry an icon and a word, never color alone; motion stops with prefers-reduced-motion.
12
+ */
13
+ [data-sf-invoice-toggle],
14
+ [data-sf-document-reader],
15
+ [data-sf-invoice-card] {
16
+ --_border: var(--sf-fiscal-border, color-mix(in srgb, currentColor 30%, transparent));
17
+ --_muted: var(--sf-fiscal-muted, color-mix(in srgb, currentColor 72%, transparent));
18
+ --_accent: var(--sf-fiscal-accent, #1d4ed8);
19
+ }
20
+ [data-sf-invoice-toggle] {
21
+ display: grid;
22
+ gap: 1rem;
23
+ }
24
+ [data-sf-invoice-label],
25
+ [data-sf-reader-save],
26
+ [data-sf-invoice-save],
27
+ [data-sf-fiscal-radio] {
28
+ display: flex;
29
+ align-items: flex-start;
30
+ gap: 0.75rem;
31
+ min-height: 44px;
32
+ padding-block: 0.5rem;
33
+ cursor: pointer;
34
+ }
35
+ [data-sf-invoice-label] {
36
+ font-weight: 600;
37
+ }
38
+ [data-sf-invoice-label] input,
39
+ [data-sf-reader-save] input,
40
+ [data-sf-invoice-save] input,
41
+ [data-sf-fiscal-radio] input {
42
+ flex: none;
43
+ width: 1.5rem;
44
+ height: 1.5rem;
45
+ margin: 0;
46
+ accent-color: var(--_accent);
47
+ }
48
+ [data-sf-invoice-body] {
49
+ display: grid;
50
+ gap: 1rem;
51
+ }
52
+ [data-sf-fiscal-fields] {
53
+ display: grid;
54
+ gap: 1rem;
55
+ }
56
+ [data-sf-from-document] {
57
+ font-weight: 600;
58
+ color: var(--sf-fiscal-ok, #166534);
59
+ }
60
+ [data-sf-fiscal-regimes] {
61
+ display: grid;
62
+ gap: 0.25rem;
63
+ }
64
+ [data-sf-fiscal-code] {
65
+ color: var(--_muted);
66
+ }
67
+
68
+ /* Reader */
69
+ [data-sf-reader] {
70
+ display: grid;
71
+ gap: 0.75rem;
72
+ }
73
+ [data-sf-reader-title] {
74
+ margin: 0;
75
+ font-size: 1.0625rem;
76
+ }
77
+ [data-sf-reader-title]:focus {
78
+ outline: none;
79
+ }
80
+ [data-sf-reader-help],
81
+ [data-sf-reader-privacy] {
82
+ margin: 0;
83
+ color: var(--_muted);
84
+ font-size: 0.875rem;
85
+ }
86
+ [data-sf-reader-zone] {
87
+ position: relative;
88
+ display: grid;
89
+ justify-items: center;
90
+ gap: 0.25rem;
91
+ padding: 1.5rem 1rem;
92
+ min-height: 8rem;
93
+ border: 2px dashed var(--_border);
94
+ border-radius: 0.75rem;
95
+ text-align: center;
96
+ cursor: pointer;
97
+ transition: background-color 0.15s, border-color 0.15s;
98
+ }
99
+ [data-sf-reader-zone][data-dragging],
100
+ [data-sf-reader-zone]:hover {
101
+ border-color: var(--_accent);
102
+ background: color-mix(in srgb, var(--_accent) 6%, transparent);
103
+ }
104
+ [data-sf-reader-zone]:focus-within {
105
+ outline: 3px solid var(--_accent);
106
+ outline-offset: 2px;
107
+ border-style: solid;
108
+ }
109
+ [data-sf-reader-icon] {
110
+ font-size: 1.5rem;
111
+ line-height: 1;
112
+ }
113
+ [data-sf-reader-choose] {
114
+ min-height: 44px;
115
+ display: inline-grid;
116
+ align-items: center;
117
+ padding-inline: 1rem;
118
+ border-radius: 0.5rem;
119
+ border: 1px solid currentColor;
120
+ font-weight: 600;
121
+ }
122
+ /* The real input stays focusable and clickable, but invisible: the zone is its visible face. */
123
+ [data-sf-reader-input] {
124
+ position: absolute;
125
+ inset: 0;
126
+ width: 100%;
127
+ height: 100%;
128
+ opacity: 0;
129
+ cursor: pointer;
130
+ }
131
+ [data-sf-reader-links] {
132
+ display: flex;
133
+ flex-wrap: wrap;
134
+ gap: 0.25rem 1.25rem;
135
+ margin: 0;
136
+ }
137
+ [data-sf-reader-links] a,
138
+ [data-sf-reader-links] button,
139
+ [data-sf-invoice-back],
140
+ [data-sf-invoice-other] {
141
+ min-height: 44px;
142
+ display: inline-flex;
143
+ align-items: center;
144
+ padding: 0;
145
+ border: 0;
146
+ background: none;
147
+ color: inherit;
148
+ font: inherit;
149
+ text-decoration: underline;
150
+ cursor: pointer;
151
+ }
152
+ [data-sf-reader-reading] {
153
+ display: flex;
154
+ align-items: center;
155
+ gap: 0.75rem;
156
+ margin: 0;
157
+ }
158
+ [data-sf-reader-spinner] {
159
+ flex: none;
160
+ width: 1.25rem;
161
+ height: 1.25rem;
162
+ border: 3px solid var(--_border);
163
+ border-top-color: var(--_accent);
164
+ border-radius: 50%;
165
+ animation: sf-fiscal-spin 0.9s linear infinite;
166
+ }
167
+ [data-sf-reader-error] {
168
+ padding: 0.75rem 1rem;
169
+ border: 2px solid var(--sf-field-error, #b42318);
170
+ border-radius: 0.5rem;
171
+ font-weight: 600;
172
+ }
173
+ [data-sf-reader-error]::before {
174
+ content: '! ';
175
+ }
176
+ [data-sf-reader-error]:focus {
177
+ outline: 3px solid var(--_accent);
178
+ outline-offset: 2px;
179
+ }
180
+ [data-sf-reader-warnings] {
181
+ margin: 0;
182
+ padding: 0.75rem 1rem;
183
+ list-style: none;
184
+ display: grid;
185
+ gap: 0.5rem;
186
+ border: 1px solid var(--sf-fiscal-warn, #8a4b00);
187
+ border-radius: 0.5rem;
188
+ color: var(--sf-fiscal-warn, #8a4b00);
189
+ }
190
+ [data-sf-invoice-actions],
191
+ [data-sf-reader-actions] {
192
+ display: flex;
193
+ flex-wrap: wrap;
194
+ gap: 0.5rem 1rem;
195
+ }
196
+ [data-sf-reader-confirm],
197
+ [data-sf-reader-cancel],
198
+ [data-sf-reader-retry],
199
+ [data-sf-reader-upload],
200
+ [data-sf-invoice-change],
201
+ [data-sf-invoice-request],
202
+ [data-sf-invoice-correct],
203
+ [data-sf-invoice-refresh],
204
+ [data-sf-invoice-pdf],
205
+ [data-sf-invoice-xml],
206
+ [data-sf-invoice-contact] {
207
+ min-height: 44px;
208
+ display: inline-flex;
209
+ align-items: center;
210
+ justify-content: center;
211
+ padding-inline: 1.25rem;
212
+ border-radius: 0.5rem;
213
+ border: 1px solid currentColor;
214
+ background: none;
215
+ color: inherit;
216
+ font: inherit;
217
+ font-weight: 600;
218
+ text-decoration: none;
219
+ cursor: pointer;
220
+ }
221
+ [data-sf-reader-confirm],
222
+ [data-sf-invoice-request],
223
+ [data-sf-invoice-correct],
224
+ [data-sf-invoice-pdf] {
225
+ background: var(--_accent);
226
+ border-color: var(--_accent);
227
+ color: var(--sf-fiscal-accent-contrast, #fff);
228
+ }
229
+ :is([data-sf-reader-confirm], [data-sf-invoice-request], [data-sf-invoice-correct], [data-sf-invoice-pdf], [data-sf-invoice-change], [data-sf-invoice-refresh]):focus-visible,
230
+ [data-sf-reader-links] :focus-visible,
231
+ [data-sf-invoice-back]:focus-visible,
232
+ [data-sf-invoice-other]:focus-visible {
233
+ outline: 3px solid var(--_accent);
234
+ outline-offset: 2px;
235
+ }
236
+
237
+ /* Saved profile card */
238
+ [data-sf-invoice-profile],
239
+ [data-sf-invoice-card] {
240
+ display: grid;
241
+ gap: 0.75rem;
242
+ padding: 1rem;
243
+ border: 1px solid var(--_border);
244
+ border-radius: 0.75rem;
245
+ }
246
+ [data-sf-invoice-profile] dl {
247
+ display: grid;
248
+ gap: 0.25rem;
249
+ margin: 0;
250
+ }
251
+ [data-sf-invoice-row] {
252
+ display: grid;
253
+ grid-template-columns: minmax(7rem, 35%) 1fr;
254
+ gap: 0.5rem;
255
+ }
256
+ [data-sf-invoice-row] dt {
257
+ color: var(--_muted);
258
+ }
259
+ [data-sf-invoice-row] dd {
260
+ margin: 0;
261
+ overflow-wrap: anywhere;
262
+ }
263
+ [data-sf-invoice-profile-title] {
264
+ margin: 0;
265
+ font-weight: 600;
266
+ }
267
+ [data-sf-invoice-privacy] {
268
+ margin: 0;
269
+ color: var(--_muted);
270
+ font-size: 0.875rem;
271
+ }
272
+
273
+ /* Status card */
274
+ [data-sf-invoice-title] {
275
+ display: flex;
276
+ align-items: center;
277
+ gap: 0.5rem;
278
+ margin: 0;
279
+ font-size: 1.0625rem;
280
+ }
281
+ [data-sf-invoice-icon] {
282
+ display: inline-grid;
283
+ place-items: center;
284
+ flex: none;
285
+ width: 1.75rem;
286
+ height: 1.75rem;
287
+ border: 2px solid currentColor;
288
+ border-radius: 50%;
289
+ font-size: 0.9rem;
290
+ font-weight: 700;
291
+ }
292
+ [data-sf-invoice-card][data-state='issued'] [data-sf-invoice-icon] {
293
+ color: var(--sf-fiscal-ok, #166534);
294
+ }
295
+ [data-sf-invoice-card][data-state='needs_data'] [data-sf-invoice-icon] {
296
+ color: var(--sf-field-error, #b42318);
297
+ }
298
+ [data-sf-invoice-card][data-state='processing'] [data-sf-invoice-icon] {
299
+ animation: sf-fiscal-spin 1.6s linear infinite;
300
+ }
301
+ [data-sf-invoice-card] p {
302
+ margin: 0;
303
+ }
304
+ [data-sf-invoice-card] [data-sf-invoice-live] {
305
+ display: grid;
306
+ gap: 0.5rem;
307
+ }
308
+ [data-sf-invoice-folio] code {
309
+ overflow-wrap: anywhere;
310
+ }
311
+
312
+ @keyframes sf-fiscal-spin {
313
+ to {
314
+ transform: rotate(360deg);
315
+ }
316
+ }
317
+ @media (prefers-reduced-motion: reduce) {
318
+ [data-sf-reader-spinner],
319
+ [data-sf-invoice-card][data-state='processing'] [data-sf-invoice-icon] {
320
+ animation: none;
321
+ }
322
+ [data-sf-reader-zone] {
323
+ transition: none;
324
+ }
325
+ }
326
+ @media (max-width: 30rem) {
327
+ [data-sf-invoice-row] {
328
+ grid-template-columns: 1fr;
329
+ gap: 0;
330
+ }
331
+ [data-sf-invoice-actions] > *,
332
+ [data-sf-reader-confirm] {
333
+ flex: 1 1 100%;
334
+ }
335
+ }
336
+
337
+ [data-sf-fiscal-regimes] legend {
338
+ padding: 0;
339
+ font-weight: 600;
340
+ }
341
+ [data-sf-invoice-actions] {
342
+ align-items: center;
343
+ }
@@ -0,0 +1,313 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { F as FieldErrors, a as CheckoutFieldClassNames } from './fields-vnMUi2HB.cjs';
4
+ import { Region, RegionFiscalId, RegionFiscalEntry, InvoiceRequest, FiscalDocumentEvidence, IdentityDocumentSpec, InvoicingCapabilities, FiscalIdentity, InvoiceSummary } from '@asteby/storefront';
5
+ import { d as FiscalFieldValues, c as FiscalFieldName, f as FiscalReadError, F as FiscalActionData, b as FiscalExtractionSummary } from './types-BnvSbV6t.cjs';
6
+ export { a as FiscalErrorCode, e as FiscalIntent } from './types-BnvSbV6t.cjs';
7
+ import { IdentityExtraction } from '@asteby/storefront/fiscal-document';
8
+
9
+ /**
10
+ * Pure helpers over the region's fiscal catalog (`Region.fiscal_id`). They know no country: the tax id format, the
11
+ * regimes, the invoice uses and the postal code format are all data.
12
+ */
13
+
14
+ type FiscalRegion = Pick<Region, 'address'> & {
15
+ fiscal_id?: RegionFiscalId;
16
+ };
17
+ /** Uppercase, no spaces, hyphens or dots: how a tax id is compared and sent. */
18
+ declare function normalizeTaxId(raw: string): string;
19
+ /** Masks a tax id for display and logs: first 2 and last 3 characters stay (`PE********ABC`). */
20
+ declare function maskTaxId(taxId: string): string;
21
+ /** `null` when the tax id is valid for the region (its pattern or one of its generic ids); otherwise why not. */
22
+ declare function taxIdProblem(fid: RegionFiscalId | undefined, raw: string): 'required' | 'format' | null;
23
+ declare function postalCodeProblem(region: FiscalRegion, raw: string): 'required' | 'format' | null;
24
+ /**
25
+ * Builds the function that tells a person type from a tax id when the region does not publish one. Pass the length
26
+ * of the tax id per type, e.g. `personTypeByLength({ individual: 13, company: 12 })`. Without a function the regimes
27
+ * are not narrowed by person type (the server still checks the combination).
28
+ */
29
+ declare function personTypeByLength(lengths: Record<string, number>): (taxId: string) => string | null;
30
+ /** Regimes that fit a person type (all when the type is unknown). */
31
+ declare function regimesFor(fid: RegionFiscalId | undefined, personType: string | null): RegionFiscalEntry[];
32
+ /** Invoice uses a regime admits (all when no regime is chosen yet). */
33
+ declare function usesFor(fid: RegionFiscalId | undefined, regime: string | null | undefined): RegionFiscalEntry[];
34
+ type FiscalProblem = 'required' | 'format' | 'unknown' | 'person_type' | 'use_not_allowed';
35
+ /** Client-side check of the whole form against the region; the server stays the authority. */
36
+ declare function validateFiscalValues(region: FiscalRegion, v: Partial<FiscalFieldValues>, personTypeOf?: (taxId: string) => string | null): Partial<Record<FiscalFieldName, FiscalProblem>>;
37
+ /** Form values -> the API's `InvoiceRequest` (without `document`). */
38
+ declare function toInvoiceRequest(v: Partial<FiscalFieldValues>, countryCode?: string): InvoiceRequest;
39
+ /** `label_en` for English locales when the region has it. */
40
+ declare function entryLabel(e: RegionFiscalEntry, locale?: string | null): string;
41
+
42
+ /** Texts of the fiscal components. Spanish (es-MX) by default, English with `en*`, any locale with `messages`. */
43
+
44
+ type DeepPartial<T> = {
45
+ [K in keyof T]?: T[K] extends Record<string, unknown> ? DeepPartial<T[K]> : T[K];
46
+ };
47
+ type FiscalMessages = {
48
+ fields: {
49
+ legend: string;
50
+ taxId: string;
51
+ taxIdHint: string;
52
+ legalName: string;
53
+ /** Used when the region publishes no help for the legal name. */
54
+ legalNameHint: string;
55
+ postalCode: string;
56
+ postalCodeHint: string;
57
+ regime: string;
58
+ regimeHint: string;
59
+ regimeChoose: string;
60
+ regimeFromDocument: string;
61
+ use: string;
62
+ useHint: string;
63
+ useChoose: string;
64
+ /** `{document}` = the document's name. */
65
+ fromDocument: string;
66
+ errors: {
67
+ required: string;
68
+ taxIdFormat: string;
69
+ postalFormat: string;
70
+ unknown: string;
71
+ personType: string;
72
+ useNotAllowed: string;
73
+ };
74
+ };
75
+ reader: {
76
+ /** `{document}`. */
77
+ title: string;
78
+ dropHint: string;
79
+ dropActive: string;
80
+ choose: string;
81
+ obtain: string;
82
+ privacyBrowser: string;
83
+ privacyServer: string;
84
+ uploadServer: string;
85
+ manual: string;
86
+ reading: string;
87
+ cancel: string;
88
+ done: string;
89
+ reviewTitle: string;
90
+ reviewHint: string;
91
+ confirm: string;
92
+ changeFile: string;
93
+ saveToAccount: string;
94
+ saveConsent: string;
95
+ warnings: {
96
+ qrMismatch: string;
97
+ stale: string;
98
+ regimeMissing: string;
99
+ fieldsMissing: string;
100
+ };
101
+ errors: Record<FiscalReadError, string>;
102
+ summaryTitleOne: string;
103
+ summaryTitleMany: string;
104
+ };
105
+ toggle: {
106
+ label: string;
107
+ payDefault: string;
108
+ payAndInvoice: string;
109
+ profileTitle: string;
110
+ change: string;
111
+ useOther: string;
112
+ useSaved: string;
113
+ manualTitle: string;
114
+ unavailable: string;
115
+ privacy: string;
116
+ fieldsOf: {
117
+ taxId: string;
118
+ legalName: string;
119
+ postalCode: string;
120
+ regime: string;
121
+ use: string;
122
+ };
123
+ };
124
+ status: {
125
+ title: string;
126
+ request: string;
127
+ requestHelp: string;
128
+ awaitingTitle: string;
129
+ awaitingBody: string;
130
+ processingTitle: string;
131
+ processingBody: string;
132
+ processingSlow: string;
133
+ refresh: string;
134
+ issuedTitle: string;
135
+ issuedBody: string;
136
+ folio: string;
137
+ pdf: string;
138
+ xml: string;
139
+ needsDataTitle: string;
140
+ needsDataBody: string;
141
+ correct: string;
142
+ reviewTitle: string;
143
+ reviewBody: string;
144
+ contact: string;
145
+ contactBy: string;
146
+ windowTitle: string;
147
+ windowBody: string;
148
+ unavailableTitle: string;
149
+ unavailableBody: string;
150
+ cancelledTitle: string;
151
+ cancelledBody: string;
152
+ /** `reason_code` -> cause for the buyer. `default` when unknown. */
153
+ reasons: Record<string, string>;
154
+ };
155
+ server: {
156
+ errors: Record<string, string>;
157
+ };
158
+ };
159
+ /** Messages for a locale (`es*` default, `en*`), with optional overrides (merged level by level). */
160
+ declare function fiscalMessages(locale?: string | null, overrides?: DeepPartial<FiscalMessages> | null): FiscalMessages;
161
+
162
+ type FiscalIdentityFieldsClassNames = CheckoutFieldClassNames & Partial<Record<'fieldset' | 'legend' | 'mark' | 'radios' | 'radio', string>>;
163
+ type FiscalIdentityFieldsProps = {
164
+ region: FiscalRegion;
165
+ /** Initial values (and, when they change, the new values: e.g. after a document is read). */
166
+ values?: Partial<FiscalFieldValues>;
167
+ onChange?: (values: FiscalFieldValues) => void;
168
+ /** Fields that were filled from a document: they get the "From your {document}" mark and stay editable. */
169
+ fromDocument?: readonly FiscalFieldName[];
170
+ /** Short noun of the document for the mark ("constancia"). Default: nothing specific ("tu documento"). */
171
+ documentName?: string;
172
+ /** The document listed these regimes: show only them, as radios. */
173
+ regimeCandidates?: readonly string[];
174
+ /** Errors by control name (`invoice.tax_regime`), from the server or `useFieldErrors`. */
175
+ errors?: FieldErrors;
176
+ namePrefix?: string;
177
+ /** Prefix of the control ids (default: generated). */
178
+ idPrefix?: string;
179
+ /** Tells a person type from a tax id, to narrow the regimes (`personTypeByLength`). */
180
+ personTypeOf?: (taxId: string) => string | null;
181
+ disabled?: boolean;
182
+ locale?: string;
183
+ messages?: DeepPartial<FiscalMessages>;
184
+ classNames?: FiscalIdentityFieldsClassNames;
185
+ /** Hides the fieldset legend (when the caller already has a heading). */
186
+ hideLegend?: boolean;
187
+ };
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;
189
+
190
+ type FiscalReaderResult = {
191
+ values: FiscalFieldValues;
192
+ /** Where the data came from; `null` when the buyer typed everything. */
193
+ evidence: FiscalDocumentEvidence | null;
194
+ /** The buyer asked to save the data to their account (`canSave`). */
195
+ save: boolean;
196
+ };
197
+ type IdentityDocumentReaderClassNames = FiscalIdentityFieldsClassNames & Partial<Record<'root' | 'zone' | 'zoneActive' | 'button' | 'link' | 'privacy' | 'status' | 'error' | 'warning' | 'notice' | 'actions' | 'primary' | 'secondary' | 'summary', string>>;
198
+ type IdentityDocumentReaderProps = {
199
+ region: FiscalRegion;
200
+ /** The document to read. Default: the first of `region.fiscal_id.documents`. */
201
+ document?: IdentityDocumentSpec;
202
+ /**
203
+ * URL of the pdf.js worker (`pdf.worker.mjs` from `pdfjs-dist/legacy/build`) that YOUR site serves. There is no
204
+ * default and no CDN: without it the browser cannot read the file and the buyer is sent to manual entry.
205
+ */
206
+ workerSrc?: string;
207
+ /** The buyer confirmed the reviewed data. */
208
+ onConfirm: (result: FiscalReaderResult) => void;
209
+ /** The buyer chose to type their data. Default: the review form opens empty. */
210
+ onManual?: () => void;
211
+ /** Values to start the review with (e.g. a saved profile). */
212
+ initialValues?: Partial<FiscalFieldValues>;
213
+ /** Result of the server (no-JS upload): when it carries an `extraction` or an error, it is shown. */
214
+ data?: FiscalActionData | null;
215
+ /** The shop has a signed-in buyer: offer "Save to my account". */
216
+ canSave?: boolean;
217
+ /** Enables the no-JS upload (a button that posts the file to the action with `intent=extract-document`). */
218
+ serverUpload?: boolean;
219
+ /** Short noun of the document for texts ("constancia"). Default: the spec's label in lowercase. */
220
+ documentName?: string;
221
+ personTypeOf?: (taxId: string) => string | null;
222
+ /** Clock for tests. */
223
+ now?: () => Date;
224
+ namePrefix?: string;
225
+ locale?: string;
226
+ messages?: DeepPartial<FiscalMessages>;
227
+ classNames?: IdentityDocumentReaderClassNames;
228
+ /** Label of the confirm button. */
229
+ confirmLabel?: ReactNode;
230
+ };
231
+ declare function IdentityDocumentReader(props: IdentityDocumentReaderProps): react.JSX.Element | null;
232
+
233
+ type InvoiceToggleState = {
234
+ requested: boolean;
235
+ /** The data to send as `CheckoutInput.invoice` / `carts.setInvoice`; `null` when none is requested or it is not ready. */
236
+ invoice: InvoiceRequest | null;
237
+ /** All the data is there and valid for the region (the server still checks it). */
238
+ ready: boolean;
239
+ source: 'profile' | 'document' | 'manual' | null;
240
+ /** "Pay" or "Pay and invoice": the label for the pay button. */
241
+ payLabel: string;
242
+ };
243
+ type InvoiceToggleClassNames = IdentityDocumentReaderClassNames & Partial<Record<'toggle' | 'body' | 'card' | 'cardRow' | 'cardTitle' | 'unavailable', string>>;
244
+ type InvoiceToggleProps = {
245
+ region: FiscalRegion & {
246
+ country_code?: string;
247
+ };
248
+ /** `loadFiscalContext(...).invoicing`. `available: false` or `checkout: 'off'` renders nothing. */
249
+ capabilities?: InvoicingCapabilities | null;
250
+ /** The buyer's saved fiscal data (`customer.fiscal`). */
251
+ profile?: FiscalIdentity | null;
252
+ defaultRequested?: boolean;
253
+ onChange?: (state: InvoiceToggleState) => void;
254
+ /** Result of the shop's action (server errors by field, a document read without JS). */
255
+ data?: FiscalActionData | null;
256
+ /** The buyer is signed in: they can save the data to their account. */
257
+ canSave?: boolean;
258
+ workerSrc?: string;
259
+ /** Enables the no-JS document upload. */
260
+ serverUpload?: boolean;
261
+ /** Link (e.g. `?invoice=1`) that opens the section when JavaScript is not available. */
262
+ noJsHref?: string;
263
+ document?: IdentityDocumentSpec;
264
+ documentName?: string;
265
+ personTypeOf?: (taxId: string) => string | null;
266
+ /** Label of the pay button when no invoice is asked. Default from the messages. */
267
+ payLabel?: string;
268
+ namePrefix?: string;
269
+ locale?: string;
270
+ messages?: DeepPartial<FiscalMessages>;
271
+ classNames?: InvoiceToggleClassNames;
272
+ now?: () => Date;
273
+ };
274
+ declare function InvoiceToggle(props: InvoiceToggleProps): react.JSX.Element | null;
275
+
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;
279
+ type InvoiceStatusCardClassNames = Partial<Record<'root' | 'title' | 'body' | 'actions' | 'primary' | 'secondary' | 'link' | 'meta', string>>;
280
+ type InvoiceStatusCardProps = {
281
+ invoice?: InvoiceSummary | null;
282
+ /** `capabilities.invoicing.available`. `false`: "Invoice not available". */
283
+ available?: boolean;
284
+ /** The buyer taps "Request invoice". Shown when `invoice.can_request !== false`. Without it, `requestHref` is a link. */
285
+ onRequest?: () => void;
286
+ requestHref?: string;
287
+ /** "Fix and retry". Without it, `correctHref` is a link. */
288
+ onCorrect?: () => void;
289
+ correctHref?: string;
290
+ /** Called while the invoice is processing (every `refreshMs`, for at most `refreshForMs`). Reload the order there. */
291
+ onRefresh?: () => void;
292
+ refreshMs?: number;
293
+ refreshForMs?: number;
294
+ /** How to reach the store when it must review: an email, a phone or a URL. */
295
+ contact?: {
296
+ email?: string;
297
+ phone?: string;
298
+ url?: string;
299
+ };
300
+ locale?: string;
301
+ messages?: DeepPartial<FiscalMessages>;
302
+ classNames?: InvoiceStatusCardClassNames;
303
+ /** Heading level of the title (default 3). */
304
+ headingLevel?: 2 | 3 | 4;
305
+ };
306
+ declare function InvoiceStatusCard(props: InvoiceStatusCardProps): react.JSX.Element;
307
+
308
+ /** Turns what the engine read into what the UI shows. Shared by the browser reader and the server upload. */
309
+
310
+ /** `evidence` comes from `buildDocumentEvidence`. Only the conventional fields are kept: nothing else can leak. */
311
+ declare function summarizeExtraction(x: IdentityExtraction, evidence: FiscalDocumentEvidence, validRegimes?: Iterable<string>): FiscalExtractionSummary;
312
+
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 };