@openreceive/react 0.3.0 → 0.3.2

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/index.js CHANGED
@@ -1,15 +1,16 @@
1
1
  // src/checkout.ts
2
2
  import {
3
+ checkoutLabels as checkoutLabels6,
3
4
  createLightningInvoiceDecodeUrl as createLightningInvoiceDecodeUrl2,
4
5
  enterCheckoutResumePath,
5
6
  mergeAttemptIntoCheckout,
6
7
  mergeAttemptIntoSnapshot,
7
8
  OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES as OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3,
8
9
  OPENRECEIVE_DEFAULT_PREFIX,
9
- checkoutLabels as checkoutLabels6,
10
10
  orClasses as orClasses7,
11
11
  prepareCheckout,
12
12
  requestCheckout,
13
+ resumeSwapAttempt,
13
14
  validateCheckoutProps
14
15
  } from "@openreceive/browser/headless";
15
16
  import * as React10 from "react";
@@ -30,16 +31,23 @@ function useCheckoutSession(options) {
30
31
  reference: () => optionsRef.current.reference(),
31
32
  requestCheckout: (reference) => optionsRef.current.requestCheckout?.(reference),
32
33
  onSnapshot: (snapshot) => optionsRef.current.onSnapshot?.(snapshot),
33
- swapPrefix: () => optionsRef.current.swapPrefix?.(),
34
- fetch: () => optionsRef.current.fetch?.(),
35
- swapSelection: {
36
- started: () => optionsRef.current.swapSelection?.started(),
37
- setStarted: (invoice) => optionsRef.current.swapSelection?.setStarted(invoice),
38
- dismissedInvoiceId: () => optionsRef.current.swapSelection?.dismissedInvoiceId() ?? null,
39
- setDismissedInvoiceId: (invoiceId) => optionsRef.current.swapSelection?.setDismissedInvoiceId(invoiceId),
40
- setSelectedAsset: (payInAsset) => optionsRef.current.swapSelection?.setSelectedAsset(payInAsset)
34
+ // The inner `swap` is always present because the session is built once,
35
+ // on the first render, and the host may only gain swap options later.
36
+ // Every accessor reads through `optionsRef`, so a host with no `swap`
37
+ // makes `prefix()` answer undefined and the session reports the missing
38
+ // wiring instead of silently doing nothing.
39
+ swap: {
40
+ selection: {
41
+ started: () => optionsRef.current.swap?.selection.started(),
42
+ setStarted: (invoice) => optionsRef.current.swap?.selection.setStarted(invoice),
43
+ dismissedInvoiceId: () => optionsRef.current.swap?.selection.dismissedInvoiceId() ?? null,
44
+ setDismissedInvoiceId: (invoiceId) => optionsRef.current.swap?.selection.setDismissedInvoiceId(invoiceId),
45
+ setSelectedAsset: (payInAsset) => optionsRef.current.swap?.selection.setSelectedAsset(payInAsset)
46
+ },
47
+ prefix: () => optionsRef.current.swap?.prefix(),
48
+ fetch: () => optionsRef.current.swap?.fetch(),
49
+ onStarted: (invoice) => optionsRef.current.swap?.onStarted?.(invoice)
41
50
  },
42
- onSwapStarted: (invoice) => optionsRef.current.onSwapStarted?.(invoice),
43
51
  get logger() {
44
52
  return optionsRef.current.logger;
45
53
  },
@@ -56,7 +64,7 @@ import {
56
64
  OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES,
57
65
  copyInvoice as copyInvoiceHelper,
58
66
  createCheckoutStatusModel,
59
- createQrSvg,
67
+ createQrSvgController,
60
68
  formatAmountCaption,
61
69
  checkoutLabels,
62
70
  openWallet as openWalletHelper,
@@ -185,14 +193,15 @@ function QRCode(props) {
185
193
  const onErrorRef = React3.useRef(onError);
186
194
  onErrorRef.current = onError;
187
195
  React3.useEffect(() => {
188
- let cancelled = false;
189
- createQrSvg(invoice, { encoder, width }).then((nextSvg) => {
190
- if (!cancelled) setSvg(nextSvg);
191
- }).catch((error) => {
192
- if (!cancelled) onErrorRef.current?.(error);
196
+ const controller = createQrSvgController({
197
+ onValue: setSvg,
198
+ onError: (error) => onErrorRef.current?.(error),
199
+ ...encoder === void 0 ? {} : { encoder },
200
+ width
193
201
  });
202
+ controller.show(invoice);
194
203
  return () => {
195
- cancelled = true;
204
+ controller.stop();
196
205
  };
197
206
  }, [invoice, encoder, width]);
198
207
  return React3.createElement("div", {
@@ -421,106 +430,17 @@ function SatsDetail(props) {
421
430
  );
422
431
  }
423
432
 
424
- // src/transaction-details.ts
425
- import {
426
- checkoutLabels as checkoutLabels2,
427
- orClasses as orClasses2,
428
- resolveTransactionDetailRows
429
- } from "@openreceive/browser/headless";
430
- import * as React4 from "react";
431
- function TransactionDetails(props) {
432
- const rows = resolveTransactionDetailRows(props.state);
433
- if (rows.length === 0) return null;
434
- return React4.createElement(
435
- "details",
436
- {
437
- className: joinClassNames(orClasses2.transactionDetails, props.className),
438
- open: props.open === true ? true : void 0
439
- },
440
- React4.createElement(
441
- "summary",
442
- { className: orClasses2.transactionDetailsTitle },
443
- checkoutLabels2.transactionDetails
444
- ),
445
- React4.createElement(
446
- "div",
447
- { className: orClasses2.transactionDetailsContent },
448
- React4.createElement(
449
- "dl",
450
- { className: orClasses2.swapDetails },
451
- rows.flatMap(
452
- (row) => renderTransactionDetailRow(row, {
453
- clipboard: props.clipboard,
454
- onError: props.onError
455
- })
456
- )
457
- )
458
- )
459
- );
460
- }
461
- function renderTransactionDetailRow(row, options) {
462
- const copyValue = row.copyValue ?? row.value;
463
- return [
464
- React4.createElement(
465
- "dt",
466
- { key: `${row.label}-label`, className: orClasses2.swapDetailsDt },
467
- row.label
468
- ),
469
- React4.createElement(
470
- "dd",
471
- { key: `${row.label}-value`, className: orClasses2.swapDetailsDd },
472
- React4.createElement("code", { className: orClasses2.swapDetailsCode }, row.value),
473
- React4.createElement(
474
- "div",
475
- { className: orClasses2.swapDetailsActions },
476
- React4.createElement(TransactionDetailCopyButton, {
477
- value: copyValue,
478
- clipboard: options.clipboard,
479
- onError: options.onError
480
- }),
481
- row.href === void 0 ? null : React4.createElement(
482
- "a",
483
- {
484
- className: orClasses2.swapDetailsLink,
485
- href: row.href,
486
- rel: "noreferrer",
487
- target: "_blank"
488
- },
489
- row.hrefLabel ?? checkoutLabels2.viewOnExplorer
490
- )
491
- )
492
- )
493
- ];
494
- }
495
- function TransactionDetailCopyButton(props) {
496
- const [copied, setCopied] = useTransientValue(false);
497
- const label = copied ? checkoutLabels2.copied : "Copy";
498
- return React4.createElement(
499
- "button",
500
- {
501
- className: orClasses2.detailCopy,
502
- type: "button",
503
- "aria-label": label,
504
- title: label,
505
- onClick: () => {
506
- void copyText(props.value, props.clipboard).then(() => setCopied(true)).catch((error) => props.onError?.(error));
507
- }
508
- },
509
- React4.createElement(ClipboardIcon)
510
- );
511
- }
512
-
513
433
  // src/theme.ts
514
- import * as React5 from "react";
434
+ import * as React4 from "react";
515
435
  import {
516
436
  OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES as OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES2,
517
437
  OPENRECEIVE_THEME_STORAGE_KEY,
518
438
  createThemeModel,
519
- orClasses as orClasses3,
439
+ orClasses as orClasses2,
520
440
  readThemePreference,
521
441
  writeThemePreference
522
442
  } from "@openreceive/browser/headless";
523
- var ThemeContext = React5.createContext(null);
443
+ var ThemeContext = React4.createContext(null);
524
444
  var storedThemeListeners = /* @__PURE__ */ new Set();
525
445
  var lastSetTheme = /* @__PURE__ */ new Map();
526
446
  function notifyStoredThemeChange() {
@@ -549,9 +469,9 @@ function useLocalTheme(options = {}) {
549
469
  const storageKey = options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY;
550
470
  const storage = options.storage;
551
471
  const defaultTheme = options.defaultTheme;
552
- const theme = React5.useSyncExternalStore(
472
+ const theme = React4.useSyncExternalStore(
553
473
  subscribeStoredTheme,
554
- React5.useCallback(
474
+ React4.useCallback(
555
475
  () => readThemePreference({
556
476
  storage,
557
477
  storageKey,
@@ -559,7 +479,7 @@ function useLocalTheme(options = {}) {
559
479
  }),
560
480
  [storage, storageKey, defaultTheme]
561
481
  ),
562
- React5.useCallback(
482
+ React4.useCallback(
563
483
  () => (
564
484
  // A host-supplied storage is readable on the server (that is how SSR theming is
565
485
  // wired); the implicit browser localStorage is not, so fall back to the default.
@@ -568,13 +488,13 @@ function useLocalTheme(options = {}) {
568
488
  [storage, storageKey, defaultTheme]
569
489
  )
570
490
  );
571
- const systemDark = React5.useSyncExternalStore(
491
+ const systemDark = React4.useSyncExternalStore(
572
492
  subscribeSystemDark,
573
493
  getSystemDark,
574
494
  getServerSystemDark
575
495
  );
576
496
  const themeModel = createThemeModel(theme, { systemDark });
577
- const setTheme = React5.useCallback(
497
+ const setTheme = React4.useCallback(
578
498
  (nextTheme) => {
579
499
  lastSetTheme.set(storageKey, nextTheme);
580
500
  writeThemePreference(nextTheme, {
@@ -585,7 +505,7 @@ function useLocalTheme(options = {}) {
585
505
  },
586
506
  [storage, storageKey]
587
507
  );
588
- const toggleTheme = React5.useCallback(() => {
508
+ const toggleTheme = React4.useCallback(() => {
589
509
  setTheme(themeModel.nextTheme);
590
510
  }, [setTheme, themeModel.nextTheme]);
591
511
  return {
@@ -602,7 +522,7 @@ function useLocalTheme(options = {}) {
602
522
  };
603
523
  }
604
524
  function useTheme(options = {}) {
605
- const scoped = React5.useContext(ThemeContext);
525
+ const scoped = React4.useContext(ThemeContext);
606
526
  const local = useLocalTheme(options);
607
527
  const storageKey = options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY;
608
528
  if (scoped !== null && options.storage === void 0 && (options.storageKey === void 0 || options.storageKey === storageKey) && options.defaultTheme === void 0) {
@@ -629,7 +549,7 @@ function ThemeToggle(props) {
629
549
  const componentProps = {
630
550
  ...buttonProps,
631
551
  "aria-label": themeModel.toggleLabel,
632
- className: joinClassNames(orClasses3.themeToggle, buttonProps.className),
552
+ className: joinClassNames(orClasses2.themeToggle, buttonProps.className),
633
553
  title: themeModel.toggleLabel,
634
554
  type,
635
555
  [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES2.themeToggle]: "",
@@ -640,7 +560,7 @@ function ThemeToggle(props) {
640
560
  if (onThemeChange === void 0) fallback.setTheme(themeModel.nextTheme);
641
561
  }
642
562
  };
643
- return React5.createElement(ButtonComponent, componentProps, children ?? themeModel.toggleLabel);
563
+ return React4.createElement(ButtonComponent, componentProps, children ?? themeModel.toggleLabel);
644
564
  }
645
565
  function ThemeScope(props) {
646
566
  const {
@@ -661,22 +581,22 @@ function ThemeScope(props) {
661
581
  storage
662
582
  });
663
583
  const scopedChildren = typeof children === "function" ? children(theme) : children;
664
- return React5.createElement(
584
+ return React4.createElement(
665
585
  ThemeContext.Provider,
666
586
  { value: theme },
667
587
  // Variadic children, not an array: an array child needs a key on every entry.
668
- React5.createElement(
588
+ React4.createElement(
669
589
  Element,
670
590
  {
671
591
  ...elementProps,
672
592
  ...theme.attributes
673
593
  },
674
- themeToggle ? React5.createElement(
594
+ themeToggle ? React4.createElement(
675
595
  "div",
676
596
  {
677
597
  className: topbarClassName
678
598
  },
679
- React5.createElement(ThemeToggle, {
599
+ React4.createElement(ThemeToggle, {
680
600
  className: themeToggleClassName,
681
601
  theme: theme.theme,
682
602
  resolvedTheme: theme.resolvedTheme,
@@ -689,6 +609,95 @@ function ThemeScope(props) {
689
609
  );
690
610
  }
691
611
 
612
+ // src/transaction-details.ts
613
+ import {
614
+ checkoutLabels as checkoutLabels2,
615
+ orClasses as orClasses3,
616
+ resolveTransactionDetailRows
617
+ } from "@openreceive/browser/headless";
618
+ import * as React5 from "react";
619
+ function TransactionDetails(props) {
620
+ const rows = resolveTransactionDetailRows(props.state);
621
+ if (rows.length === 0) return null;
622
+ return React5.createElement(
623
+ "details",
624
+ {
625
+ className: joinClassNames(orClasses3.transactionDetails, props.className),
626
+ open: props.open === true ? true : void 0
627
+ },
628
+ React5.createElement(
629
+ "summary",
630
+ { className: orClasses3.transactionDetailsTitle },
631
+ checkoutLabels2.transactionDetails
632
+ ),
633
+ React5.createElement(
634
+ "div",
635
+ { className: orClasses3.transactionDetailsContent },
636
+ React5.createElement(
637
+ "dl",
638
+ { className: orClasses3.swapDetails },
639
+ rows.flatMap(
640
+ (row) => renderTransactionDetailRow(row, {
641
+ clipboard: props.clipboard,
642
+ onError: props.onError
643
+ })
644
+ )
645
+ )
646
+ )
647
+ );
648
+ }
649
+ function renderTransactionDetailRow(row, options) {
650
+ const copyValue = row.copyValue ?? row.value;
651
+ return [
652
+ React5.createElement(
653
+ "dt",
654
+ { key: `${row.label}-label`, className: orClasses3.swapDetailsDt },
655
+ row.label
656
+ ),
657
+ React5.createElement(
658
+ "dd",
659
+ { key: `${row.label}-value`, className: orClasses3.swapDetailsDd },
660
+ React5.createElement("code", { className: orClasses3.swapDetailsCode }, row.value),
661
+ React5.createElement(
662
+ "div",
663
+ { className: orClasses3.swapDetailsActions },
664
+ React5.createElement(TransactionDetailCopyButton, {
665
+ value: copyValue,
666
+ clipboard: options.clipboard,
667
+ onError: options.onError
668
+ }),
669
+ row.href === void 0 ? null : React5.createElement(
670
+ "a",
671
+ {
672
+ className: orClasses3.swapDetailsLink,
673
+ href: row.href,
674
+ rel: "noreferrer",
675
+ target: "_blank"
676
+ },
677
+ row.hrefLabel ?? checkoutLabels2.viewOnExplorer
678
+ )
679
+ )
680
+ )
681
+ ];
682
+ }
683
+ function TransactionDetailCopyButton(props) {
684
+ const [copied, setCopied] = useTransientValue(false);
685
+ const label = copied ? checkoutLabels2.copied : "Copy";
686
+ return React5.createElement(
687
+ "button",
688
+ {
689
+ className: orClasses3.detailCopy,
690
+ type: "button",
691
+ "aria-label": label,
692
+ title: label,
693
+ onClick: () => {
694
+ void copyText(props.value, props.clipboard).then(() => setCopied(true)).catch((error) => props.onError?.(error));
695
+ }
696
+ },
697
+ React5.createElement(ClipboardIcon)
698
+ );
699
+ }
700
+
692
701
  // src/use-checkout.ts
693
702
  import * as React6 from "react";
694
703
  import {
@@ -927,8 +936,10 @@ import {
927
936
  createMethodGridDisplay,
928
937
  createPaymentWizardController,
929
938
  createPaymentWizardModel,
939
+ createSwapDisplayModel as createSwapDisplayModel2,
930
940
  createWizardRouteAssetDisplays,
931
941
  createWizardRouteDisplays,
942
+ formatMethodNetworkDetail,
932
943
  formatNetworkSummary,
933
944
  getNetworkIcon,
934
945
  getPaymentMethodIcon,
@@ -1191,16 +1202,17 @@ function ProviderTutorialModal(options) {
1191
1202
 
1192
1203
  // src/swap.ts
1193
1204
  import {
1205
+ checkoutLabels as checkoutLabels4,
1194
1206
  createDetailExternalLink,
1207
+ createQrSvgController as createQrSvgController2,
1195
1208
  createSwapDisplayModel,
1209
+ createSwapUnavailableModel,
1196
1210
  createTransactionDetails,
1197
- createQrPayloadSvg,
1211
+ currentCheckoutUrl,
1198
1212
  getSwapRefundFormError,
1199
- checkoutLabels as checkoutLabels4,
1200
- createSwapUnavailableModel,
1201
- swapOptionLimitMessage,
1202
1213
  orClasses as orClasses5,
1203
- selectCheckoutDisplayInvoice
1214
+ selectCheckoutDisplayInvoice,
1215
+ swapOptionLimitMessage
1204
1216
  } from "@openreceive/browser/headless";
1205
1217
  import * as React8 from "react";
1206
1218
  function renderSwapActions(options) {
@@ -1301,10 +1313,10 @@ function renderSwapUnavailable(quote, checkout) {
1301
1313
  );
1302
1314
  }
1303
1315
  function renderSwapDepositPanel(options) {
1304
- const display = createSwapDisplayModel(
1305
- options.invoice,
1306
- options.now === void 0 ? {} : { now: options.now }
1307
- );
1316
+ const display = createSwapDisplayModel(options.invoice, {
1317
+ ...options.now === void 0 ? {} : { now: options.now },
1318
+ ...options.resumable === void 0 ? {} : { resumable: options.resumable }
1319
+ });
1308
1320
  if (display === void 0) return null;
1309
1321
  const backButton = React8.createElement(
1310
1322
  "button",
@@ -1331,6 +1343,25 @@ function renderSwapDepositPanel(options) {
1331
1343
  display.providerStateDetail
1332
1344
  )
1333
1345
  );
1346
+ const refundHeading = React8.createElement(
1347
+ "div",
1348
+ { className: orClasses5.swapRefundHeading, role: "alert" },
1349
+ renderAlertIcon("warning"),
1350
+ React8.createElement(
1351
+ "div",
1352
+ { className: orClasses5.swapNetworkWarningContent },
1353
+ React8.createElement(
1354
+ "strong",
1355
+ { className: orClasses5.swapHeadingTitle },
1356
+ display.providerStateLabel
1357
+ ),
1358
+ React8.createElement(
1359
+ "span",
1360
+ { className: orClasses5.swapHeadingDetail },
1361
+ display.providerStateDetail
1362
+ )
1363
+ )
1364
+ );
1334
1365
  const waitingCard = (countdownLabel) => React8.createElement(WaitingState, {
1335
1366
  waiting: true,
1336
1367
  statusTitle: display.providerStateLabel,
@@ -1435,26 +1466,20 @@ function renderSwapDepositPanel(options) {
1435
1466
  {
1436
1467
  className: orClasses5.swapPanel
1437
1468
  },
1438
- heading,
1439
- renderSwapRefundFacts(display, options),
1440
- React8.createElement(
1441
- "p",
1442
- {
1443
- className: orClasses5.swapWarning
1444
- },
1445
- `Use a ${display.networkLabel} address you control. Do not paste the deposit address.`
1446
- ),
1469
+ refundHeading,
1470
+ renderSwapRefundReturnWarning(display, options),
1471
+ renderSwapAmountFacts(display),
1447
1472
  React8.createElement(SwapRefundForm, {
1448
1473
  attemptId: display.attemptId,
1449
1474
  payInAsset: display.payInAsset,
1450
1475
  networkLabel: display.networkLabel,
1476
+ ...display.refundReason === void 0 ? {} : { refundReason: display.refundReason },
1451
1477
  submittedRefundAddress: display.refundAddress,
1452
1478
  refundAllowed: display.refundAllowed,
1453
1479
  onRefund: options.onRefund,
1454
1480
  onError: options.onError
1455
1481
  }),
1456
- renderSwapSupportDetails(display, options),
1457
- renderSwapRefundReturnWarning()
1482
+ renderSwapSupportDetails(display, options)
1458
1483
  );
1459
1484
  }
1460
1485
  if (display.state === "refund_pending" || display.state === "refunded") {
@@ -1463,8 +1488,9 @@ function renderSwapDepositPanel(options) {
1463
1488
  {
1464
1489
  className: orClasses5.swapPanel
1465
1490
  },
1466
- heading,
1467
- renderSwapRefundFacts(display, options),
1491
+ refundHeading,
1492
+ renderSwapRefundReturnWarning(display, options),
1493
+ renderSwapAmountFacts(display),
1468
1494
  React8.createElement(
1469
1495
  "dl",
1470
1496
  {
@@ -1481,8 +1507,7 @@ function renderSwapDepositPanel(options) {
1481
1507
  payInAsset: display.payInAsset
1482
1508
  })
1483
1509
  ),
1484
- renderSwapSupportDetails(display, options),
1485
- renderSwapRefundReturnWarning()
1510
+ renderSwapSupportDetails(display, options)
1486
1511
  );
1487
1512
  }
1488
1513
  if (display.state === "deposit") {
@@ -1506,11 +1531,15 @@ function renderSwapDepositPanel(options) {
1506
1531
  {
1507
1532
  className: orClasses5.swapDepositLayout
1508
1533
  },
1509
- React8.createElement(SwapPayloadQRCode, {
1510
- payload: display.qrPayload,
1511
- encoder: options.encoder,
1512
- onError: options.onError
1513
- }),
1534
+ React8.createElement(
1535
+ "div",
1536
+ { className: orClasses5.swapQrFrame },
1537
+ React8.createElement(SwapPayloadQRCode, {
1538
+ payload: display.qrPayload,
1539
+ encoder: options.encoder,
1540
+ onError: options.onError
1541
+ })
1542
+ ),
1514
1543
  React8.createElement(
1515
1544
  "div",
1516
1545
  {
@@ -1546,9 +1575,10 @@ function renderSwapDepositPanel(options) {
1546
1575
  React8.createElement(
1547
1576
  "p",
1548
1577
  { className: orClasses5.swapWarning },
1549
- checkoutLabels4.supportReviewNeeded
1578
+ checkoutLabels4.supportReviewFacts
1550
1579
  ),
1551
- renderSwapSupportDetails(display, options),
1580
+ renderSwapAmountFacts(display),
1581
+ renderSwapSupportDetails(display, options, { open: true }),
1552
1582
  backButton
1553
1583
  );
1554
1584
  }
@@ -1602,26 +1632,45 @@ function renderSwapNetworkWarning(display) {
1602
1632
  )
1603
1633
  );
1604
1634
  }
1605
- function renderSwapRefundFacts(display, options) {
1635
+ function renderSwapAmountFacts(display) {
1606
1636
  const rows = [
1607
- ...display.depositReceivedAmount === void 0 ? [] : renderSwapCopyRow(
1608
- "Amount received",
1609
- `${display.depositReceivedAmount} ${display.assetLabel}`,
1610
- options
1611
- ),
1612
- ...display.depositReceivedAmount === void 0 ? [] : renderSwapCopyRow(
1613
- "Amount required",
1614
- `${display.depositAmount} ${display.assetLabel}`,
1615
- options
1616
- ),
1617
- ...display.refundAmount === void 0 ? [] : renderSwapCopyRow(
1618
- "Estimated refund",
1619
- `${display.refundAmount} ${display.assetLabel}`,
1620
- options
1621
- )
1637
+ ...display.depositReceivedAmount === void 0 ? [] : [
1638
+ ["Amount received", `${display.depositReceivedAmount} ${display.assetLabel}`],
1639
+ ["Amount required", `${display.depositAmount} ${display.assetLabel}`]
1640
+ ],
1641
+ ...display.refundAmount === void 0 ? [] : [["Estimated refund", `${display.refundAmount} ${display.assetLabel}`]]
1622
1642
  ];
1623
1643
  if (rows.length === 0) return null;
1624
- return React8.createElement("dl", { className: orClasses5.swapDetails }, rows);
1644
+ return React8.createElement(
1645
+ "dl",
1646
+ { className: orClasses5.swapFacts },
1647
+ rows.map(
1648
+ ([label, value]) => React8.createElement(
1649
+ "div",
1650
+ { key: label, className: orClasses5.swapFactsRow },
1651
+ React8.createElement("dt", { className: orClasses5.swapFactsLabel }, label),
1652
+ React8.createElement("dd", { className: orClasses5.swapFactsValue }, value)
1653
+ )
1654
+ )
1655
+ );
1656
+ }
1657
+ function renderAlertIcon(kind) {
1658
+ return React8.createElement(
1659
+ "svg",
1660
+ {
1661
+ xmlns: "http://www.w3.org/2000/svg",
1662
+ fill: "none",
1663
+ viewBox: "0 0 24 24",
1664
+ className: orClasses5.swapNetworkWarningIcon,
1665
+ "aria-hidden": "true"
1666
+ },
1667
+ React8.createElement("path", {
1668
+ strokeLinecap: "round",
1669
+ strokeLinejoin: "round",
1670
+ strokeWidth: 2,
1671
+ d: kind === "warning" ? "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" : "M17 3H7a2 2 0 00-2 2v16l7-3.5L19 21V5a2 2 0 00-2-2z"
1672
+ })
1673
+ );
1625
1674
  }
1626
1675
  function renderSwapFeeBreakdown(breakdown) {
1627
1676
  if (breakdown === void 0) return null;
@@ -1720,7 +1769,7 @@ function SwapCopyButton(props) {
1720
1769
  React8.createElement(ClipboardIcon)
1721
1770
  );
1722
1771
  }
1723
- function renderSwapSupportDetails(display, options) {
1772
+ function renderSwapSupportDetails(display, options, view = {}) {
1724
1773
  const rowOptions = { ...options, payInAsset: display.payInAsset };
1725
1774
  const rows = [
1726
1775
  ...display.depositTxId === void 0 ? [] : renderSwapCopyRow("Deposit transaction", display.depositTxId, rowOptions),
@@ -1732,7 +1781,8 @@ function renderSwapSupportDetails(display, options) {
1732
1781
  return React8.createElement(
1733
1782
  "details",
1734
1783
  {
1735
- className: orClasses5.swapSupport
1784
+ className: orClasses5.swapSupport,
1785
+ ...view.open === true ? { open: true } : {}
1736
1786
  },
1737
1787
  React8.createElement("summary", { className: orClasses5.swapSupportTitle }, "Payment details"),
1738
1788
  React8.createElement(
@@ -1742,13 +1792,57 @@ function renderSwapSupportDetails(display, options) {
1742
1792
  )
1743
1793
  );
1744
1794
  }
1745
- function renderSwapRefundReturnWarning() {
1795
+ function renderSwapRefundReturnWarning(display, options) {
1796
+ const url = display.resumable ? currentCheckoutUrl() : void 0;
1746
1797
  return React8.createElement(
1747
- "p",
1748
- {
1749
- className: orClasses5.swapWarning
1750
- },
1751
- checkoutLabels4.refundReturnWarning
1798
+ "div",
1799
+ { className: orClasses5.swapRefundReturn },
1800
+ renderAlertIcon("bookmark"),
1801
+ React8.createElement(
1802
+ "div",
1803
+ { className: orClasses5.swapNetworkWarningContent },
1804
+ React8.createElement(
1805
+ "p",
1806
+ { className: orClasses5.swapRefundReturnTitle },
1807
+ checkoutLabels4.refundReturnTitle
1808
+ ),
1809
+ React8.createElement(
1810
+ "p",
1811
+ { className: orClasses5.swapRefundReturnBody },
1812
+ display.refundReturnLabel
1813
+ ),
1814
+ url === void 0 ? null : React8.createElement(
1815
+ "dl",
1816
+ { className: orClasses5.swapDetails },
1817
+ ...renderSwapCopyRow(checkoutLabels4.refundReturnUrlLabel, url, {
1818
+ ...options,
1819
+ selectable: true
1820
+ })
1821
+ )
1822
+ )
1823
+ );
1824
+ }
1825
+ function renderKeepOrderNote(options) {
1826
+ if (options.resumable !== true) return null;
1827
+ const reference = options.reference ?? "";
1828
+ const url = currentCheckoutUrl();
1829
+ if (reference.length === 0 && url === void 0) return null;
1830
+ const rowOptions = { ...options, selectable: true };
1831
+ return React8.createElement(
1832
+ "div",
1833
+ { className: orClasses5.keepOrder },
1834
+ React8.createElement(
1835
+ "p",
1836
+ { className: orClasses5.swapSectionTitle },
1837
+ checkoutLabels4.keepOrderTitle
1838
+ ),
1839
+ React8.createElement("p", { className: orClasses5.keepOrderBody }, checkoutLabels4.keepOrderBody),
1840
+ React8.createElement(
1841
+ "dl",
1842
+ { className: orClasses5.swapDetails },
1843
+ ...reference.length === 0 ? [] : renderSwapCopyRow(checkoutLabels4.keepOrderIdLabel, reference, rowOptions),
1844
+ ...url === void 0 ? [] : renderSwapCopyRow(checkoutLabels4.keepOrderUrlLabel, url, rowOptions)
1845
+ )
1752
1846
  );
1753
1847
  }
1754
1848
  var REFUND_ADDRESS_DRAFT_LIMIT = 8;
@@ -1791,10 +1885,30 @@ function SwapRefundForm(props) {
1791
1885
  void props.onRefund(props.attemptId, address, confirm).catch(props.onError).finally(() => setSubmitting(false));
1792
1886
  }
1793
1887
  },
1888
+ // The form says what it is and why it is here before it asks for anything:
1889
+ // a bare input under a red banner is a payer guessing what to type.
1890
+ React8.createElement(
1891
+ "p",
1892
+ { className: orClasses5.swapSectionTitle },
1893
+ checkoutLabels4.refundSectionTitle
1894
+ ),
1895
+ props.refundReason === void 0 ? null : React8.createElement(
1896
+ "p",
1897
+ { className: orClasses5.swapRefundReason },
1898
+ checkoutLabels4.refundReasonLabel.replace(
1899
+ "{reason}",
1900
+ props.refundReason.replace(/_/g, " ")
1901
+ )
1902
+ ),
1903
+ React8.createElement(
1904
+ "p",
1905
+ { className: orClasses5.swapRefundInstruction },
1906
+ checkoutLabels4.refundAddressOwnership.replace("{network}", props.networkLabel)
1907
+ ),
1794
1908
  props.submittedRefundAddress === void 0 ? null : React8.createElement(
1795
1909
  "p",
1796
1910
  {
1797
- className: orClasses5.swapWarning
1911
+ className: orClasses5.swapRefundInstruction
1798
1912
  },
1799
1913
  checkoutLabels4.confirmRefundTo.replace("{address}", props.submittedRefundAddress)
1800
1914
  ),
@@ -1845,17 +1959,19 @@ function SwapPayloadQRCode(props) {
1845
1959
  const [svg, setSvg] = React8.useState("");
1846
1960
  const onErrorRef = React8.useRef(props.onError);
1847
1961
  onErrorRef.current = props.onError;
1962
+ const { payload, encoder } = props;
1848
1963
  React8.useEffect(() => {
1849
- let cancelled = false;
1850
- createQrPayloadSvg(props.payload, { encoder: props.encoder, width: 220 }).then((nextSvg) => {
1851
- if (!cancelled) setSvg(nextSvg);
1852
- }).catch((error) => {
1853
- if (!cancelled) onErrorRef.current?.(error);
1964
+ const controller = createQrSvgController2({
1965
+ onValue: setSvg,
1966
+ onError: (error) => onErrorRef.current?.(error),
1967
+ ...encoder === void 0 ? {} : { encoder },
1968
+ width: 220
1854
1969
  });
1970
+ controller.showPayload(payload);
1855
1971
  return () => {
1856
- cancelled = true;
1972
+ controller.stop();
1857
1973
  };
1858
- }, [props.payload, props.encoder]);
1974
+ }, [payload, encoder]);
1859
1975
  const imageSource = svg.length === 0 ? void 0 : `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
1860
1976
  return React8.createElement("img", {
1861
1977
  alt: "",
@@ -1873,9 +1989,7 @@ function PaymentWizard(props) {
1873
1989
  const [startedSwapInvoice, setStartedSwapInvoice] = React9.useState(null);
1874
1990
  const [dismissedSwapInvoiceId, setDismissedSwapInvoiceId] = React9.useState(null);
1875
1991
  const [selectedSwapAsset, setSelectedSwapAsset] = React9.useState(null);
1876
- const [selectedSwapNetworks, setSelectedSwapNetworks] = React9.useState(
1877
- {}
1878
- );
1992
+ const [selectedSwapAssetByGroup, setSelectedSwapAssetByGroup] = React9.useState({});
1879
1993
  const [selectedPickerKey, setSelectedPickerKey] = React9.useState(null);
1880
1994
  const autoSwapAttemptedRef = React9.useRef(/* @__PURE__ */ new Set());
1881
1995
  const fetcher = props.fetch ?? globalThis.fetch;
@@ -1884,16 +1998,18 @@ function PaymentWizard(props) {
1884
1998
  const session = useCheckoutSession({
1885
1999
  snapshot: () => checkout,
1886
2000
  reference: () => reference,
1887
- swapPrefix: () => props.prefix,
1888
- fetch: () => fetcher,
1889
- swapSelection: {
1890
- started: () => startedSwapInvoice ?? void 0,
1891
- setStarted: setStartedSwapInvoice,
1892
- dismissedInvoiceId: () => dismissedSwapInvoiceId,
1893
- setDismissedInvoiceId: setDismissedSwapInvoiceId,
1894
- setSelectedAsset: setSelectedSwapAsset
2001
+ swap: {
2002
+ selection: {
2003
+ started: () => startedSwapInvoice ?? void 0,
2004
+ setStarted: setStartedSwapInvoice,
2005
+ dismissedInvoiceId: () => dismissedSwapInvoiceId,
2006
+ setDismissedInvoiceId: setDismissedSwapInvoiceId,
2007
+ setSelectedAsset: setSelectedSwapAsset
2008
+ },
2009
+ prefix: () => props.prefix,
2010
+ fetch: () => fetcher,
2011
+ onStarted: (invoice) => props.onSwapStarted?.(invoice)
1895
2012
  },
1896
- onSwapStarted: (invoice) => props.onSwapStarted?.(invoice),
1897
2013
  ...props.logger === void 0 ? {} : { logger: props.logger },
1898
2014
  onError: (error) => props.onError?.(error)
1899
2015
  });
@@ -1901,7 +2017,7 @@ function PaymentWizard(props) {
1901
2017
  const clearSwapFocus = React9.useCallback(() => {
1902
2018
  setSelectedSwapAsset(null);
1903
2019
  setSelectedPickerKey(null);
1904
- setSelectedSwapNetworks({});
2020
+ setSelectedSwapAssetByGroup({});
1905
2021
  session.clearSwapStartError();
1906
2022
  props.swapRefund?.clearSwapRefundStaging();
1907
2023
  }, [session, props.swapRefund]);
@@ -1997,6 +2113,18 @@ function PaymentWizard(props) {
1997
2113
  stickySwapInvoiceRef.current = void 0;
1998
2114
  }
1999
2115
  const activeSwapForAsset = selectedSwapAsset === null ? void 0 : currentSwapInvoice !== void 0 && currentSwapInvoice.swap?.pay_in_asset === selectedSwapAsset ? currentSwapInvoice : stickySwapInvoiceRef.current?.swap?.pay_in_asset === selectedSwapAsset ? stickySwapInvoiceRef.current : void 0;
2116
+ const resumeAdoptedRef = React9.useRef(false);
2117
+ React9.useEffect(() => {
2118
+ if (resumeAdoptedRef.current) return;
2119
+ if (selectedSwapAsset !== null) {
2120
+ resumeAdoptedRef.current = true;
2121
+ return;
2122
+ }
2123
+ const payInAsset = currentSwapInvoice?.swap?.pay_in_asset;
2124
+ if (payInAsset === void 0) return;
2125
+ resumeAdoptedRef.current = true;
2126
+ setSelectedSwapAsset(payInAsset);
2127
+ }, [currentSwapInvoice, selectedSwapAsset]);
2000
2128
  React9.useEffect(() => {
2001
2129
  if (selectedSwapAsset === null) return;
2002
2130
  if (props.prefix === void 0) return;
@@ -2008,6 +2136,18 @@ function PaymentWizard(props) {
2008
2136
  const selectedSwapOption = selectedSwapAsset === null ? void 0 : swapAssetOptions.find((option) => option.pay_in_asset === selectedSwapAsset) ?? session.swapQuotes[selectedSwapAsset];
2009
2137
  const selectedSwapQuote = selectedSwapAsset === null ? void 0 : session.swapQuotes[selectedSwapAsset];
2010
2138
  const selectedSwapLabel = selectedSwapOption?.label ?? "this coin";
2139
+ const activeSwapState = activeSwapForAsset === void 0 ? void 0 : createSwapDisplayModel2(activeSwapForAsset, {
2140
+ ...now === void 0 ? {} : { now },
2141
+ ...props.resumable === void 0 ? {} : { resumable: props.resumable }
2142
+ })?.state;
2143
+ const refundOwed = activeSwapState === "refund_required";
2144
+ const refundStage = activeSwapState?.startsWith("refund") ?? false;
2145
+ const keepOrderNote = renderKeepOrderNote({
2146
+ ...checkout?.reference === void 0 ? {} : { reference: checkout.reference },
2147
+ ...props.resumable === void 0 ? {} : { resumable: props.resumable },
2148
+ ...props.clipboard === void 0 ? {} : { clipboard: props.clipboard },
2149
+ ...props.onError === void 0 ? {} : { onError: props.onError }
2150
+ });
2011
2151
  if (selectedSwapAsset !== null) {
2012
2152
  return React9.createElement(
2013
2153
  "div",
@@ -2017,7 +2157,7 @@ function PaymentWizard(props) {
2017
2157
  React9.createElement(
2018
2158
  "div",
2019
2159
  { className: orClasses6.wizardBody },
2020
- renderWizardBackBreadcrumb(
2160
+ refundOwed ? null : renderWizardBackBreadcrumb(
2021
2161
  selectedSwapOption === void 0 ? selectedSwapLabel : `${selectedSwapOption.label} \xB7 ${selectedSwapOption.network_label}`,
2022
2162
  clearSwapFocus
2023
2163
  ),
@@ -2038,13 +2178,15 @@ function PaymentWizard(props) {
2038
2178
  logger: props.logger,
2039
2179
  onError: props.onError,
2040
2180
  onRefund: refundSwap,
2181
+ ...props.resumable === void 0 ? {} : { resumable: props.resumable },
2041
2182
  onBackToLightning: () => {
2042
2183
  setDismissedSwapInvoiceId(activeSwapForAsset.invoice_id);
2043
2184
  clearSwapFocus();
2044
2185
  void props.onRequestLightning?.();
2045
2186
  }
2046
2187
  }) : selectedSwapQuote !== void 0 && !selectedSwapQuote.available ? renderSwapUnavailable(selectedSwapQuote, checkout) : renderSwapPreparing(selectedSwapLabel)
2047
- )
2188
+ ),
2189
+ refundStage ? null : keepOrderNote
2048
2190
  )
2049
2191
  );
2050
2192
  }
@@ -2061,7 +2203,7 @@ function PaymentWizard(props) {
2061
2203
  checkout: checkout ?? void 0,
2062
2204
  selectedPickerKey,
2063
2205
  startingAsset: swapStartingAsset,
2064
- selectedSwapNetworks,
2206
+ selectedSwapAssetByGroup,
2065
2207
  // One resolver decides what a tile click MEANS, so the "ask the
2066
2208
  // network question only when it is a real question" rule is not
2067
2209
  // re-derived here: a single-network group comes back as start_swap
@@ -2071,7 +2213,7 @@ function PaymentWizard(props) {
2071
2213
  pickerKey: key,
2072
2214
  previousKey,
2073
2215
  entries: buildMethodGridEntries(paymentMethods, swapAssetOptions),
2074
- selectedNetworks: selectedSwapNetworks
2216
+ selectedAssetByGroup: selectedSwapAssetByGroup
2075
2217
  });
2076
2218
  if (resolved.kind === "none") return;
2077
2219
  if (resolved.kind === "select_method") {
@@ -2088,10 +2230,10 @@ function PaymentWizard(props) {
2088
2230
  return;
2089
2231
  }
2090
2232
  setSelectedPickerKey(key);
2091
- setSelectedSwapNetworks(resolved.selectedNetworks);
2233
+ setSelectedSwapAssetByGroup(resolved.selectedAssetByGroup);
2092
2234
  },
2093
2235
  onSelectNetwork: (groupKey, payInAsset) => {
2094
- setSelectedSwapNetworks((current) => ({
2236
+ setSelectedSwapAssetByGroup((current) => ({
2095
2237
  ...current,
2096
2238
  [groupKey]: payInAsset
2097
2239
  }));
@@ -2107,6 +2249,13 @@ function PaymentWizard(props) {
2107
2249
  onContinueSwap: selectSwapAsset,
2108
2250
  ...resolveAssetUrl === void 0 ? {} : { resolveAssetUrl }
2109
2251
  }) : null,
2252
+ // On the grid the note is a section of its own, under the tiles: there is no
2253
+ // body to put it in until a method is chosen.
2254
+ selection.selectedMethod === null && keepOrderNote !== null ? React9.createElement(
2255
+ "div",
2256
+ { key: "keep-order", className: orClasses6.wizardBody },
2257
+ keepOrderNote
2258
+ ) : null,
2110
2259
  selection.selectedMethod === null ? null : React9.createElement(
2111
2260
  "div",
2112
2261
  { className: orClasses6.wizardBody },
@@ -2174,6 +2323,7 @@ function PaymentWizard(props) {
2174
2323
  logger: props.logger,
2175
2324
  onError: props.onError,
2176
2325
  onRefund: refundSwap,
2326
+ ...props.resumable === void 0 ? {} : { resumable: props.resumable },
2177
2327
  onBackToLightning: () => {
2178
2328
  setDismissedSwapInvoiceId(activeSwapForRoute.invoice_id);
2179
2329
  clearSwapFocus();
@@ -2234,7 +2384,8 @@ function PaymentWizard(props) {
2234
2384
  ) : null
2235
2385
  );
2236
2386
  })
2237
- )
2387
+ ),
2388
+ keepOrderNote
2238
2389
  ),
2239
2390
  activeTutorialProvider === void 0 || activeTutorial === null ? null : React9.createElement(ProviderTutorialModal, {
2240
2391
  key: "provider-tutorial",
@@ -2275,7 +2426,7 @@ function renderCompactPaymentMethodSelector(options) {
2275
2426
  const display = createMethodGridDisplay({
2276
2427
  entries: buildMethodGridEntries(paymentMethods, options.swapAssetOptions),
2277
2428
  selectedPickerKey: options.selectedPickerKey,
2278
- selectedNetworks: options.selectedSwapNetworks,
2429
+ selectedAssetByGroup: options.selectedSwapAssetByGroup,
2279
2430
  startingAsset: options.startingAsset,
2280
2431
  ...options.checkout === void 0 ? {} : { checkout: options.checkout }
2281
2432
  });
@@ -2470,7 +2621,15 @@ function renderCompactPaymentMethodSelector(options) {
2470
2621
  React9.createElement(
2471
2622
  "span",
2472
2623
  { className: orClasses6.methodTitleWrap },
2473
- React9.createElement("span", { className: orClasses6.methodTitle }, method.title)
2624
+ React9.createElement("span", { className: orClasses6.methodTitle }, method.title),
2625
+ // The tile's own description. A grid of five names is a grid of
2626
+ // five questions; `paymentMethods` has carried the answer all
2627
+ // along and only the mobile layout was printing it.
2628
+ React9.createElement(
2629
+ "span",
2630
+ { className: orClasses6.methodTileDetail },
2631
+ method.detail
2632
+ )
2474
2633
  )
2475
2634
  );
2476
2635
  }
@@ -2480,7 +2639,6 @@ function renderCompactPaymentMethodSelector(options) {
2480
2639
  selected,
2481
2640
  multiNetwork,
2482
2641
  displayOption,
2483
- selectedOption,
2484
2642
  starting,
2485
2643
  disabled,
2486
2644
  accent,
@@ -2530,11 +2688,11 @@ function renderCompactPaymentMethodSelector(options) {
2530
2688
  "span",
2531
2689
  { className: orClasses6.methodTitleWrap },
2532
2690
  React9.createElement("span", { className: orClasses6.methodTitle }, group.label),
2533
- !disabled && multiNetwork ? React9.createElement(
2691
+ React9.createElement(
2534
2692
  "span",
2535
- { className: orClasses6.methodDetailMobile },
2536
- selected && selectedOption !== void 0 ? `${selectedOption.network_label} network` : checkoutLabels5.selectNetwork
2537
- ) : null
2693
+ { className: orClasses6.methodTileDetail },
2694
+ formatMethodNetworkDetail(group.options)
2695
+ )
2538
2696
  )
2539
2697
  ),
2540
2698
  disabled && limitMessage !== void 0 ? React9.createElement("span", { className: orClasses6.methodLimitHint }, limitMessage) : null,
@@ -2714,7 +2872,8 @@ function Checkout(props) {
2714
2872
  metadata: props.metadata,
2715
2873
  syncUrl: props.syncUrl,
2716
2874
  resumePathPrefix: props.resumePathPrefix,
2717
- routeReference: props.routeReference
2875
+ routeReference: props.routeReference,
2876
+ resumePaymentHash: props.resumePaymentHash
2718
2877
  });
2719
2878
  const { checkout } = props;
2720
2879
  if (checkout !== void 0) {
@@ -2757,7 +2916,8 @@ function CheckoutCreate(props) {
2757
2916
  classNames,
2758
2917
  syncUrl = false,
2759
2918
  resumePathPrefix = "/checkout",
2760
- routeReference
2919
+ routeReference,
2920
+ resumePaymentHash
2761
2921
  } = props;
2762
2922
  const [created, setCreated] = React10.useState({ status: "pending" });
2763
2923
  const [attempt, setAttempt] = React10.useState(0);
@@ -2798,7 +2958,15 @@ function CheckoutCreate(props) {
2798
2958
  prefix: resolvedPrefix,
2799
2959
  reference,
2800
2960
  ...createFetchRef.current === void 0 ? {} : { fetch: createFetchRef.current }
2801
- }).then((checkout) => {
2961
+ }).then(
2962
+ (checkout) => resumePaymentHash === void 0 ? checkout : resumeSwapAttempt({
2963
+ fetch: createFetchRef.current ?? globalThis.fetch,
2964
+ prefix: resolvedPrefix,
2965
+ reference,
2966
+ paymentHash: resumePaymentHash,
2967
+ snapshot: checkout
2968
+ })
2969
+ ).then((checkout) => {
2802
2970
  if (!cancelled) setCreated({ status: "ready", checkout });
2803
2971
  }).catch((error) => {
2804
2972
  if (cancelled) return;
@@ -2811,7 +2979,7 @@ function CheckoutCreate(props) {
2811
2979
  return () => {
2812
2980
  cancelled = true;
2813
2981
  };
2814
- }, [reference, resolvedPrefix, attempt]);
2982
+ }, [reference, resolvedPrefix, resumePaymentHash, attempt]);
2815
2983
  const onSwapStarted = React10.useCallback(
2816
2984
  (invoice) => {
2817
2985
  setCreated((current) => {
@@ -2890,9 +3058,16 @@ function CheckoutView(props) {
2890
3058
  prefix = OPENRECEIVE_DEFAULT_PREFIX,
2891
3059
  metadata: _metadata,
2892
3060
  createFetch: _createFetch,
2893
- syncUrl: _syncUrl,
3061
+ // Not `_`-prefixed like its neighbours: the view reads it, to infer
3062
+ // `resumable` for the refund screen. Still destructured out so it never
3063
+ // reaches the rendered <section>.
3064
+ syncUrl,
2894
3065
  resumePathPrefix: _resumePathPrefix,
2895
- routeReference: _routeReference,
3066
+ routeReference,
3067
+ // Consumed by CheckoutCreate before the view exists; destructured out here
3068
+ // so it never reaches the rendered <section> as an attribute.
3069
+ resumePaymentHash: _resumePaymentHash,
3070
+ resumable,
2896
3071
  onRequestLightning,
2897
3072
  onSwapStarted,
2898
3073
  mintingLightning = false,
@@ -3175,6 +3350,11 @@ function CheckoutView(props) {
3175
3350
  onSwapStarted,
3176
3351
  resolveAssetUrl,
3177
3352
  assetBaseUrl,
3353
+ // Whether a payer who closes the tab has a URL to come back
3354
+ // to. Explicit wins — only the host knows about a per-order
3355
+ // route of its own; otherwise infer it from the two props that
3356
+ // put the reference in the URL.
3357
+ resumable: resumable ?? (syncUrl === true || routeReference !== void 0),
3178
3358
  // The engine's staged refund address rides the controller this
3179
3359
  // model owns, so a poll cannot wipe a review in progress.
3180
3360
  swapRefund: checkoutModel