@asteby/storefront-react 0.17.0 → 0.19.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/README.md +19 -0
- package/dist/account.cjs +114 -0
- package/dist/account.cjs.map +1 -1
- package/dist/account.d.cts +60 -4
- package/dist/account.d.ts +60 -4
- package/dist/account.js +113 -1
- package/dist/account.js.map +1 -1
- package/dist/checkout.cjs +65 -14
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +7 -0
- package/dist/checkout.d.ts +7 -0
- package/dist/checkout.js +65 -14
- package/dist/checkout.js.map +1 -1
- package/dist/payments.cjs +86 -15
- package/dist/payments.cjs.map +1 -1
- package/dist/payments.css +65 -0
- package/dist/payments.d.cts +24 -3
- package/dist/payments.d.ts +24 -3
- package/dist/payments.js +86 -15
- package/dist/payments.js.map +1 -1
- package/package.json +2 -2
package/dist/payments.css
CHANGED
|
@@ -87,3 +87,68 @@
|
|
|
87
87
|
flex-wrap: wrap;
|
|
88
88
|
gap: 0.5rem;
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* 3DS challenge (`<PaymentChallenge>`): a near full-screen modal. Colors are fixed on purpose: the bank page inside
|
|
93
|
+
* the iframe is always white, and the dialog often lives in a themed (dark) panel. Override with a more specific rule.
|
|
94
|
+
*/
|
|
95
|
+
dialog[data-sf-challenge] {
|
|
96
|
+
margin: auto;
|
|
97
|
+
box-sizing: border-box;
|
|
98
|
+
width: min(60rem, calc(100% - 2rem));
|
|
99
|
+
max-width: none;
|
|
100
|
+
max-height: 94dvh;
|
|
101
|
+
overflow: auto;
|
|
102
|
+
border: 1px solid #c9d2ee;
|
|
103
|
+
border-radius: 0.75rem;
|
|
104
|
+
background: #ffffff;
|
|
105
|
+
color: #0b1220;
|
|
106
|
+
/* Claro aunque la página esté en oscuro: barras de desplazamiento y controles del navegador sobre fondo blanco. */
|
|
107
|
+
color-scheme: light;
|
|
108
|
+
padding: 1.25rem;
|
|
109
|
+
}
|
|
110
|
+
dialog[data-sf-challenge]::backdrop {
|
|
111
|
+
background: rgb(0 8 31 / 0.72);
|
|
112
|
+
}
|
|
113
|
+
dialog[data-sf-challenge] h2 {
|
|
114
|
+
margin: 0 0 0.75rem;
|
|
115
|
+
font-weight: 800;
|
|
116
|
+
color: #001963;
|
|
117
|
+
}
|
|
118
|
+
dialog[data-sf-challenge] h2:focus {
|
|
119
|
+
outline: none;
|
|
120
|
+
}
|
|
121
|
+
dialog[data-sf-challenge] [data-sf-challenge-frame] {
|
|
122
|
+
display: block;
|
|
123
|
+
height: min(70dvh, 40rem);
|
|
124
|
+
background: #ffffff;
|
|
125
|
+
}
|
|
126
|
+
dialog[data-sf-challenge] [data-sf-challenge-escape] {
|
|
127
|
+
margin-top: 0.75rem;
|
|
128
|
+
font-size: 0.875rem;
|
|
129
|
+
}
|
|
130
|
+
dialog[data-sf-challenge] [data-sf-challenge-escape]:empty {
|
|
131
|
+
margin: 0;
|
|
132
|
+
}
|
|
133
|
+
dialog[data-sf-challenge] [data-sf-challenge-escape] button {
|
|
134
|
+
margin-top: 0.5rem;
|
|
135
|
+
padding: 0 1rem;
|
|
136
|
+
background: #ffffff;
|
|
137
|
+
color: #0b1220;
|
|
138
|
+
border: 1px solid #8a94b3;
|
|
139
|
+
border-radius: 0.5rem;
|
|
140
|
+
font-weight: 600;
|
|
141
|
+
}
|
|
142
|
+
@media (max-width: 40rem) {
|
|
143
|
+
dialog[data-sf-challenge] {
|
|
144
|
+
width: 100%;
|
|
145
|
+
height: 100dvh;
|
|
146
|
+
max-height: 100dvh;
|
|
147
|
+
border-radius: 0;
|
|
148
|
+
border: 0;
|
|
149
|
+
padding: 1rem;
|
|
150
|
+
}
|
|
151
|
+
dialog[data-sf-challenge] [data-sf-challenge-frame] {
|
|
152
|
+
height: calc(100dvh - 8rem);
|
|
153
|
+
}
|
|
154
|
+
}
|
package/dist/payments.d.cts
CHANGED
|
@@ -226,6 +226,14 @@ type EmbeddedPaymentState = {
|
|
|
226
226
|
retry: () => Promise<void>;
|
|
227
227
|
/** After a rejection: clears the message (the form is remounted by the hook). */
|
|
228
228
|
dismiss: () => void;
|
|
229
|
+
/**
|
|
230
|
+
* Leaves a pending 3DS challenge (the buyer's emergency exit). The outcome is UNKNOWN (the bank may still approve the
|
|
231
|
+
* attempt the buyer just verified), so the attempt key is kept and no new payment can start: the hook verifies the
|
|
232
|
+
* payment state through `transport.refresh` (status `blocked`, `error.kind = 'payment_in_progress'`, `verifying`).
|
|
233
|
+
* Only a definitive answer settles it: approved, or rejected / expired / cancelled, which gives a new attempt and a
|
|
234
|
+
* fresh form. A still-pending challenge does not reopen the dialog.
|
|
235
|
+
*/
|
|
236
|
+
cancelChallenge: () => void;
|
|
229
237
|
};
|
|
230
238
|
/**
|
|
231
239
|
* Embedded payment state machine for one card form.
|
|
@@ -256,10 +264,20 @@ type PaymentChallengeProps = {
|
|
|
256
264
|
messages?: Partial<PaymentMessages>;
|
|
257
265
|
/** Replace the default iframe (e.g. mount the provider's status screen). */
|
|
258
266
|
render?: (outcome: PaymentOutcome) => ReactNode;
|
|
267
|
+
/**
|
|
268
|
+
* The buyer's emergency exit. The dialog is NOT dismissible (no Esc, no backdrop click) while the payment is in
|
|
269
|
+
* progress; this button only appears after `escapeAfterMs`, so a stuck bank page never traps the buyer (WCAG 2.2.1).
|
|
270
|
+
*/
|
|
259
271
|
onCancel?: () => void;
|
|
272
|
+
/** How long the dialog stays locked before the exit shows. Default 120000. */
|
|
273
|
+
escapeAfterMs?: number;
|
|
260
274
|
};
|
|
261
|
-
/**
|
|
262
|
-
|
|
275
|
+
/**
|
|
276
|
+
* 3DS inside the page: a near full-screen modal dialog (`showModal()`: focus trap, inert page) with an accessible title.
|
|
277
|
+
* Esc and backdrop clicks do nothing until the payment ends (the owner unmounts it). Default content is the bank's
|
|
278
|
+
* https iframe. Layout comes from `payments.css` (`dialog[data-sf-challenge]`), overridable with your own CSS.
|
|
279
|
+
*/
|
|
280
|
+
declare function PaymentChallenge({ outcome, locale, messages, render, onCancel, escapeAfterMs }: PaymentChallengeProps): react.JSX.Element;
|
|
263
281
|
type PaymentBrickHandle = EmbeddedPaymentState;
|
|
264
282
|
type PaymentBrickProps = Omit<UseEmbeddedPaymentOptions, 'amount'> & {
|
|
265
283
|
/** The server's total. Shown on the button and passed to the provider widget. */
|
|
@@ -494,6 +512,8 @@ type MercadoPagoAdapterOptions = {
|
|
|
494
512
|
getSdk?: () => MercadoPagoCtor | undefined;
|
|
495
513
|
/** Reads the anti-fraud device id. Default: `window.MP_DEVICE_SESSION_ID`. */
|
|
496
514
|
getDeviceSessionId?: () => string | undefined;
|
|
515
|
+
/** Wait before the single internal re-read of the form data (see `collect`). Default 400. */
|
|
516
|
+
collectRetryDelayMs?: number;
|
|
497
517
|
};
|
|
498
518
|
/**
|
|
499
519
|
* The only fields that may leave the browser, and the only place that decides it. Anything else the SDK returns
|
|
@@ -502,7 +522,8 @@ type MercadoPagoAdapterOptions = {
|
|
|
502
522
|
declare function sanitizeMercadoPagoFormData(data: Record<string, unknown> | null | undefined): Record<string, unknown>;
|
|
503
523
|
/**
|
|
504
524
|
* Card Payment Brick adapter. The payment button is hidden: the shop's own button calls `collect()` (MP's
|
|
505
|
-
* `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code.
|
|
525
|
+
* `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code. `collect()` re-reads the
|
|
526
|
+
* form once if the first read fails, before anything is sent to the shop's server.
|
|
506
527
|
*/
|
|
507
528
|
declare function mercadoPagoBricksAdapter(options?: MercadoPagoAdapterOptions): PaymentFormAdapter;
|
|
508
529
|
|
package/dist/payments.d.ts
CHANGED
|
@@ -226,6 +226,14 @@ type EmbeddedPaymentState = {
|
|
|
226
226
|
retry: () => Promise<void>;
|
|
227
227
|
/** After a rejection: clears the message (the form is remounted by the hook). */
|
|
228
228
|
dismiss: () => void;
|
|
229
|
+
/**
|
|
230
|
+
* Leaves a pending 3DS challenge (the buyer's emergency exit). The outcome is UNKNOWN (the bank may still approve the
|
|
231
|
+
* attempt the buyer just verified), so the attempt key is kept and no new payment can start: the hook verifies the
|
|
232
|
+
* payment state through `transport.refresh` (status `blocked`, `error.kind = 'payment_in_progress'`, `verifying`).
|
|
233
|
+
* Only a definitive answer settles it: approved, or rejected / expired / cancelled, which gives a new attempt and a
|
|
234
|
+
* fresh form. A still-pending challenge does not reopen the dialog.
|
|
235
|
+
*/
|
|
236
|
+
cancelChallenge: () => void;
|
|
229
237
|
};
|
|
230
238
|
/**
|
|
231
239
|
* Embedded payment state machine for one card form.
|
|
@@ -256,10 +264,20 @@ type PaymentChallengeProps = {
|
|
|
256
264
|
messages?: Partial<PaymentMessages>;
|
|
257
265
|
/** Replace the default iframe (e.g. mount the provider's status screen). */
|
|
258
266
|
render?: (outcome: PaymentOutcome) => ReactNode;
|
|
267
|
+
/**
|
|
268
|
+
* The buyer's emergency exit. The dialog is NOT dismissible (no Esc, no backdrop click) while the payment is in
|
|
269
|
+
* progress; this button only appears after `escapeAfterMs`, so a stuck bank page never traps the buyer (WCAG 2.2.1).
|
|
270
|
+
*/
|
|
259
271
|
onCancel?: () => void;
|
|
272
|
+
/** How long the dialog stays locked before the exit shows. Default 120000. */
|
|
273
|
+
escapeAfterMs?: number;
|
|
260
274
|
};
|
|
261
|
-
/**
|
|
262
|
-
|
|
275
|
+
/**
|
|
276
|
+
* 3DS inside the page: a near full-screen modal dialog (`showModal()`: focus trap, inert page) with an accessible title.
|
|
277
|
+
* Esc and backdrop clicks do nothing until the payment ends (the owner unmounts it). Default content is the bank's
|
|
278
|
+
* https iframe. Layout comes from `payments.css` (`dialog[data-sf-challenge]`), overridable with your own CSS.
|
|
279
|
+
*/
|
|
280
|
+
declare function PaymentChallenge({ outcome, locale, messages, render, onCancel, escapeAfterMs }: PaymentChallengeProps): react.JSX.Element;
|
|
263
281
|
type PaymentBrickHandle = EmbeddedPaymentState;
|
|
264
282
|
type PaymentBrickProps = Omit<UseEmbeddedPaymentOptions, 'amount'> & {
|
|
265
283
|
/** The server's total. Shown on the button and passed to the provider widget. */
|
|
@@ -494,6 +512,8 @@ type MercadoPagoAdapterOptions = {
|
|
|
494
512
|
getSdk?: () => MercadoPagoCtor | undefined;
|
|
495
513
|
/** Reads the anti-fraud device id. Default: `window.MP_DEVICE_SESSION_ID`. */
|
|
496
514
|
getDeviceSessionId?: () => string | undefined;
|
|
515
|
+
/** Wait before the single internal re-read of the form data (see `collect`). Default 400. */
|
|
516
|
+
collectRetryDelayMs?: number;
|
|
497
517
|
};
|
|
498
518
|
/**
|
|
499
519
|
* The only fields that may leave the browser, and the only place that decides it. Anything else the SDK returns
|
|
@@ -502,7 +522,8 @@ type MercadoPagoAdapterOptions = {
|
|
|
502
522
|
declare function sanitizeMercadoPagoFormData(data: Record<string, unknown> | null | undefined): Record<string, unknown>;
|
|
503
523
|
/**
|
|
504
524
|
* Card Payment Brick adapter. The payment button is hidden: the shop's own button calls `collect()` (MP's
|
|
505
|
-
* `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code.
|
|
525
|
+
* `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code. `collect()` re-reads the
|
|
526
|
+
* form once if the first read fails, before anything is sent to the shop's server.
|
|
506
527
|
*/
|
|
507
528
|
declare function mercadoPagoBricksAdapter(options?: MercadoPagoAdapterOptions): PaymentFormAdapter;
|
|
508
529
|
|
package/dist/payments.js
CHANGED
|
@@ -84,6 +84,7 @@ function sanitizeMercadoPagoFormData(data) {
|
|
|
84
84
|
function mercadoPagoBricksAdapter(options = {}) {
|
|
85
85
|
const allowed = options.allowedSdkOrigins ?? ["https://sdk.mercadopago.com"];
|
|
86
86
|
const getSdk = options.getSdk ?? (() => typeof window !== "undefined" ? window.MercadoPago : void 0);
|
|
87
|
+
const retryDelay = options.collectRetryDelayMs ?? 400;
|
|
87
88
|
const getDevice = options.getDeviceSessionId ?? (() => typeof window !== "undefined" ? window.MP_DEVICE_SESSION_ID : void 0);
|
|
88
89
|
return {
|
|
89
90
|
kind: MERCADOPAGO_BRICKS_KIND,
|
|
@@ -125,9 +126,21 @@ function mercadoPagoBricksAdapter(options = {}) {
|
|
|
125
126
|
return {
|
|
126
127
|
async collect() {
|
|
127
128
|
if (gone) throw new Error("payment form is unmounted");
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
const read = async () => {
|
|
130
|
+
const raw = await controller.getFormData();
|
|
131
|
+
const data = sanitizeMercadoPagoFormData(raw);
|
|
132
|
+
if (!data.token) throw new Error("payment form incomplete");
|
|
133
|
+
return data;
|
|
134
|
+
};
|
|
135
|
+
let provider_data;
|
|
136
|
+
try {
|
|
137
|
+
provider_data = await read();
|
|
138
|
+
} catch (first) {
|
|
139
|
+
if (gone) throw first;
|
|
140
|
+
await new Promise((r) => setTimeout(r, retryDelay));
|
|
141
|
+
if (gone) throw first;
|
|
142
|
+
provider_data = await read();
|
|
143
|
+
}
|
|
131
144
|
const device = getDevice();
|
|
132
145
|
return { provider_data, ...typeof device === "string" && device ? { device_session_id: device } : {} };
|
|
133
146
|
},
|
|
@@ -485,7 +498,7 @@ function useEmbeddedPayment(options) {
|
|
|
485
498
|
autoRetries = 2,
|
|
486
499
|
retryDelayMs = 600,
|
|
487
500
|
pollIntervalMs = 2e3,
|
|
488
|
-
pollTimeoutMs =
|
|
501
|
+
pollTimeoutMs = 3e5,
|
|
489
502
|
verifyTimeoutMs = 12e4,
|
|
490
503
|
verifyIntervalMs = 2e3,
|
|
491
504
|
scope = "default"
|
|
@@ -514,6 +527,7 @@ function useEmbeddedPayment(options) {
|
|
|
514
527
|
const alive = useRef(true);
|
|
515
528
|
const generation = useRef(0);
|
|
516
529
|
const statusRef = useRef("idle");
|
|
530
|
+
const leftChallenge = useRef(false);
|
|
517
531
|
statusRef.current = status;
|
|
518
532
|
errorRef.current = error;
|
|
519
533
|
const amountKey = `${amount.amount}|${amount.currency_code}`;
|
|
@@ -697,6 +711,7 @@ function useEmbeddedPayment(options) {
|
|
|
697
711
|
(result) => {
|
|
698
712
|
const o = paymentOutcome(result, live.current.locale, live.current.messages);
|
|
699
713
|
pendingData.current = null;
|
|
714
|
+
leftChallenge.current = false;
|
|
700
715
|
setOutcome(o);
|
|
701
716
|
setError(null);
|
|
702
717
|
setAttemptsLeft(o.attempts_left);
|
|
@@ -781,15 +796,21 @@ function useEmbeddedPayment(options) {
|
|
|
781
796
|
setError(null);
|
|
782
797
|
setOutcome(null);
|
|
783
798
|
emit({ type: "submit" });
|
|
799
|
+
const withdrawn = () => !alive.current || form.current !== m;
|
|
800
|
+
const settle = () => {
|
|
801
|
+
if (alive.current) setStatus((s) => s === "processing" ? "idle" : s);
|
|
802
|
+
};
|
|
784
803
|
let data;
|
|
785
804
|
try {
|
|
786
805
|
data = await m.collect();
|
|
787
806
|
} catch {
|
|
807
|
+
if (withdrawn()) return settle();
|
|
788
808
|
emit({ type: "tokenize_error" });
|
|
789
809
|
setError({ kind: "generic", message: live.current.msgs["error.card_data"], retrySameAttempt: false, canRetry: true });
|
|
790
810
|
setStatus("ready");
|
|
791
811
|
return;
|
|
792
812
|
}
|
|
813
|
+
if (withdrawn()) return settle();
|
|
793
814
|
const attempt = readAttempt();
|
|
794
815
|
setAttemptId(attempt);
|
|
795
816
|
await send(data, attempt, total);
|
|
@@ -857,7 +878,7 @@ function useEmbeddedPayment(options) {
|
|
|
857
878
|
}
|
|
858
879
|
let stop = false;
|
|
859
880
|
const ctl = new AbortController();
|
|
860
|
-
const until = Date.now() + verifyTimeoutMs;
|
|
881
|
+
const until = Date.now() + (leftChallenge.current ? Math.max(verifyTimeoutMs, pollTimeoutMs) : verifyTimeoutMs);
|
|
861
882
|
setVerifying(true);
|
|
862
883
|
(async () => {
|
|
863
884
|
let wait = verifyIntervalMs;
|
|
@@ -869,6 +890,8 @@ function useEmbeddedPayment(options) {
|
|
|
869
890
|
const r = await transport.refresh({ signal: ctl.signal });
|
|
870
891
|
if (stop || !alive.current) return;
|
|
871
892
|
if (isResolvedAttempt(r)) {
|
|
893
|
+
const settled = r.payment.status === "paid" || r.payment.status === "failed" || r.payment.status === "expired" || r.payment.status === "cancelled";
|
|
894
|
+
if (leftChallenge.current && !settled && r.payment.action?.type === "challenge") continue;
|
|
872
895
|
setVerifying(false);
|
|
873
896
|
finish(r);
|
|
874
897
|
return;
|
|
@@ -883,11 +906,18 @@ function useEmbeddedPayment(options) {
|
|
|
883
906
|
ctl.abort();
|
|
884
907
|
setVerifying(false);
|
|
885
908
|
};
|
|
886
|
-
}, [unknownOutcome, transport, verifyTimeoutMs, verifyIntervalMs, finish]);
|
|
909
|
+
}, [unknownOutcome, transport, verifyTimeoutMs, verifyIntervalMs, pollTimeoutMs, finish]);
|
|
887
910
|
const dismiss = useCallback(() => {
|
|
888
911
|
setError(null);
|
|
889
912
|
setOutcome((o) => o?.kind === "rejected" ? null : o);
|
|
890
913
|
}, []);
|
|
914
|
+
const cancelChallenge = useCallback(() => {
|
|
915
|
+
if (statusRef.current !== "challenge") return;
|
|
916
|
+
leftChallenge.current = true;
|
|
917
|
+
setOutcome(null);
|
|
918
|
+
setError({ kind: "payment_in_progress", message: live.current.msgs["challenge.left"], retrySameAttempt: false, canRetry: false });
|
|
919
|
+
setStatus("blocked");
|
|
920
|
+
}, []);
|
|
891
921
|
const message = status === "processing" ? msgs["state.processing"] : status === "fallback" ? msgs["state.fallback"] : error?.message ?? outcome?.message ?? (status === "loading" ? msgs["state.loading"] : null);
|
|
892
922
|
return {
|
|
893
923
|
status,
|
|
@@ -903,7 +933,8 @@ function useEmbeddedPayment(options) {
|
|
|
903
933
|
containerId,
|
|
904
934
|
submit,
|
|
905
935
|
retry,
|
|
906
|
-
dismiss
|
|
936
|
+
dismiss,
|
|
937
|
+
cancelChallenge
|
|
907
938
|
};
|
|
908
939
|
}
|
|
909
940
|
function VoucherCard({ outcome, locale, messages, className }) {
|
|
@@ -940,15 +971,55 @@ function VoucherCard({ outcome, locale, messages, className }) {
|
|
|
940
971
|
/* @__PURE__ */ jsx("p", { children: m["voucher.email"] })
|
|
941
972
|
] });
|
|
942
973
|
}
|
|
943
|
-
function PaymentChallenge({ outcome, locale, messages, render, onCancel }) {
|
|
974
|
+
function PaymentChallenge({ outcome, locale, messages, render, onCancel, escapeAfterMs = 12e4 }) {
|
|
944
975
|
const m = paymentMessages(locale, messages);
|
|
945
|
-
const { ref } = useModalDialog({ open: true, onClose: () =>
|
|
976
|
+
const { ref } = useModalDialog({ open: true, onClose: () => {
|
|
977
|
+
} });
|
|
978
|
+
const [canEscape, setCanEscape] = useState(false);
|
|
979
|
+
const [closed, setClosed] = useState(false);
|
|
980
|
+
const cancelRef = useRef(onCancel);
|
|
981
|
+
cancelRef.current = onCancel;
|
|
982
|
+
const hasCancel = !!onCancel;
|
|
983
|
+
useEffect(() => {
|
|
984
|
+
if (!hasCancel) return;
|
|
985
|
+
const t = setTimeout(() => setCanEscape(true), escapeAfterMs);
|
|
986
|
+
return () => clearTimeout(t);
|
|
987
|
+
}, [hasCancel, escapeAfterMs]);
|
|
988
|
+
useEffect(() => {
|
|
989
|
+
const el = ref.current;
|
|
990
|
+
if (!el) return;
|
|
991
|
+
const onClosed = () => setClosed(true);
|
|
992
|
+
el.addEventListener("close", onClosed);
|
|
993
|
+
return () => el.removeEventListener("close", onClosed);
|
|
994
|
+
}, [ref]);
|
|
995
|
+
const reopen = () => {
|
|
996
|
+
const el = ref.current;
|
|
997
|
+
if (!el) return;
|
|
998
|
+
try {
|
|
999
|
+
if (typeof el.showModal === "function") el.showModal();
|
|
1000
|
+
else el.setAttribute("open", "");
|
|
1001
|
+
} catch {
|
|
1002
|
+
el.setAttribute("open", "");
|
|
1003
|
+
}
|
|
1004
|
+
setClosed(false);
|
|
1005
|
+
el.querySelector("[data-sf-autofocus]")?.focus({ preventScroll: true });
|
|
1006
|
+
};
|
|
946
1007
|
const url = outcome.challenge?.url;
|
|
947
|
-
return /* @__PURE__ */
|
|
948
|
-
/* @__PURE__ */
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1008
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1009
|
+
closed && /* @__PURE__ */ jsxs("p", { role: "status", "data-sf-challenge-closed": true, children: [
|
|
1010
|
+
m["state.challenge"],
|
|
1011
|
+
" ",
|
|
1012
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: reopen, "data-sf-challenge-reopen": true, style: { minWidth: 44, minHeight: 44 }, children: m["challenge.title"] })
|
|
1013
|
+
] }),
|
|
1014
|
+
/* @__PURE__ */ jsx("dialog", { ref, "aria-labelledby": "sf-challenge-title", "data-sf-challenge": true, children: /* @__PURE__ */ jsxs("div", { "data-sf-challenge-body": true, children: [
|
|
1015
|
+
/* @__PURE__ */ jsx("h2", { id: "sf-challenge-title", "data-sf-autofocus": true, tabIndex: -1, children: m["challenge.title"] }),
|
|
1016
|
+
render ? render(outcome) : url ? /* @__PURE__ */ jsx("iframe", { src: url, title: m["challenge.title"], "data-sf-challenge-frame": true, style: { width: "100%", minHeight: 420, border: 0 } }) : /* @__PURE__ */ jsx("p", { children: m["state.challenge"] }),
|
|
1017
|
+
hasCancel && /* @__PURE__ */ jsx("div", { "data-sf-challenge-escape": true, "aria-live": "polite", children: canEscape && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1018
|
+
/* @__PURE__ */ jsx("p", { children: m["challenge.escape_hint"] }),
|
|
1019
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => cancelRef.current?.(), style: { minWidth: 44, minHeight: 44 }, children: m["challenge.escape"] })
|
|
1020
|
+
] }) })
|
|
1021
|
+
] }) })
|
|
1022
|
+
] });
|
|
952
1023
|
}
|
|
953
1024
|
var PaymentBrick = forwardRef(function PaymentBrick2(props, ref) {
|
|
954
1025
|
const { submitLabel, hideAmountInButton, renderVoucher, renderChallenge, minHeight = 360, className, style, ...hookOptions } = props;
|
|
@@ -986,7 +1057,7 @@ var PaymentBrick = forwardRef(function PaymentBrick2(props, ref) {
|
|
|
986
1057
|
state.status === "network_error" && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void state.retry(), style: { minHeight: 44 }, children: m["action.retry"] })
|
|
987
1058
|
] }) : /* @__PURE__ */ jsx("p", { role: "status", "aria-live": "polite", "data-sf-pay-message": true, children: state.message }),
|
|
988
1059
|
outcome?.kind === "voucher" && (renderVoucher ? renderVoucher(outcome) : /* @__PURE__ */ jsx(VoucherCard, { outcome, locale, ...props.messages ? { messages: props.messages } : {} })),
|
|
989
|
-
outcome?.kind === "challenge" && /* @__PURE__ */ jsx(PaymentChallenge, { outcome, locale, ...props.messages ? { messages: props.messages } : {}, ...renderChallenge ? { render: renderChallenge } : {} }),
|
|
1060
|
+
outcome?.kind === "challenge" && /* @__PURE__ */ jsx(PaymentChallenge, { outcome, locale, onCancel: state.cancelChallenge, ...props.messages ? { messages: props.messages } : {}, ...renderChallenge ? { render: renderChallenge } : {} }),
|
|
990
1061
|
submitLabel !== void 0 && showForm && /* @__PURE__ */ jsxs(
|
|
991
1062
|
"button",
|
|
992
1063
|
{
|