@openreceive/react 0.3.1 → 0.3.3

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";
@@ -429,106 +430,17 @@ function SatsDetail(props) {
429
430
  );
430
431
  }
431
432
 
432
- // src/transaction-details.ts
433
- import {
434
- checkoutLabels as checkoutLabels2,
435
- orClasses as orClasses2,
436
- resolveTransactionDetailRows
437
- } from "@openreceive/browser/headless";
438
- import * as React4 from "react";
439
- function TransactionDetails(props) {
440
- const rows = resolveTransactionDetailRows(props.state);
441
- if (rows.length === 0) return null;
442
- return React4.createElement(
443
- "details",
444
- {
445
- className: joinClassNames(orClasses2.transactionDetails, props.className),
446
- open: props.open === true ? true : void 0
447
- },
448
- React4.createElement(
449
- "summary",
450
- { className: orClasses2.transactionDetailsTitle },
451
- checkoutLabels2.transactionDetails
452
- ),
453
- React4.createElement(
454
- "div",
455
- { className: orClasses2.transactionDetailsContent },
456
- React4.createElement(
457
- "dl",
458
- { className: orClasses2.swapDetails },
459
- rows.flatMap(
460
- (row) => renderTransactionDetailRow(row, {
461
- clipboard: props.clipboard,
462
- onError: props.onError
463
- })
464
- )
465
- )
466
- )
467
- );
468
- }
469
- function renderTransactionDetailRow(row, options) {
470
- const copyValue = row.copyValue ?? row.value;
471
- return [
472
- React4.createElement(
473
- "dt",
474
- { key: `${row.label}-label`, className: orClasses2.swapDetailsDt },
475
- row.label
476
- ),
477
- React4.createElement(
478
- "dd",
479
- { key: `${row.label}-value`, className: orClasses2.swapDetailsDd },
480
- React4.createElement("code", { className: orClasses2.swapDetailsCode }, row.value),
481
- React4.createElement(
482
- "div",
483
- { className: orClasses2.swapDetailsActions },
484
- React4.createElement(TransactionDetailCopyButton, {
485
- value: copyValue,
486
- clipboard: options.clipboard,
487
- onError: options.onError
488
- }),
489
- row.href === void 0 ? null : React4.createElement(
490
- "a",
491
- {
492
- className: orClasses2.swapDetailsLink,
493
- href: row.href,
494
- rel: "noreferrer",
495
- target: "_blank"
496
- },
497
- row.hrefLabel ?? checkoutLabels2.viewOnExplorer
498
- )
499
- )
500
- )
501
- ];
502
- }
503
- function TransactionDetailCopyButton(props) {
504
- const [copied, setCopied] = useTransientValue(false);
505
- const label = copied ? checkoutLabels2.copied : "Copy";
506
- return React4.createElement(
507
- "button",
508
- {
509
- className: orClasses2.detailCopy,
510
- type: "button",
511
- "aria-label": label,
512
- title: label,
513
- onClick: () => {
514
- void copyText(props.value, props.clipboard).then(() => setCopied(true)).catch((error) => props.onError?.(error));
515
- }
516
- },
517
- React4.createElement(ClipboardIcon)
518
- );
519
- }
520
-
521
433
  // src/theme.ts
522
- import * as React5 from "react";
434
+ import * as React4 from "react";
523
435
  import {
524
436
  OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES as OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES2,
525
437
  OPENRECEIVE_THEME_STORAGE_KEY,
526
438
  createThemeModel,
527
- orClasses as orClasses3,
439
+ orClasses as orClasses2,
528
440
  readThemePreference,
529
441
  writeThemePreference
530
442
  } from "@openreceive/browser/headless";
531
- var ThemeContext = React5.createContext(null);
443
+ var ThemeContext = React4.createContext(null);
532
444
  var storedThemeListeners = /* @__PURE__ */ new Set();
533
445
  var lastSetTheme = /* @__PURE__ */ new Map();
534
446
  function notifyStoredThemeChange() {
@@ -557,9 +469,10 @@ function useLocalTheme(options = {}) {
557
469
  const storageKey = options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY;
558
470
  const storage = options.storage;
559
471
  const defaultTheme = options.defaultTheme;
560
- const theme = React5.useSyncExternalStore(
472
+ const lockedTheme = options.theme;
473
+ const theme = React4.useSyncExternalStore(
561
474
  subscribeStoredTheme,
562
- React5.useCallback(
475
+ React4.useCallback(
563
476
  () => readThemePreference({
564
477
  storage,
565
478
  storageKey,
@@ -567,7 +480,7 @@ function useLocalTheme(options = {}) {
567
480
  }),
568
481
  [storage, storageKey, defaultTheme]
569
482
  ),
570
- React5.useCallback(
483
+ React4.useCallback(
571
484
  () => (
572
485
  // A host-supplied storage is readable on the server (that is how SSR theming is
573
486
  // wired); the implicit browser localStorage is not, so fall back to the default.
@@ -576,14 +489,15 @@ function useLocalTheme(options = {}) {
576
489
  [storage, storageKey, defaultTheme]
577
490
  )
578
491
  );
579
- const systemDark = React5.useSyncExternalStore(
492
+ const systemDark = React4.useSyncExternalStore(
580
493
  subscribeSystemDark,
581
494
  getSystemDark,
582
495
  getServerSystemDark
583
496
  );
584
- const themeModel = createThemeModel(theme, { systemDark });
585
- const setTheme = React5.useCallback(
497
+ const themeModel = createThemeModel(lockedTheme ?? theme, { systemDark });
498
+ const setTheme = React4.useCallback(
586
499
  (nextTheme) => {
500
+ if (lockedTheme !== void 0) return;
587
501
  lastSetTheme.set(storageKey, nextTheme);
588
502
  writeThemePreference(nextTheme, {
589
503
  storage,
@@ -591,13 +505,13 @@ function useLocalTheme(options = {}) {
591
505
  });
592
506
  notifyStoredThemeChange();
593
507
  },
594
- [storage, storageKey]
508
+ [storage, storageKey, lockedTheme]
595
509
  );
596
- const toggleTheme = React5.useCallback(() => {
510
+ const toggleTheme = React4.useCallback(() => {
597
511
  setTheme(themeModel.nextTheme);
598
512
  }, [setTheme, themeModel.nextTheme]);
599
513
  return {
600
- theme,
514
+ theme: lockedTheme ?? theme,
601
515
  resolvedTheme: themeModel.resolvedTheme,
602
516
  model: themeModel,
603
517
  nextTheme: themeModel.nextTheme,
@@ -610,10 +524,10 @@ function useLocalTheme(options = {}) {
610
524
  };
611
525
  }
612
526
  function useTheme(options = {}) {
613
- const scoped = React5.useContext(ThemeContext);
527
+ const scoped = React4.useContext(ThemeContext);
614
528
  const local = useLocalTheme(options);
615
529
  const storageKey = options.storageKey ?? OPENRECEIVE_THEME_STORAGE_KEY;
616
- if (scoped !== null && options.storage === void 0 && (options.storageKey === void 0 || options.storageKey === storageKey) && options.defaultTheme === void 0) {
530
+ if (scoped !== null && options.theme === void 0 && options.storage === void 0 && (options.storageKey === void 0 || options.storageKey === storageKey) && options.defaultTheme === void 0) {
617
531
  return { ...scoped, fromScope: true };
618
532
  }
619
533
  return local;
@@ -637,7 +551,7 @@ function ThemeToggle(props) {
637
551
  const componentProps = {
638
552
  ...buttonProps,
639
553
  "aria-label": themeModel.toggleLabel,
640
- className: joinClassNames(orClasses3.themeToggle, buttonProps.className),
554
+ className: joinClassNames(orClasses2.themeToggle, buttonProps.className),
641
555
  title: themeModel.toggleLabel,
642
556
  type,
643
557
  [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES2.themeToggle]: "",
@@ -648,7 +562,7 @@ function ThemeToggle(props) {
648
562
  if (onThemeChange === void 0) fallback.setTheme(themeModel.nextTheme);
649
563
  }
650
564
  };
651
- return React5.createElement(ButtonComponent, componentProps, children ?? themeModel.toggleLabel);
565
+ return React4.createElement(ButtonComponent, componentProps, children ?? themeModel.toggleLabel);
652
566
  }
653
567
  function ThemeScope(props) {
654
568
  const {
@@ -656,6 +570,7 @@ function ThemeScope(props) {
656
570
  defaultTheme,
657
571
  storageKey,
658
572
  storage,
573
+ theme: lockedTheme,
659
574
  themeToggle = false,
660
575
  topbarClassName,
661
576
  themeToggleClassName,
@@ -666,25 +581,27 @@ function ThemeScope(props) {
666
581
  const theme = useLocalTheme({
667
582
  defaultTheme,
668
583
  storageKey,
669
- storage
584
+ storage,
585
+ theme: lockedTheme
670
586
  });
671
587
  const scopedChildren = typeof children === "function" ? children(theme) : children;
672
- return React5.createElement(
588
+ const showsToggle = themeToggle && lockedTheme === void 0;
589
+ return React4.createElement(
673
590
  ThemeContext.Provider,
674
591
  { value: theme },
675
592
  // Variadic children, not an array: an array child needs a key on every entry.
676
- React5.createElement(
593
+ React4.createElement(
677
594
  Element,
678
595
  {
679
596
  ...elementProps,
680
597
  ...theme.attributes
681
598
  },
682
- themeToggle ? React5.createElement(
599
+ showsToggle ? React4.createElement(
683
600
  "div",
684
601
  {
685
602
  className: topbarClassName
686
603
  },
687
- React5.createElement(ThemeToggle, {
604
+ React4.createElement(ThemeToggle, {
688
605
  className: themeToggleClassName,
689
606
  theme: theme.theme,
690
607
  resolvedTheme: theme.resolvedTheme,
@@ -697,6 +614,95 @@ function ThemeScope(props) {
697
614
  );
698
615
  }
699
616
 
617
+ // src/transaction-details.ts
618
+ import {
619
+ checkoutLabels as checkoutLabels2,
620
+ orClasses as orClasses3,
621
+ resolveTransactionDetailRows
622
+ } from "@openreceive/browser/headless";
623
+ import * as React5 from "react";
624
+ function TransactionDetails(props) {
625
+ const rows = resolveTransactionDetailRows(props.state);
626
+ if (rows.length === 0) return null;
627
+ return React5.createElement(
628
+ "details",
629
+ {
630
+ className: joinClassNames(orClasses3.transactionDetails, props.className),
631
+ open: props.open === true ? true : void 0
632
+ },
633
+ React5.createElement(
634
+ "summary",
635
+ { className: orClasses3.transactionDetailsTitle },
636
+ checkoutLabels2.transactionDetails
637
+ ),
638
+ React5.createElement(
639
+ "div",
640
+ { className: orClasses3.transactionDetailsContent },
641
+ React5.createElement(
642
+ "dl",
643
+ { className: orClasses3.swapDetails },
644
+ rows.flatMap(
645
+ (row) => renderTransactionDetailRow(row, {
646
+ clipboard: props.clipboard,
647
+ onError: props.onError
648
+ })
649
+ )
650
+ )
651
+ )
652
+ );
653
+ }
654
+ function renderTransactionDetailRow(row, options) {
655
+ const copyValue = row.copyValue ?? row.value;
656
+ return [
657
+ React5.createElement(
658
+ "dt",
659
+ { key: `${row.label}-label`, className: orClasses3.swapDetailsDt },
660
+ row.label
661
+ ),
662
+ React5.createElement(
663
+ "dd",
664
+ { key: `${row.label}-value`, className: orClasses3.swapDetailsDd },
665
+ React5.createElement("code", { className: orClasses3.swapDetailsCode }, row.value),
666
+ React5.createElement(
667
+ "div",
668
+ { className: orClasses3.swapDetailsActions },
669
+ React5.createElement(TransactionDetailCopyButton, {
670
+ value: copyValue,
671
+ clipboard: options.clipboard,
672
+ onError: options.onError
673
+ }),
674
+ row.href === void 0 ? null : React5.createElement(
675
+ "a",
676
+ {
677
+ className: orClasses3.swapDetailsLink,
678
+ href: row.href,
679
+ rel: "noreferrer",
680
+ target: "_blank"
681
+ },
682
+ row.hrefLabel ?? checkoutLabels2.viewOnExplorer
683
+ )
684
+ )
685
+ )
686
+ ];
687
+ }
688
+ function TransactionDetailCopyButton(props) {
689
+ const [copied, setCopied] = useTransientValue(false);
690
+ const label = copied ? checkoutLabels2.copied : "Copy";
691
+ return React5.createElement(
692
+ "button",
693
+ {
694
+ className: orClasses3.detailCopy,
695
+ type: "button",
696
+ "aria-label": label,
697
+ title: label,
698
+ onClick: () => {
699
+ void copyText(props.value, props.clipboard).then(() => setCopied(true)).catch((error) => props.onError?.(error));
700
+ }
701
+ },
702
+ React5.createElement(ClipboardIcon)
703
+ );
704
+ }
705
+
700
706
  // src/use-checkout.ts
701
707
  import * as React6 from "react";
702
708
  import {
@@ -935,8 +941,10 @@ import {
935
941
  createMethodGridDisplay,
936
942
  createPaymentWizardController,
937
943
  createPaymentWizardModel,
944
+ createSwapDisplayModel as createSwapDisplayModel2,
938
945
  createWizardRouteAssetDisplays,
939
946
  createWizardRouteDisplays,
947
+ formatMethodNetworkDetail,
940
948
  formatNetworkSummary,
941
949
  getNetworkIcon,
942
950
  getPaymentMethodIcon,
@@ -1199,16 +1207,17 @@ function ProviderTutorialModal(options) {
1199
1207
 
1200
1208
  // src/swap.ts
1201
1209
  import {
1210
+ checkoutLabels as checkoutLabels4,
1202
1211
  createDetailExternalLink,
1212
+ createQrSvgController as createQrSvgController2,
1203
1213
  createSwapDisplayModel,
1214
+ createSwapUnavailableModel,
1204
1215
  createTransactionDetails,
1205
- createQrSvgController as createQrSvgController2,
1216
+ currentCheckoutUrl,
1206
1217
  getSwapRefundFormError,
1207
- checkoutLabels as checkoutLabels4,
1208
- createSwapUnavailableModel,
1209
- swapOptionLimitMessage,
1210
1218
  orClasses as orClasses5,
1211
- selectCheckoutDisplayInvoice
1219
+ selectCheckoutDisplayInvoice,
1220
+ swapOptionLimitMessage
1212
1221
  } from "@openreceive/browser/headless";
1213
1222
  import * as React8 from "react";
1214
1223
  function renderSwapActions(options) {
@@ -1339,6 +1348,25 @@ function renderSwapDepositPanel(options) {
1339
1348
  display.providerStateDetail
1340
1349
  )
1341
1350
  );
1351
+ const refundHeading = React8.createElement(
1352
+ "div",
1353
+ { className: orClasses5.swapRefundHeading, role: "alert" },
1354
+ renderAlertIcon("warning"),
1355
+ React8.createElement(
1356
+ "div",
1357
+ { className: orClasses5.swapNetworkWarningContent },
1358
+ React8.createElement(
1359
+ "strong",
1360
+ { className: orClasses5.swapHeadingTitle },
1361
+ display.providerStateLabel
1362
+ ),
1363
+ React8.createElement(
1364
+ "span",
1365
+ { className: orClasses5.swapHeadingDetail },
1366
+ display.providerStateDetail
1367
+ )
1368
+ )
1369
+ );
1342
1370
  const waitingCard = (countdownLabel) => React8.createElement(WaitingState, {
1343
1371
  waiting: true,
1344
1372
  statusTitle: display.providerStateLabel,
@@ -1443,26 +1471,20 @@ function renderSwapDepositPanel(options) {
1443
1471
  {
1444
1472
  className: orClasses5.swapPanel
1445
1473
  },
1446
- heading,
1447
- renderSwapRefundFacts(display, options),
1448
- React8.createElement(
1449
- "p",
1450
- {
1451
- className: orClasses5.swapWarning
1452
- },
1453
- `Use a ${display.networkLabel} address you control. Do not paste the deposit address.`
1454
- ),
1474
+ refundHeading,
1475
+ renderSwapRefundReturnWarning(display, options),
1476
+ renderSwapAmountFacts(display),
1455
1477
  React8.createElement(SwapRefundForm, {
1456
1478
  attemptId: display.attemptId,
1457
1479
  payInAsset: display.payInAsset,
1458
1480
  networkLabel: display.networkLabel,
1481
+ ...display.refundReason === void 0 ? {} : { refundReason: display.refundReason },
1459
1482
  submittedRefundAddress: display.refundAddress,
1460
1483
  refundAllowed: display.refundAllowed,
1461
1484
  onRefund: options.onRefund,
1462
1485
  onError: options.onError
1463
1486
  }),
1464
- renderSwapSupportDetails(display, options),
1465
- renderSwapRefundReturnWarning(display)
1487
+ renderSwapSupportDetails(display, options)
1466
1488
  );
1467
1489
  }
1468
1490
  if (display.state === "refund_pending" || display.state === "refunded") {
@@ -1471,8 +1493,9 @@ function renderSwapDepositPanel(options) {
1471
1493
  {
1472
1494
  className: orClasses5.swapPanel
1473
1495
  },
1474
- heading,
1475
- renderSwapRefundFacts(display, options),
1496
+ refundHeading,
1497
+ renderSwapRefundReturnWarning(display, options),
1498
+ renderSwapAmountFacts(display),
1476
1499
  React8.createElement(
1477
1500
  "dl",
1478
1501
  {
@@ -1489,8 +1512,7 @@ function renderSwapDepositPanel(options) {
1489
1512
  payInAsset: display.payInAsset
1490
1513
  })
1491
1514
  ),
1492
- renderSwapSupportDetails(display, options),
1493
- renderSwapRefundReturnWarning(display)
1515
+ renderSwapSupportDetails(display, options)
1494
1516
  );
1495
1517
  }
1496
1518
  if (display.state === "deposit") {
@@ -1514,11 +1536,15 @@ function renderSwapDepositPanel(options) {
1514
1536
  {
1515
1537
  className: orClasses5.swapDepositLayout
1516
1538
  },
1517
- React8.createElement(SwapPayloadQRCode, {
1518
- payload: display.qrPayload,
1519
- encoder: options.encoder,
1520
- onError: options.onError
1521
- }),
1539
+ React8.createElement(
1540
+ "div",
1541
+ { className: orClasses5.swapQrFrame },
1542
+ React8.createElement(SwapPayloadQRCode, {
1543
+ payload: display.qrPayload,
1544
+ encoder: options.encoder,
1545
+ onError: options.onError
1546
+ })
1547
+ ),
1522
1548
  React8.createElement(
1523
1549
  "div",
1524
1550
  {
@@ -1554,9 +1580,10 @@ function renderSwapDepositPanel(options) {
1554
1580
  React8.createElement(
1555
1581
  "p",
1556
1582
  { className: orClasses5.swapWarning },
1557
- checkoutLabels4.supportReviewNeeded
1583
+ checkoutLabels4.supportReviewFacts
1558
1584
  ),
1559
- renderSwapSupportDetails(display, options),
1585
+ renderSwapAmountFacts(display),
1586
+ renderSwapSupportDetails(display, options, { open: true }),
1560
1587
  backButton
1561
1588
  );
1562
1589
  }
@@ -1610,26 +1637,45 @@ function renderSwapNetworkWarning(display) {
1610
1637
  )
1611
1638
  );
1612
1639
  }
1613
- function renderSwapRefundFacts(display, options) {
1640
+ function renderSwapAmountFacts(display) {
1614
1641
  const rows = [
1615
- ...display.depositReceivedAmount === void 0 ? [] : renderSwapCopyRow(
1616
- "Amount received",
1617
- `${display.depositReceivedAmount} ${display.assetLabel}`,
1618
- options
1619
- ),
1620
- ...display.depositReceivedAmount === void 0 ? [] : renderSwapCopyRow(
1621
- "Amount required",
1622
- `${display.depositAmount} ${display.assetLabel}`,
1623
- options
1624
- ),
1625
- ...display.refundAmount === void 0 ? [] : renderSwapCopyRow(
1626
- "Estimated refund",
1627
- `${display.refundAmount} ${display.assetLabel}`,
1628
- options
1629
- )
1642
+ ...display.depositReceivedAmount === void 0 ? [] : [
1643
+ ["Amount received", `${display.depositReceivedAmount} ${display.assetLabel}`],
1644
+ ["Amount required", `${display.depositAmount} ${display.assetLabel}`]
1645
+ ],
1646
+ ...display.refundAmount === void 0 ? [] : [["Estimated refund", `${display.refundAmount} ${display.assetLabel}`]]
1630
1647
  ];
1631
1648
  if (rows.length === 0) return null;
1632
- return React8.createElement("dl", { className: orClasses5.swapDetails }, rows);
1649
+ return React8.createElement(
1650
+ "dl",
1651
+ { className: orClasses5.swapFacts },
1652
+ rows.map(
1653
+ ([label, value]) => React8.createElement(
1654
+ "div",
1655
+ { key: label, className: orClasses5.swapFactsRow },
1656
+ React8.createElement("dt", { className: orClasses5.swapFactsLabel }, label),
1657
+ React8.createElement("dd", { className: orClasses5.swapFactsValue }, value)
1658
+ )
1659
+ )
1660
+ );
1661
+ }
1662
+ function renderAlertIcon(kind) {
1663
+ return React8.createElement(
1664
+ "svg",
1665
+ {
1666
+ xmlns: "http://www.w3.org/2000/svg",
1667
+ fill: "none",
1668
+ viewBox: "0 0 24 24",
1669
+ className: orClasses5.swapNetworkWarningIcon,
1670
+ "aria-hidden": "true"
1671
+ },
1672
+ React8.createElement("path", {
1673
+ strokeLinecap: "round",
1674
+ strokeLinejoin: "round",
1675
+ strokeWidth: 2,
1676
+ 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"
1677
+ })
1678
+ );
1633
1679
  }
1634
1680
  function renderSwapFeeBreakdown(breakdown) {
1635
1681
  if (breakdown === void 0) return null;
@@ -1728,7 +1774,7 @@ function SwapCopyButton(props) {
1728
1774
  React8.createElement(ClipboardIcon)
1729
1775
  );
1730
1776
  }
1731
- function renderSwapSupportDetails(display, options) {
1777
+ function renderSwapSupportDetails(display, options, view = {}) {
1732
1778
  const rowOptions = { ...options, payInAsset: display.payInAsset };
1733
1779
  const rows = [
1734
1780
  ...display.depositTxId === void 0 ? [] : renderSwapCopyRow("Deposit transaction", display.depositTxId, rowOptions),
@@ -1740,7 +1786,8 @@ function renderSwapSupportDetails(display, options) {
1740
1786
  return React8.createElement(
1741
1787
  "details",
1742
1788
  {
1743
- className: orClasses5.swapSupport
1789
+ className: orClasses5.swapSupport,
1790
+ ...view.open === true ? { open: true } : {}
1744
1791
  },
1745
1792
  React8.createElement("summary", { className: orClasses5.swapSupportTitle }, "Payment details"),
1746
1793
  React8.createElement(
@@ -1750,13 +1797,57 @@ function renderSwapSupportDetails(display, options) {
1750
1797
  )
1751
1798
  );
1752
1799
  }
1753
- function renderSwapRefundReturnWarning(display) {
1800
+ function renderSwapRefundReturnWarning(display, options) {
1801
+ const url = display.resumable ? currentCheckoutUrl() : void 0;
1754
1802
  return React8.createElement(
1755
- "p",
1756
- {
1757
- className: orClasses5.swapWarning
1758
- },
1759
- display.refundReturnLabel
1803
+ "div",
1804
+ { className: orClasses5.swapRefundReturn },
1805
+ renderAlertIcon("bookmark"),
1806
+ React8.createElement(
1807
+ "div",
1808
+ { className: orClasses5.swapNetworkWarningContent },
1809
+ React8.createElement(
1810
+ "p",
1811
+ { className: orClasses5.swapRefundReturnTitle },
1812
+ checkoutLabels4.refundReturnTitle
1813
+ ),
1814
+ React8.createElement(
1815
+ "p",
1816
+ { className: orClasses5.swapRefundReturnBody },
1817
+ display.refundReturnLabel
1818
+ ),
1819
+ url === void 0 ? null : React8.createElement(
1820
+ "dl",
1821
+ { className: orClasses5.swapDetails },
1822
+ ...renderSwapCopyRow(checkoutLabels4.refundReturnUrlLabel, url, {
1823
+ ...options,
1824
+ selectable: true
1825
+ })
1826
+ )
1827
+ )
1828
+ );
1829
+ }
1830
+ function renderKeepOrderNote(options) {
1831
+ if (options.resumable !== true) return null;
1832
+ const reference = options.reference ?? "";
1833
+ const url = currentCheckoutUrl();
1834
+ if (reference.length === 0 && url === void 0) return null;
1835
+ const rowOptions = { ...options, selectable: true };
1836
+ return React8.createElement(
1837
+ "div",
1838
+ { className: orClasses5.keepOrder },
1839
+ React8.createElement(
1840
+ "p",
1841
+ { className: orClasses5.swapSectionTitle },
1842
+ checkoutLabels4.keepOrderTitle
1843
+ ),
1844
+ React8.createElement("p", { className: orClasses5.keepOrderBody }, checkoutLabels4.keepOrderBody),
1845
+ React8.createElement(
1846
+ "dl",
1847
+ { className: orClasses5.swapDetails },
1848
+ ...reference.length === 0 ? [] : renderSwapCopyRow(checkoutLabels4.keepOrderIdLabel, reference, rowOptions),
1849
+ ...url === void 0 ? [] : renderSwapCopyRow(checkoutLabels4.keepOrderUrlLabel, url, rowOptions)
1850
+ )
1760
1851
  );
1761
1852
  }
1762
1853
  var REFUND_ADDRESS_DRAFT_LIMIT = 8;
@@ -1799,10 +1890,30 @@ function SwapRefundForm(props) {
1799
1890
  void props.onRefund(props.attemptId, address, confirm).catch(props.onError).finally(() => setSubmitting(false));
1800
1891
  }
1801
1892
  },
1893
+ // The form says what it is and why it is here before it asks for anything:
1894
+ // a bare input under a red banner is a payer guessing what to type.
1895
+ React8.createElement(
1896
+ "p",
1897
+ { className: orClasses5.swapSectionTitle },
1898
+ checkoutLabels4.refundSectionTitle
1899
+ ),
1900
+ props.refundReason === void 0 ? null : React8.createElement(
1901
+ "p",
1902
+ { className: orClasses5.swapRefundReason },
1903
+ checkoutLabels4.refundReasonLabel.replace(
1904
+ "{reason}",
1905
+ props.refundReason.replace(/_/g, " ")
1906
+ )
1907
+ ),
1908
+ React8.createElement(
1909
+ "p",
1910
+ { className: orClasses5.swapRefundInstruction },
1911
+ checkoutLabels4.refundAddressOwnership.replace("{network}", props.networkLabel)
1912
+ ),
1802
1913
  props.submittedRefundAddress === void 0 ? null : React8.createElement(
1803
1914
  "p",
1804
1915
  {
1805
- className: orClasses5.swapWarning
1916
+ className: orClasses5.swapRefundInstruction
1806
1917
  },
1807
1918
  checkoutLabels4.confirmRefundTo.replace("{address}", props.submittedRefundAddress)
1808
1919
  ),
@@ -2007,6 +2118,18 @@ function PaymentWizard(props) {
2007
2118
  stickySwapInvoiceRef.current = void 0;
2008
2119
  }
2009
2120
  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;
2121
+ const resumeAdoptedRef = React9.useRef(false);
2122
+ React9.useEffect(() => {
2123
+ if (resumeAdoptedRef.current) return;
2124
+ if (selectedSwapAsset !== null) {
2125
+ resumeAdoptedRef.current = true;
2126
+ return;
2127
+ }
2128
+ const payInAsset = currentSwapInvoice?.swap?.pay_in_asset;
2129
+ if (payInAsset === void 0) return;
2130
+ resumeAdoptedRef.current = true;
2131
+ setSelectedSwapAsset(payInAsset);
2132
+ }, [currentSwapInvoice, selectedSwapAsset]);
2010
2133
  React9.useEffect(() => {
2011
2134
  if (selectedSwapAsset === null) return;
2012
2135
  if (props.prefix === void 0) return;
@@ -2018,6 +2141,18 @@ function PaymentWizard(props) {
2018
2141
  const selectedSwapOption = selectedSwapAsset === null ? void 0 : swapAssetOptions.find((option) => option.pay_in_asset === selectedSwapAsset) ?? session.swapQuotes[selectedSwapAsset];
2019
2142
  const selectedSwapQuote = selectedSwapAsset === null ? void 0 : session.swapQuotes[selectedSwapAsset];
2020
2143
  const selectedSwapLabel = selectedSwapOption?.label ?? "this coin";
2144
+ const activeSwapState = activeSwapForAsset === void 0 ? void 0 : createSwapDisplayModel2(activeSwapForAsset, {
2145
+ ...now === void 0 ? {} : { now },
2146
+ ...props.resumable === void 0 ? {} : { resumable: props.resumable }
2147
+ })?.state;
2148
+ const refundOwed = activeSwapState === "refund_required";
2149
+ const refundStage = activeSwapState?.startsWith("refund") ?? false;
2150
+ const keepOrderNote = renderKeepOrderNote({
2151
+ ...checkout?.reference === void 0 ? {} : { reference: checkout.reference },
2152
+ ...props.resumable === void 0 ? {} : { resumable: props.resumable },
2153
+ ...props.clipboard === void 0 ? {} : { clipboard: props.clipboard },
2154
+ ...props.onError === void 0 ? {} : { onError: props.onError }
2155
+ });
2021
2156
  if (selectedSwapAsset !== null) {
2022
2157
  return React9.createElement(
2023
2158
  "div",
@@ -2027,7 +2162,7 @@ function PaymentWizard(props) {
2027
2162
  React9.createElement(
2028
2163
  "div",
2029
2164
  { className: orClasses6.wizardBody },
2030
- renderWizardBackBreadcrumb(
2165
+ refundOwed ? null : renderWizardBackBreadcrumb(
2031
2166
  selectedSwapOption === void 0 ? selectedSwapLabel : `${selectedSwapOption.label} \xB7 ${selectedSwapOption.network_label}`,
2032
2167
  clearSwapFocus
2033
2168
  ),
@@ -2055,7 +2190,8 @@ function PaymentWizard(props) {
2055
2190
  void props.onRequestLightning?.();
2056
2191
  }
2057
2192
  }) : selectedSwapQuote !== void 0 && !selectedSwapQuote.available ? renderSwapUnavailable(selectedSwapQuote, checkout) : renderSwapPreparing(selectedSwapLabel)
2058
- )
2193
+ ),
2194
+ refundStage ? null : keepOrderNote
2059
2195
  )
2060
2196
  );
2061
2197
  }
@@ -2118,6 +2254,13 @@ function PaymentWizard(props) {
2118
2254
  onContinueSwap: selectSwapAsset,
2119
2255
  ...resolveAssetUrl === void 0 ? {} : { resolveAssetUrl }
2120
2256
  }) : null,
2257
+ // On the grid the note is a section of its own, under the tiles: there is no
2258
+ // body to put it in until a method is chosen.
2259
+ selection.selectedMethod === null && keepOrderNote !== null ? React9.createElement(
2260
+ "div",
2261
+ { key: "keep-order", className: orClasses6.wizardBody },
2262
+ keepOrderNote
2263
+ ) : null,
2121
2264
  selection.selectedMethod === null ? null : React9.createElement(
2122
2265
  "div",
2123
2266
  { className: orClasses6.wizardBody },
@@ -2246,7 +2389,8 @@ function PaymentWizard(props) {
2246
2389
  ) : null
2247
2390
  );
2248
2391
  })
2249
- )
2392
+ ),
2393
+ keepOrderNote
2250
2394
  ),
2251
2395
  activeTutorialProvider === void 0 || activeTutorial === null ? null : React9.createElement(ProviderTutorialModal, {
2252
2396
  key: "provider-tutorial",
@@ -2482,7 +2626,15 @@ function renderCompactPaymentMethodSelector(options) {
2482
2626
  React9.createElement(
2483
2627
  "span",
2484
2628
  { className: orClasses6.methodTitleWrap },
2485
- React9.createElement("span", { className: orClasses6.methodTitle }, method.title)
2629
+ React9.createElement("span", { className: orClasses6.methodTitle }, method.title),
2630
+ // The tile's own description. A grid of five names is a grid of
2631
+ // five questions; `paymentMethods` has carried the answer all
2632
+ // along and only the mobile layout was printing it.
2633
+ React9.createElement(
2634
+ "span",
2635
+ { className: orClasses6.methodTileDetail },
2636
+ method.detail
2637
+ )
2486
2638
  )
2487
2639
  );
2488
2640
  }
@@ -2492,7 +2644,6 @@ function renderCompactPaymentMethodSelector(options) {
2492
2644
  selected,
2493
2645
  multiNetwork,
2494
2646
  displayOption,
2495
- selectedOption,
2496
2647
  starting,
2497
2648
  disabled,
2498
2649
  accent,
@@ -2542,11 +2693,11 @@ function renderCompactPaymentMethodSelector(options) {
2542
2693
  "span",
2543
2694
  { className: orClasses6.methodTitleWrap },
2544
2695
  React9.createElement("span", { className: orClasses6.methodTitle }, group.label),
2545
- !disabled && multiNetwork ? React9.createElement(
2696
+ React9.createElement(
2546
2697
  "span",
2547
- { className: orClasses6.methodDetailMobile },
2548
- selected && selectedOption !== void 0 ? `${selectedOption.network_label} network` : checkoutLabels5.selectNetwork
2549
- ) : null
2698
+ { className: orClasses6.methodTileDetail },
2699
+ formatMethodNetworkDetail(group.options)
2700
+ )
2550
2701
  )
2551
2702
  ),
2552
2703
  disabled && limitMessage !== void 0 ? React9.createElement("span", { className: orClasses6.methodLimitHint }, limitMessage) : null,
@@ -2726,7 +2877,8 @@ function Checkout(props) {
2726
2877
  metadata: props.metadata,
2727
2878
  syncUrl: props.syncUrl,
2728
2879
  resumePathPrefix: props.resumePathPrefix,
2729
- routeReference: props.routeReference
2880
+ routeReference: props.routeReference,
2881
+ resumePaymentHash: props.resumePaymentHash
2730
2882
  });
2731
2883
  const { checkout } = props;
2732
2884
  if (checkout !== void 0) {
@@ -2769,7 +2921,8 @@ function CheckoutCreate(props) {
2769
2921
  classNames,
2770
2922
  syncUrl = false,
2771
2923
  resumePathPrefix = "/checkout",
2772
- routeReference
2924
+ routeReference,
2925
+ resumePaymentHash
2773
2926
  } = props;
2774
2927
  const [created, setCreated] = React10.useState({ status: "pending" });
2775
2928
  const [attempt, setAttempt] = React10.useState(0);
@@ -2810,7 +2963,15 @@ function CheckoutCreate(props) {
2810
2963
  prefix: resolvedPrefix,
2811
2964
  reference,
2812
2965
  ...createFetchRef.current === void 0 ? {} : { fetch: createFetchRef.current }
2813
- }).then((checkout) => {
2966
+ }).then(
2967
+ (checkout) => resumePaymentHash === void 0 ? checkout : resumeSwapAttempt({
2968
+ fetch: createFetchRef.current ?? globalThis.fetch,
2969
+ prefix: resolvedPrefix,
2970
+ reference,
2971
+ paymentHash: resumePaymentHash,
2972
+ snapshot: checkout
2973
+ })
2974
+ ).then((checkout) => {
2814
2975
  if (!cancelled) setCreated({ status: "ready", checkout });
2815
2976
  }).catch((error) => {
2816
2977
  if (cancelled) return;
@@ -2823,7 +2984,7 @@ function CheckoutCreate(props) {
2823
2984
  return () => {
2824
2985
  cancelled = true;
2825
2986
  };
2826
- }, [reference, resolvedPrefix, attempt]);
2987
+ }, [reference, resolvedPrefix, resumePaymentHash, attempt]);
2827
2988
  const onSwapStarted = React10.useCallback(
2828
2989
  (invoice) => {
2829
2990
  setCreated((current) => {
@@ -2908,6 +3069,9 @@ function CheckoutView(props) {
2908
3069
  syncUrl,
2909
3070
  resumePathPrefix: _resumePathPrefix,
2910
3071
  routeReference,
3072
+ // Consumed by CheckoutCreate before the view exists; destructured out here
3073
+ // so it never reaches the rendered <section> as an attribute.
3074
+ resumePaymentHash: _resumePaymentHash,
2911
3075
  resumable,
2912
3076
  onRequestLightning,
2913
3077
  onSwapStarted,
@@ -2927,6 +3091,7 @@ function CheckoutView(props) {
2927
3091
  pollIntervalMs,
2928
3092
  paymentWizard = true,
2929
3093
  themeToggle = true,
3094
+ theme: lockedTheme,
2930
3095
  defaultTheme,
2931
3096
  storageKey,
2932
3097
  components,
@@ -2952,9 +3117,11 @@ function CheckoutView(props) {
2952
3117
  });
2953
3118
  const theme = useTheme({
2954
3119
  defaultTheme,
2955
- storageKey
3120
+ storageKey,
3121
+ theme: lockedTheme
2956
3122
  });
2957
- const ownsTheme = themeToggle && !theme.fromScope;
3123
+ const stampsTheme = !theme.fromScope;
3124
+ const ownsTheme = themeToggle && !theme.fromScope && lockedTheme === void 0;
2958
3125
  const [swapFocused, setSwapFocused] = React10.useState(false);
2959
3126
  const QRCodeComponent = components?.QRCode ?? QRCode;
2960
3127
  const InvoiceSummaryComponent = components?.InvoiceSummary ?? InvoiceSummary;
@@ -3001,206 +3168,207 @@ function CheckoutView(props) {
3001
3168
  className: joinClassNames(className, orClasses7.root, classNames?.root),
3002
3169
  [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.root]: "",
3003
3170
  // Under ThemeScope, inherit data-theme from the page. Standalone Checkout owns it.
3004
- ...ownsTheme ? theme.attributes : {}
3171
+ ...stampsTheme ? theme.attributes : {}
3005
3172
  },
3006
- customChildren === void 0 ? [
3007
- // Above the amount and OUTSIDE the Lightning pane, which drops out on
3008
- // the swap deposit panel, on expiry and on the receipt — the payer
3009
- // needs to know what they are buying on all four screens.
3010
- checkoutModel.checkout.description === void 0 || checkoutModel.checkout.description === "" ? null : React10.createElement(
3011
- "p",
3012
- {
3013
- key: "order-description",
3014
- className: joinClassNames(
3015
- orClasses7.orderDescription,
3016
- classNames?.orderDescription
3017
- ),
3018
- [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.orderDescription]: ""
3019
- },
3020
- checkoutModel.checkout.description
3021
- ),
3022
- ownsTheme ? React10.createElement(ThemeToggle, {
3023
- key: "theme",
3024
- className: classNames?.themeToggle,
3025
- theme: theme.theme,
3026
- resolvedTheme: theme.resolvedTheme,
3027
- onThemeChange: theme.setTheme,
3028
- ButtonComponent
3029
- }) : null,
3030
- mintingLightning ? React10.createElement(
3031
- "div",
3032
- {
3033
- key: "minting-lightning",
3034
- className: orClasses7.creating
3035
- },
3036
- React10.createElement("span", {
3037
- className: orClasses7.spinner,
3038
- "aria-hidden": "true"
3039
- }),
3040
- React10.createElement("p", null, checkoutLabels6.preparingPayment)
3041
- ) : null,
3042
- hideLightning ? null : React10.createElement(
3043
- "div",
3044
- {
3045
- key: "payment-layout",
3046
- className: expired || settled ? orClasses7.paymentLayoutExpired : orClasses7.paymentLayout
3047
- },
3048
- lightningPane,
3049
- React10.createElement(
3173
+ [
3174
+ // Order context from the host, composed ABOVE the shipped payment UI —
3175
+ // the same position as the custom element's `order` slot. Children never
3176
+ // replace the payment UI; a host that wants its own checkout builds on
3177
+ // useCheckout / @openreceive/browser/headless instead.
3178
+ customChildren === void 0 ? null : React10.createElement(React10.Fragment, { key: "order-children" }, customChildren),
3179
+ ...[
3180
+ // Above the amount and OUTSIDE the Lightning pane, which drops out on
3181
+ // the swap deposit panel, on expiry and on the receipt — the payer
3182
+ // needs to know what they are buying on all four screens.
3183
+ checkoutModel.checkout.description === void 0 || checkoutModel.checkout.description === "" ? null : React10.createElement(
3184
+ "p",
3185
+ {
3186
+ key: "order-description",
3187
+ className: joinClassNames(orClasses7.orderDescription, classNames?.orderDescription),
3188
+ [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.orderDescription]: ""
3189
+ },
3190
+ checkoutModel.checkout.description
3191
+ ),
3192
+ ownsTheme ? React10.createElement(ThemeToggle, {
3193
+ key: "theme",
3194
+ className: classNames?.themeToggle,
3195
+ theme: theme.theme,
3196
+ resolvedTheme: theme.resolvedTheme,
3197
+ onThemeChange: theme.setTheme,
3198
+ ButtonComponent
3199
+ }) : null,
3200
+ mintingLightning ? React10.createElement(
3050
3201
  "div",
3051
3202
  {
3052
- key: "payment-info",
3053
- className: orClasses7.paymentInfo
3203
+ key: "minting-lightning",
3204
+ className: orClasses7.creating
3054
3205
  },
3055
- expired || settled ? null : React10.createElement(
3056
- "p",
3057
- {
3058
- key: "invoice-title",
3059
- className: joinClassNames(
3060
- orClasses7.invoiceTitle,
3061
- classNames?.invoiceTitle
3062
- )
3063
- },
3064
- checkoutLabels6.bitcoinLightningInvoice
3065
- ),
3066
- React10.createElement(WaitingState, {
3067
- key: "waiting",
3068
- waiting: checkoutModel.waiting,
3069
- statusTitle: checkoutModel.statusTitle,
3070
- statusDetail: checkoutModel.statusDetail,
3071
- settled,
3072
- className: classNames?.waiting
3206
+ React10.createElement("span", {
3207
+ className: orClasses7.spinner,
3208
+ "aria-hidden": "true"
3073
3209
  }),
3074
- checkoutModel.countdownLabel === void 0 ? null : React10.createElement(
3075
- "div",
3076
- {
3077
- key: "countdown",
3078
- className: joinClassNames(orClasses7.countdown, classNames?.countdown)
3079
- },
3080
- checkoutModel.countdownPrefix,
3081
- " ",
3082
- React10.createElement(
3083
- "strong",
3084
- { className: orClasses7.countdownStrong },
3085
- checkoutModel.countdownLabel
3086
- )
3087
- ),
3088
- showSummaryMeta ? React10.createElement(InvoiceSummaryComponent, {
3089
- key: "summary",
3090
- status: checkoutModel.status,
3091
- PaymentStateComponent,
3092
- className: classNames?.summary,
3093
- classNames
3094
- }) : null,
3095
- settled ? React10.createElement(TransactionDetails, {
3096
- key: "transaction-details",
3097
- // The model IS the checkout state, so the panel reads
3098
- // the same derivation the rest of the screen does. It
3099
- // used to re-flatten the snapshot separately, which
3100
- // reported the displayed ATTEMPT's transaction /
3101
- // workflow state on a checkout the state already knows
3102
- // is paid.
3103
- //
3104
- // The SAME panel the swap flow renders one screen
3105
- // earlier. A payer's whole evidence that they paid is a
3106
- // payment hash and, on a swap, a deposit txid — so the
3107
- // most keep-worthy screen gets copy buttons and
3108
- // explorer links, not un-copyable text. No
3109
- // `decodeLinkUrl` is passed, so the bolt11 never
3110
- // reaches a third party.
3111
- state: checkoutModel,
3112
- className: classNames?.details,
3113
- onError
3114
- }) : expired ? React10.createElement(
3210
+ React10.createElement("p", null, checkoutLabels6.preparingPayment)
3211
+ ) : null,
3212
+ hideLightning ? null : React10.createElement(
3213
+ "div",
3214
+ {
3215
+ key: "payment-layout",
3216
+ className: expired || settled ? orClasses7.paymentLayoutExpired : orClasses7.paymentLayout
3217
+ },
3218
+ lightningPane,
3219
+ React10.createElement(
3115
3220
  "div",
3116
3221
  {
3117
- key: "expired-actions",
3118
- className: joinClassNames(orClasses7.actions, classNames?.actions),
3119
- [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3222
+ key: "payment-info",
3223
+ className: orClasses7.paymentInfo
3120
3224
  },
3121
- React10.createElement(
3122
- ButtonComponent ?? "button",
3225
+ expired || settled ? null : React10.createElement(
3226
+ "p",
3123
3227
  {
3124
- type: "button",
3125
- className: orClasses7.btn,
3126
- onClick: startOver
3228
+ key: "invoice-title",
3229
+ className: joinClassNames(orClasses7.invoiceTitle, classNames?.invoiceTitle)
3127
3230
  },
3128
- checkoutLabels6.startOver
3129
- )
3130
- ) : React10.createElement(
3131
- "div",
3132
- {
3133
- key: "actions",
3134
- className: joinClassNames(orClasses7.actions, classNames?.actions),
3135
- [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3136
- },
3137
- React10.createElement(CopyButton, {
3138
- key: "copy-invoice",
3139
- invoice: checkoutModel.invoice,
3140
- copyInvoice: checkoutModel.copyInvoice,
3141
- onError,
3142
- logger,
3143
- ButtonComponent,
3144
- className: classNames?.copyButton
3145
- }),
3146
- // Opt-in slot: the default checkout ships no wallet button, so a
3147
- // desktop payer is never sent to a handler that does not exist.
3148
- OpenWalletButtonComponent === void 0 ? null : React10.createElement(OpenWalletButtonComponent, {
3149
- key: "open-wallet",
3150
- invoice: checkoutModel.invoice,
3151
- openWallet: checkoutModel.openWallet,
3152
- onError,
3153
- logger,
3154
- ButtonComponent,
3155
- className: classNames?.openWalletButton
3231
+ checkoutLabels6.bitcoinLightningInvoice
3232
+ ),
3233
+ React10.createElement(WaitingState, {
3234
+ key: "waiting",
3235
+ waiting: checkoutModel.waiting,
3236
+ statusTitle: checkoutModel.statusTitle,
3237
+ statusDetail: checkoutModel.statusDetail,
3238
+ settled,
3239
+ className: classNames?.waiting
3156
3240
  }),
3157
- decodeInvoiceHref === void 0 ? null : React10.createElement(
3158
- "a",
3241
+ checkoutModel.countdownLabel === void 0 ? null : React10.createElement(
3242
+ "div",
3243
+ {
3244
+ key: "countdown",
3245
+ className: joinClassNames(orClasses7.countdown, classNames?.countdown)
3246
+ },
3247
+ checkoutModel.countdownPrefix,
3248
+ " ",
3249
+ React10.createElement(
3250
+ "strong",
3251
+ { className: orClasses7.countdownStrong },
3252
+ checkoutModel.countdownLabel
3253
+ )
3254
+ ),
3255
+ showSummaryMeta ? React10.createElement(InvoiceSummaryComponent, {
3256
+ key: "summary",
3257
+ status: checkoutModel.status,
3258
+ PaymentStateComponent,
3259
+ className: classNames?.summary,
3260
+ classNames
3261
+ }) : null,
3262
+ settled ? React10.createElement(TransactionDetails, {
3263
+ key: "transaction-details",
3264
+ // The model IS the checkout state, so the panel reads
3265
+ // the same derivation the rest of the screen does. It
3266
+ // used to re-flatten the snapshot separately, which
3267
+ // reported the displayed ATTEMPT's transaction /
3268
+ // workflow state on a checkout the state already knows
3269
+ // is paid.
3270
+ //
3271
+ // The SAME panel the swap flow renders one screen
3272
+ // earlier. A payer's whole evidence that they paid is a
3273
+ // payment hash and, on a swap, a deposit txid — so the
3274
+ // most keep-worthy screen gets copy buttons and
3275
+ // explorer links, not un-copyable text. No
3276
+ // `decodeLinkUrl` is passed, so the bolt11 never
3277
+ // reaches a third party.
3278
+ state: checkoutModel,
3279
+ className: classNames?.details,
3280
+ onError
3281
+ }) : expired ? React10.createElement(
3282
+ "div",
3283
+ {
3284
+ key: "expired-actions",
3285
+ className: joinClassNames(orClasses7.actions, classNames?.actions),
3286
+ [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3287
+ },
3288
+ React10.createElement(
3289
+ ButtonComponent ?? "button",
3290
+ {
3291
+ type: "button",
3292
+ className: orClasses7.btn,
3293
+ onClick: startOver
3294
+ },
3295
+ checkoutLabels6.startOver
3296
+ )
3297
+ ) : React10.createElement(
3298
+ "div",
3159
3299
  {
3160
- key: "decode-invoice",
3161
- className: orClasses7.btn,
3162
- href: decodeInvoiceHref,
3163
- rel: "noreferrer",
3164
- target: "_blank"
3300
+ key: "actions",
3301
+ className: joinClassNames(orClasses7.actions, classNames?.actions),
3302
+ [OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES3.actions]: ""
3165
3303
  },
3166
- checkoutLabels6.decodeInvoice
3304
+ React10.createElement(CopyButton, {
3305
+ key: "copy-invoice",
3306
+ invoice: checkoutModel.invoice,
3307
+ copyInvoice: checkoutModel.copyInvoice,
3308
+ onError,
3309
+ logger,
3310
+ ButtonComponent,
3311
+ className: classNames?.copyButton
3312
+ }),
3313
+ // Opt-in slot: the default checkout ships no wallet button, so a
3314
+ // desktop payer is never sent to a handler that does not exist.
3315
+ OpenWalletButtonComponent === void 0 ? null : React10.createElement(OpenWalletButtonComponent, {
3316
+ key: "open-wallet",
3317
+ invoice: checkoutModel.invoice,
3318
+ openWallet: checkoutModel.openWallet,
3319
+ onError,
3320
+ logger,
3321
+ ButtonComponent,
3322
+ className: classNames?.openWalletButton
3323
+ }),
3324
+ decodeInvoiceHref === void 0 ? null : React10.createElement(
3325
+ "a",
3326
+ {
3327
+ key: "decode-invoice",
3328
+ className: orClasses7.btn,
3329
+ href: decodeInvoiceHref,
3330
+ rel: "noreferrer",
3331
+ target: "_blank"
3332
+ },
3333
+ checkoutLabels6.decodeInvoice
3334
+ )
3167
3335
  )
3168
3336
  )
3169
- )
3170
- ),
3171
- paymentWizard && !settled && (!expired || swapFocused) ? React10.createElement(PaymentWizard, {
3172
- key: "wizard",
3173
- // Only pass invoice when it's a real bolt11 (non-empty, non-deferred).
3174
- invoice: checkoutModel.invoice || void 0,
3175
- checkout: checkoutModel.checkout,
3176
- className: classNames?.wizard,
3177
- logger,
3178
- onError,
3179
- onSwapFocusChange: setSwapFocused,
3180
- prefix,
3181
- qrEncoder,
3182
- decodeLinkUrl,
3183
- logContext: getCheckoutLogContext({
3184
- invoice_id: checkoutModel.invoice_id,
3185
- payment_hash: checkoutModel.payment_hash,
3186
- amount_msats: checkoutModel.amount_msats
3187
- }),
3188
- onProviderCopy,
3189
- onCopy,
3190
- onRequestLightning,
3191
- onSwapStarted,
3192
- resolveAssetUrl,
3193
- assetBaseUrl,
3194
- // Whether a payer who closes the tab has a URL to come back
3195
- // to. Explicit wins — only the host knows about a per-order
3196
- // route of its own; otherwise infer it from the two props that
3197
- // put the reference in the URL.
3198
- resumable: resumable ?? (syncUrl === true || routeReference !== void 0),
3199
- // The engine's staged refund address rides the controller this
3200
- // model owns, so a poll cannot wipe a review in progress.
3201
- swapRefund: checkoutModel
3202
- }) : null
3203
- ] : customChildren
3337
+ ),
3338
+ paymentWizard && !settled && (!expired || swapFocused) ? React10.createElement(PaymentWizard, {
3339
+ key: "wizard",
3340
+ // Only pass invoice when it's a real bolt11 (non-empty, non-deferred).
3341
+ invoice: checkoutModel.invoice || void 0,
3342
+ checkout: checkoutModel.checkout,
3343
+ className: classNames?.wizard,
3344
+ logger,
3345
+ onError,
3346
+ onSwapFocusChange: setSwapFocused,
3347
+ prefix,
3348
+ qrEncoder,
3349
+ decodeLinkUrl,
3350
+ logContext: getCheckoutLogContext({
3351
+ invoice_id: checkoutModel.invoice_id,
3352
+ payment_hash: checkoutModel.payment_hash,
3353
+ amount_msats: checkoutModel.amount_msats
3354
+ }),
3355
+ onProviderCopy,
3356
+ onCopy,
3357
+ onRequestLightning,
3358
+ onSwapStarted,
3359
+ resolveAssetUrl,
3360
+ assetBaseUrl,
3361
+ // Whether a payer who closes the tab has a URL to come back
3362
+ // to. Explicit wins — only the host knows about a per-order
3363
+ // route of its own; otherwise infer it from the two props that
3364
+ // put the reference in the URL.
3365
+ resumable: resumable ?? (syncUrl === true || routeReference !== void 0),
3366
+ // The engine's staged refund address rides the controller this
3367
+ // model owns, so a poll cannot wipe a review in progress.
3368
+ swapRefund: checkoutModel
3369
+ }) : null
3370
+ ]
3371
+ ]
3204
3372
  );
3205
3373
  }
3206
3374