@openreceive/elements 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.
@@ -22,10 +22,10 @@ import {
22
22
  createCheckoutStateEvent,
23
23
  createCheckoutStatusModel as createCheckoutStatusModel2,
24
24
  createPaymentWizardSelection,
25
- createSwapDisplayModel as createSwapDisplayModel2,
26
- createThemeChangeEvent,
27
25
  createQrPayloadSvg,
28
26
  createQrSvg,
27
+ createSwapDisplayModel as createSwapDisplayModel3,
28
+ createThemeChangeEvent,
29
29
  deriveStatus as deriveStatus2,
30
30
  enterCheckoutResumePath,
31
31
  getSwapRefundFormError,
@@ -33,20 +33,20 @@ import {
33
33
  OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3,
34
34
  OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS,
35
35
  OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS,
36
+ OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
36
37
  OPENRECEIVE_DEFAULT_PREFIX as OPENRECEIVE_DEFAULT_PREFIX2,
37
38
  OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7,
38
39
  OPENRECEIVE_PAYMENT_WIZARD_SELECTORS as OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3,
39
40
  OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES,
40
41
  OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS,
41
- OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
42
42
  OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME,
43
- paymentMethods as paymentMethods2,
44
43
  orClasses as orClasses7,
45
44
  parseBooleanAttribute,
46
45
  parseOptionalInteger,
47
46
  parsePaymentMethod,
48
47
  parseResolvedTheme,
49
48
  parseThemePreference,
49
+ paymentMethods as paymentMethods2,
50
50
  resolveWizardSelection,
51
51
  selectCurrentSwapInvoice,
52
52
  syncStoredThemeControls,
@@ -54,16 +54,147 @@ import {
54
54
  updatePaymentWizardSelection
55
55
  } from "@openreceive/browser/headless";
56
56
 
57
+ // src/dom-helpers.ts
58
+ import {
59
+ createDetailExternalLink,
60
+ createTransientFeedbackController,
61
+ escapeHtml,
62
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES,
63
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES,
64
+ OPENRECEIVE_PAYMENT_WIZARD_SELECTORS,
65
+ checkoutLabels,
66
+ orClasses
67
+ } from "@openreceive/browser/headless";
68
+ var COPY_INVOICE_ICON = `<svg class="${orClasses.copyIcon}" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><rect x="5" y="5" width="8" height="9" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M3.5 11V3.5A1.5 1.5 0 0 1 5 2h5.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>`;
69
+ var elementCopyFeedbackControllers = /* @__PURE__ */ new WeakMap();
70
+ function readElementFiatQuote(element) {
71
+ const currency = element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.fiatCurrency);
72
+ const value = element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.fiatValue);
73
+ if (currency === null || value === null) return void 0;
74
+ return {
75
+ fiat: {
76
+ currency,
77
+ value
78
+ }
79
+ };
80
+ }
81
+ function readElementNumberAttribute(element, attribute) {
82
+ const raw = element.getAttribute(attribute);
83
+ if (raw === null || raw.trim() === "") return void 0;
84
+ const parsed = Number(raw);
85
+ return Number.isFinite(parsed) ? parsed : void 0;
86
+ }
87
+ function readElementAmountMsats(element) {
88
+ return readElementNumberAttribute(element, OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.amountMsats);
89
+ }
90
+ function readElementExpiresAt(element) {
91
+ return readElementNumberAttribute(element, OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.expiresAt);
92
+ }
93
+ function parseElementRail(value) {
94
+ if (value === "swap") return "swap";
95
+ if (value === "checkout_lock") return "checkout_lock";
96
+ return "lightning";
97
+ }
98
+ function showElementCopyFeedback(button) {
99
+ if (button === null) return;
100
+ let controller = elementCopyFeedbackControllers.get(button);
101
+ if (controller === void 0) {
102
+ const labelEl = button.querySelector(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS.swapCopyLabel);
103
+ const resetValue = button.getAttribute("aria-label")?.trim() || labelEl?.textContent?.trim() || button.textContent?.trim() || checkoutLabels.copyInvoice;
104
+ controller = createTransientFeedbackController({
105
+ resetValue,
106
+ onValue: (label) => {
107
+ if (!button.isConnected) return;
108
+ if (button instanceof HTMLElement && button.hasAttribute("aria-label")) {
109
+ button.setAttribute("aria-label", label);
110
+ button.setAttribute("title", label);
111
+ }
112
+ if (labelEl instanceof HTMLElement) {
113
+ labelEl.textContent = label;
114
+ return;
115
+ }
116
+ if (!(button instanceof HTMLElement && button.querySelector("svg"))) {
117
+ button.textContent = label;
118
+ }
119
+ }
120
+ });
121
+ elementCopyFeedbackControllers.set(button, controller);
122
+ }
123
+ controller.show(checkoutLabels.copied);
124
+ }
125
+ function wireSwapSelectAllInputs(root) {
126
+ for (const input of root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS.swapSelectAll)) {
127
+ if (!(input instanceof HTMLInputElement)) continue;
128
+ const selectAll = () => {
129
+ input.select();
130
+ };
131
+ input.addEventListener("focus", selectAll);
132
+ input.addEventListener("click", selectAll);
133
+ input.addEventListener("mouseup", (event) => {
134
+ event.preventDefault();
135
+ });
136
+ input.addEventListener("select", () => {
137
+ if (input.selectionStart !== 0 || input.selectionEnd !== input.value.length) {
138
+ input.setSelectionRange(0, input.value.length);
139
+ }
140
+ });
141
+ }
142
+ }
143
+ function renderElementSwapCopyDetailHtml(label, value, options = {}) {
144
+ const displayValue = options.displayValue ?? value;
145
+ const link = options.href === void 0 ? options.kind === void 0 ? void 0 : createDetailExternalLink({
146
+ kind: options.kind,
147
+ value,
148
+ ...options.payInAsset === void 0 ? {} : { payInAsset: options.payInAsset }
149
+ }) : {
150
+ href: options.href,
151
+ hrefLabel: options.hrefLabel ?? checkoutLabels.viewOnExplorer
152
+ };
153
+ const external = link === void 0 ? "" : `<a
154
+ part="swap-external"
155
+ class="${orClasses.swapDetailsLink}"
156
+ href="${escapeHtml(link.href)}"
157
+ rel="noreferrer"
158
+ target="_blank"
159
+ >${escapeHtml(link.hrefLabel)}</a>`;
160
+ const valueField = options.selectable === true ? `<input
161
+ class="${orClasses.swapDetailsInput}"
162
+ type="text"
163
+ readonly
164
+ value="${escapeHtml(displayValue)}"
165
+ aria-label="${escapeHtml(label)}"
166
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES.swapSelectAll}
167
+ />` : `<code class="${orClasses.swapDetailsCode}">${escapeHtml(displayValue)}</code>`;
168
+ return `
169
+ <dt class="${orClasses.swapDetailsDt}">${escapeHtml(label)}</dt>
170
+ <dd class="${orClasses.swapDetailsDd}">
171
+ ${valueField}
172
+ <div class="${orClasses.swapDetailsActions}">
173
+ <button
174
+ part="swap-copy"
175
+ class="${orClasses.detailCopy}"
176
+ aria-label="Copy"
177
+ title="Copy"
178
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES.swapCopy}="${escapeHtml(value)}"
179
+ type="button"
180
+ >${COPY_INVOICE_ICON}</button>
181
+ ${external}
182
+ </div>
183
+ </dd>
184
+ `;
185
+ }
186
+
57
187
  // src/element-checkout-session.ts
58
188
  import {
59
189
  applyCheckoutElementAttributes,
60
190
  createCheckoutElementAttributes,
61
191
  createCheckoutSession,
62
192
  mergeAttemptIntoCheckout,
63
- OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES,
193
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2,
64
194
  OPENRECEIVE_DEFAULT_PREFIX,
65
195
  prepareCheckout,
66
- requestCheckout
196
+ requestCheckout,
197
+ resumeSwapAttempt
67
198
  } from "@openreceive/browser/headless";
68
199
  function createElementCheckoutSession(host) {
69
200
  let creating = false;
@@ -71,10 +202,10 @@ function createElementCheckoutSession(host) {
71
202
  let createError;
72
203
  let applyingOwnAttributes = 0;
73
204
  function currentPrefix() {
74
- return host.element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.prefix) ?? OPENRECEIVE_DEFAULT_PREFIX;
205
+ return host.element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2.prefix) ?? OPENRECEIVE_DEFAULT_PREFIX;
75
206
  }
76
207
  function currentReference() {
77
- const reference = host.element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.reference);
208
+ const reference = host.element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2.reference);
78
209
  return reference === null || reference.length === 0 ? void 0 : reference;
79
210
  }
80
211
  function currentCreateKey() {
@@ -154,11 +285,19 @@ function createElementCheckoutSession(host) {
154
285
  try {
155
286
  createError = void 0;
156
287
  host.syncResumePath(reference);
157
- const checkout = await prepareCheckout({
288
+ const prepared = await prepareCheckout({
158
289
  prefix,
159
290
  reference,
160
291
  fetch: globalThis.fetch
161
292
  });
293
+ const resumeHash = host.resumePaymentHash();
294
+ const checkout = resumeHash === void 0 ? prepared : await resumeSwapAttempt({
295
+ fetch: globalThis.fetch,
296
+ prefix,
297
+ reference,
298
+ paymentHash: resumeHash,
299
+ snapshot: prepared
300
+ });
162
301
  if (currentCreateKey() !== key) return;
163
302
  host.handleControllerSnapshot(checkout);
164
303
  applyOwnAttributes(
@@ -225,136 +364,6 @@ function createElementCheckoutSession(host) {
225
364
  };
226
365
  }
227
366
 
228
- // src/dom-helpers.ts
229
- import {
230
- createDetailExternalLink,
231
- createTransientFeedbackController,
232
- escapeHtml,
233
- OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2,
234
- OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES,
235
- OPENRECEIVE_PAYMENT_WIZARD_SELECTORS,
236
- checkoutLabels,
237
- orClasses
238
- } from "@openreceive/browser/headless";
239
- var COPY_INVOICE_ICON = `<svg class="${orClasses.copyIcon}" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><rect x="5" y="5" width="8" height="9" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M3.5 11V3.5A1.5 1.5 0 0 1 5 2h5.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>`;
240
- var elementCopyFeedbackControllers = /* @__PURE__ */ new WeakMap();
241
- function readElementFiatQuote(element) {
242
- const currency = element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2.fiatCurrency);
243
- const value = element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2.fiatValue);
244
- if (currency === null || value === null) return void 0;
245
- return {
246
- fiat: {
247
- currency,
248
- value
249
- }
250
- };
251
- }
252
- function readElementNumberAttribute(element, attribute) {
253
- const raw = element.getAttribute(attribute);
254
- if (raw === null || raw.trim() === "") return void 0;
255
- const parsed = Number(raw);
256
- return Number.isFinite(parsed) ? parsed : void 0;
257
- }
258
- function readElementAmountMsats(element) {
259
- return readElementNumberAttribute(element, OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2.amountMsats);
260
- }
261
- function readElementExpiresAt(element) {
262
- return readElementNumberAttribute(element, OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES2.expiresAt);
263
- }
264
- function parseElementRail(value) {
265
- if (value === "swap") return "swap";
266
- if (value === "checkout_lock") return "checkout_lock";
267
- return "lightning";
268
- }
269
- function showElementCopyFeedback(button) {
270
- if (button === null) return;
271
- let controller = elementCopyFeedbackControllers.get(button);
272
- if (controller === void 0) {
273
- const labelEl = button.querySelector(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS.swapCopyLabel);
274
- const resetValue = button.getAttribute("aria-label")?.trim() || labelEl?.textContent?.trim() || button.textContent?.trim() || checkoutLabels.copyInvoice;
275
- controller = createTransientFeedbackController({
276
- resetValue,
277
- onValue: (label) => {
278
- if (!button.isConnected) return;
279
- if (button instanceof HTMLElement && button.hasAttribute("aria-label")) {
280
- button.setAttribute("aria-label", label);
281
- button.setAttribute("title", label);
282
- }
283
- if (labelEl instanceof HTMLElement) {
284
- labelEl.textContent = label;
285
- return;
286
- }
287
- if (!(button instanceof HTMLElement && button.querySelector("svg"))) {
288
- button.textContent = label;
289
- }
290
- }
291
- });
292
- elementCopyFeedbackControllers.set(button, controller);
293
- }
294
- controller.show(checkoutLabels.copied);
295
- }
296
- function wireSwapSelectAllInputs(root) {
297
- for (const input of root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS.swapSelectAll)) {
298
- if (!(input instanceof HTMLInputElement)) continue;
299
- const selectAll = () => {
300
- input.select();
301
- };
302
- input.addEventListener("focus", selectAll);
303
- input.addEventListener("click", selectAll);
304
- input.addEventListener("mouseup", (event) => {
305
- event.preventDefault();
306
- });
307
- input.addEventListener("select", () => {
308
- if (input.selectionStart !== 0 || input.selectionEnd !== input.value.length) {
309
- input.setSelectionRange(0, input.value.length);
310
- }
311
- });
312
- }
313
- }
314
- function renderElementSwapCopyDetailHtml(label, value, options = {}) {
315
- const displayValue = options.displayValue ?? value;
316
- const link = options.href === void 0 ? options.kind === void 0 ? void 0 : createDetailExternalLink({
317
- kind: options.kind,
318
- value,
319
- ...options.payInAsset === void 0 ? {} : { payInAsset: options.payInAsset }
320
- }) : {
321
- href: options.href,
322
- hrefLabel: options.hrefLabel ?? checkoutLabels.viewOnExplorer
323
- };
324
- const external = link === void 0 ? "" : `<a
325
- part="swap-external"
326
- class="${orClasses.swapDetailsLink}"
327
- href="${escapeHtml(link.href)}"
328
- rel="noreferrer"
329
- target="_blank"
330
- >${escapeHtml(link.hrefLabel)}</a>`;
331
- const valueField = options.selectable === true ? `<input
332
- class="${orClasses.swapDetailsInput}"
333
- type="text"
334
- readonly
335
- value="${escapeHtml(displayValue)}"
336
- aria-label="${escapeHtml(label)}"
337
- ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES.swapSelectAll}
338
- />` : `<code class="${orClasses.swapDetailsCode}">${escapeHtml(displayValue)}</code>`;
339
- return `
340
- <dt class="${orClasses.swapDetailsDt}">${escapeHtml(label)}</dt>
341
- <dd class="${orClasses.swapDetailsDd}">
342
- ${valueField}
343
- <div class="${orClasses.swapDetailsActions}">
344
- <button
345
- part="swap-copy"
346
- class="${orClasses.detailCopy}"
347
- aria-label="Copy"
348
- title="Copy"
349
- ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES.swapCopy}="${escapeHtml(value)}"
350
- type="button"
351
- >${COPY_INVOICE_ICON}</button>
352
- ${external}
353
- </div>
354
- </dd>
355
- `;
356
- }
357
-
358
367
  // src/element-styles.ts
359
368
  import { checkoutElementStyles } from "@openreceive/browser/headless";
360
369
  var checkoutStyleTag = `<style>${checkoutElementStyles}</style>`;
@@ -408,10 +417,13 @@ import {
408
417
  checkoutLabels as checkoutLabels5,
409
418
  createMethodGridDisplay,
410
419
  createPaymentWizardModel,
420
+ createSwapDisplayModel as createSwapDisplayModel2,
411
421
  createSwapUnavailableModel,
412
422
  createWizardRouteAssetDisplays,
413
423
  createWizardRouteDisplays,
424
+ currentCheckoutUrl as currentCheckoutUrl2,
414
425
  escapeHtml as escapeHtml5,
426
+ formatMethodNetworkDetail,
415
427
  formatNetworkSummary,
416
428
  getNetworkIcon,
417
429
  getPaymentMethodIcon,
@@ -526,13 +538,14 @@ function renderTutorialModalHtml(routes, activeProviderId, activeTutorialIndex,
526
538
 
527
539
  // src/render-swap-panel.ts
528
540
  import {
541
+ checkoutLabels as checkoutLabels4,
529
542
  createSwapDisplayModel,
543
+ currentCheckoutUrl,
530
544
  escapeHtml as escapeHtml4,
531
545
  OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4,
532
- checkoutLabels as checkoutLabels4,
546
+ orClasses as orClasses4,
533
547
  swapAssetMatchesRoute,
534
- swapOptionLimitMessage,
535
- orClasses as orClasses4
548
+ swapOptionLimitMessage
536
549
  } from "@openreceive/browser/headless";
537
550
 
538
551
  // src/transaction-details.ts
@@ -642,6 +655,15 @@ function renderElementSwapPanelHtml(invoice, view = {}) {
642
655
  <span class="${orClasses4.swapHeadingDetail}">${escapeHtml4(display.providerStateDetail)}</span>
643
656
  </div>
644
657
  `;
658
+ const refundHeading = `
659
+ <div part="swap-heading" class="${orClasses4.swapRefundHeading}" role="alert">
660
+ ${renderElementAlertIconHtml("warning")}
661
+ <div class="${orClasses4.swapNetworkWarningContent}">
662
+ <strong class="${orClasses4.swapHeadingTitle}">${escapeHtml4(display.providerStateLabel)}</strong>
663
+ <span class="${orClasses4.swapHeadingDetail}">${escapeHtml4(display.providerStateDetail)}</span>
664
+ </div>
665
+ </div>
666
+ `;
645
667
  if (display.state === "creating") {
646
668
  return `
647
669
  <section part="swap-panel" class="${orClasses4.swapPanel}">
@@ -675,7 +697,7 @@ function renderElementSwapPanelHtml(invoice, view = {}) {
675
697
  <p part="swap-instruction" class="${orClasses4.swapInstruction}">Pay <strong>${escapeHtml4(display.depositAmount)} ${escapeHtml4(display.assetLabel)}</strong> to this address</p>
676
698
  ${renderElementSwapNetworkWarningHtml(display)}
677
699
  <div part="swap-deposit-layout" class="${orClasses4.swapDepositLayout}">
678
- <div part="swap-qr" class="${orClasses4.swapQr}" ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapQr}="${escapeHtml4(display.qrPayload)}"></div>
700
+ <div part="swap-qr" class="${orClasses4.swapQrFrame}" ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapQr}="${escapeHtml4(display.qrPayload)}"></div>
679
701
  <div part="swap-deposit-side" class="${orClasses4.swapDepositSide}">
680
702
  <dl part="swap-details" class="${orClasses4.swapDetails}">
681
703
  ${display.copyRows.map(
@@ -732,12 +754,24 @@ function renderElementSwapPanelHtml(invoice, view = {}) {
732
754
  }
733
755
  if (display.state === "refund_required") {
734
756
  const stagedRefundAddress = display.refundAddress;
735
- const refundFacts = renderElementSwapRefundFactsHtml(display);
757
+ const refundFacts = renderElementSwapAmountFactsHtml(display);
758
+ const refundFormIntro = `
759
+ <p class="${orClasses4.swapSectionTitle}">${escapeHtml4(checkoutLabels4.refundSectionTitle)}</p>
760
+ ${display.refundReason === void 0 ? "" : `<p class="${orClasses4.swapRefundReason}">${escapeHtml4(
761
+ checkoutLabels4.refundReasonLabel.replace(
762
+ "{reason}",
763
+ display.refundReason.replace(/_/g, " ")
764
+ )
765
+ )}</p>`}
766
+ <p class="${orClasses4.swapRefundInstruction}">${escapeHtml4(
767
+ checkoutLabels4.refundAddressOwnership.replace("{network}", display.networkLabel)
768
+ )}</p>
769
+ `;
736
770
  return `
737
771
  <section part="swap-panel" class="${orClasses4.swapPanel}">
738
- ${heading}
772
+ ${refundHeading}
773
+ ${renderElementSwapRefundReturnWarningHtml(display)}
739
774
  ${refundFacts}
740
- <p part="swap-warning" class="${orClasses4.swapWarning}">Use a ${escapeHtml4(display.networkLabel)} address you control. Do not paste the deposit address.</p>
741
775
  ${stagedRefundAddress === void 0 ? `
742
776
  <form
743
777
  part="swap-refund"
@@ -748,6 +782,7 @@ function renderElementSwapPanelHtml(invoice, view = {}) {
748
782
  ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundNetworkLabel}="${escapeHtml4(display.networkLabel)}"
749
783
  ${display.refundAllowed ? `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAllowed}="true"` : ""}
750
784
  >
785
+ ${refundFormIntro}
751
786
  <input
752
787
  class="${orClasses4.swapRefundInput}"
753
788
  ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAddress}
@@ -777,7 +812,8 @@ function renderElementSwapPanelHtml(invoice, view = {}) {
777
812
  ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundConfirm}="true"
778
813
  ${display.refundAllowed ? `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAllowed}="true"` : ""}
779
814
  >
780
- <p part="swap-warning" class="${orClasses4.swapWarning}">${escapeHtml4(checkoutLabels4.confirmRefundTo.replace("{address}", stagedRefundAddress))}</p>
815
+ ${refundFormIntro}
816
+ <p class="${orClasses4.swapRefundInstruction}">${escapeHtml4(checkoutLabels4.confirmRefundTo.replace("{address}", stagedRefundAddress))}</p>
781
817
  <input
782
818
  ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAddress}
783
819
  name="refund_address"
@@ -788,56 +824,74 @@ function renderElementSwapPanelHtml(invoice, view = {}) {
788
824
  </form>
789
825
  `}
790
826
  ${supportDetails}
791
- ${renderElementSwapRefundReturnWarningHtml(display)}
792
827
  </section>
793
828
  `;
794
829
  }
795
830
  if (display.state === "refund_pending" || display.state === "refunded") {
796
- const refundFacts = renderElementSwapRefundFactsHtml(display);
831
+ const refundFacts = renderElementSwapAmountFactsHtml(display);
797
832
  return `
798
833
  <section part="swap-panel" class="${orClasses4.swapPanel}">
799
- ${heading}
834
+ ${refundHeading}
835
+ ${renderElementSwapRefundReturnWarningHtml(display)}
800
836
  ${refundFacts}
801
837
  <dl part="swap-details" class="${orClasses4.swapDetails}">
802
838
  ${display.refundAddress === void 0 ? "" : renderElementSwapCopyDetailHtml("Refund address", display.refundAddress, { kind: "address", payInAsset: display.payInAsset })}
803
839
  ${display.refundTxId === void 0 ? "" : renderElementSwapCopyDetailHtml("Refund transaction", display.refundTxId, { kind: "tx", payInAsset: display.payInAsset })}
804
840
  </dl>
805
841
  ${supportDetails}
806
- ${renderElementSwapRefundReturnWarningHtml(display)}
807
842
  </section>
808
843
  `;
809
844
  }
810
845
  return `
811
846
  <section part="swap-panel" class="${orClasses4.swapPanel}">
812
847
  ${heading}
813
- <p part="swap-warning" class="${orClasses4.swapWarning}">${escapeHtml4(checkoutLabels4.supportReviewNeeded)}</p>
814
- ${supportDetails}
848
+ <p part="swap-warning" class="${orClasses4.swapWarning}">${escapeHtml4(checkoutLabels4.supportReviewFacts)}</p>
849
+ ${renderElementSwapAmountFactsHtml(display)}
850
+ ${renderElementSwapSupportDetailsHtml(display, { open: true })}
815
851
  ${backButton}
816
852
  </section>
817
853
  `;
818
854
  }
819
855
  function renderElementSwapRefundReturnWarningHtml(display) {
856
+ const url = display.resumable ? currentCheckoutUrl() : void 0;
820
857
  return `
821
- <p part="swap-refund-return" class="${orClasses4.swapWarning}">${escapeHtml4(display.refundReturnLabel)}</p>
858
+ <div part="swap-refund-return" class="${orClasses4.swapRefundReturn}">
859
+ ${renderElementAlertIconHtml("bookmark")}
860
+ <div class="${orClasses4.swapNetworkWarningContent}">
861
+ <p class="${orClasses4.swapRefundReturnTitle}">${escapeHtml4(checkoutLabels4.refundReturnTitle)}</p>
862
+ <p class="${orClasses4.swapRefundReturnBody}">${escapeHtml4(display.refundReturnLabel)}</p>
863
+ ${url === void 0 ? "" : `<dl part="swap-details" class="${orClasses4.swapDetails}">${renderElementSwapCopyDetailHtml(
864
+ checkoutLabels4.refundReturnUrlLabel,
865
+ url,
866
+ { selectable: true }
867
+ )}</dl>`}
868
+ </div>
869
+ </div>
822
870
  `;
823
871
  }
824
- function renderElementSwapRefundFactsHtml(display) {
825
- const rows = [
826
- display.depositReceivedAmount === void 0 ? "" : renderElementSwapCopyDetailHtml(
827
- "Amount received",
828
- `${display.depositReceivedAmount} ${display.assetLabel}`
829
- ),
830
- display.depositReceivedAmount === void 0 ? "" : renderElementSwapCopyDetailHtml(
831
- "Amount required",
832
- `${display.depositAmount} ${display.assetLabel}`
833
- ),
834
- display.refundAmount === void 0 ? "" : renderElementSwapCopyDetailHtml(
835
- "Estimated refund",
836
- `${display.refundAmount} ${display.assetLabel}`
837
- )
838
- ].join("");
839
- if (rows.length === 0) return "";
840
- return `<dl part="swap-details" class="${orClasses4.swapDetails}">${rows}</dl>`;
872
+ function renderElementSwapAmountFactsHtml(display) {
873
+ const facts = [
874
+ ...display.depositReceivedAmount === void 0 ? [] : [
875
+ ["Amount received", `${display.depositReceivedAmount} ${display.assetLabel}`],
876
+ ["Amount required", `${display.depositAmount} ${display.assetLabel}`]
877
+ ],
878
+ ...display.refundAmount === void 0 ? [] : [["Estimated refund", `${display.refundAmount} ${display.assetLabel}`]]
879
+ ];
880
+ if (facts.length === 0) return "";
881
+ const rows = facts.map(
882
+ ([label, value]) => `
883
+ <div class="${orClasses4.swapFactsRow}">
884
+ <dt class="${orClasses4.swapFactsLabel}">${escapeHtml4(label)}</dt>
885
+ <dd class="${orClasses4.swapFactsValue}">${escapeHtml4(value)}</dd>
886
+ </div>`
887
+ ).join("");
888
+ return `<dl part="swap-facts" class="${orClasses4.swapFacts}">${rows}</dl>`;
889
+ }
890
+ function renderElementAlertIconHtml(kind) {
891
+ const path = 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";
892
+ return `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="${orClasses4.swapNetworkWarningIcon}" aria-hidden="true">
893
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="${path}" />
894
+ </svg>`;
841
895
  }
842
896
  function renderElementSwapNetworkWarningHtml(display) {
843
897
  const alarm = display.depositRisk !== "pinned";
@@ -895,12 +949,12 @@ function renderElementSwapFeeBreakdownHtml(breakdown) {
895
949
  </div>
896
950
  `;
897
951
  }
898
- function renderElementSwapSupportDetailsHtml(display) {
952
+ function renderElementSwapSupportDetailsHtml(display, options = {}) {
899
953
  if (display.depositTxId === void 0 && display.payoutTxId === void 0 && display.refundTxId === void 0 && display.providerOrderId === void 0) {
900
954
  return "";
901
955
  }
902
956
  return `
903
- <details part="swap-support" class="${orClasses4.swapSupport}">
957
+ <details part="swap-support" class="${orClasses4.swapSupport}"${options.open === true ? " open" : ""}>
904
958
  <summary class="${orClasses4.swapSupportTitle}">Payment details</summary>
905
959
  <div class="${orClasses4.swapSupportContent}">
906
960
  <dl part="swap-details" class="${orClasses4.swapDetails}">
@@ -931,6 +985,7 @@ function renderElementSwapUnavailableHtml(quote, checkout) {
931
985
  </section>`;
932
986
  }
933
987
  function renderPaymentWizardHtml(view = {}) {
988
+ const keepOrderNote = renderElementKeepOrderNoteHtml(view);
934
989
  const selection = {
935
990
  selectedMethod: view.selectedMethod ?? null,
936
991
  selectedBitcoinRoute: view.selectedBitcoinRoute ?? null
@@ -956,10 +1011,15 @@ function renderPaymentWizardHtml(view = {}) {
956
1011
  if (selectedSwapAsset !== null) {
957
1012
  const label = selectedSwapOption === void 0 ? "this coin" : `${selectedSwapOption.label} \xB7 ${selectedSwapOption.network_label}`;
958
1013
  const activeSwap = view.swapInvoice !== void 0 && view.swapInvoice.swap?.pay_in_asset === selectedSwapAsset ? view.swapInvoice : void 0;
1014
+ const activeSwapState = activeSwap === void 0 ? void 0 : createSwapDisplayModel2(activeSwap, {
1015
+ ...view.resumable === void 0 ? {} : { resumable: view.resumable }
1016
+ })?.state;
1017
+ const refundOwed = activeSwapState === "refund_required";
1018
+ const refundStage = activeSwapState?.startsWith("refund") ?? false;
959
1019
  return `
960
1020
  <section part="wizard" class="${orClasses5.wizard}" ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.root}>
961
1021
  <div class="${orClasses5.wizardBody}">
962
- <div part="wizard-breadcrumbs" class="${orClasses5.breadcrumbs}">
1022
+ ${refundOwed ? "" : `<div part="wizard-breadcrumbs" class="${orClasses5.breadcrumbs}">
963
1023
  <button
964
1024
  part="wizard-breadcrumb"
965
1025
  class="${orClasses5.btnGhost}"
@@ -968,7 +1028,7 @@ function renderPaymentWizardHtml(view = {}) {
968
1028
  >${escapeHtml5(checkoutLabels5.switchPaymentMethod)}</button>
969
1029
  <span aria-hidden="true">/</span>
970
1030
  <span part="wizard-breadcrumb-current" class="${orClasses5.breadcrumbCurrent}">${escapeHtml5(label)}</span>
971
- </div>
1031
+ </div>`}
972
1032
  <div part="wizard-results" class="${orClasses5.wizardResults}">
973
1033
  ${activeSwap !== void 0 ? renderElementSwapPanelHtml(activeSwap, view) : view.swapStartError !== void 0 ? `<section part="swap-panel" class="${orClasses5.swapPanel}">
974
1034
  <div part="swap-error" role="alert" class="${orClasses5.paymentStatus}">
@@ -1001,6 +1061,7 @@ function renderPaymentWizardHtml(view = {}) {
1001
1061
  </div>
1002
1062
  </section>`}
1003
1063
  </div>
1064
+ ${refundStage ? "" : keepOrderNote}
1004
1065
  </div>
1005
1066
  </section>
1006
1067
  `;
@@ -1010,6 +1071,7 @@ function renderPaymentWizardHtml(view = {}) {
1010
1071
  <section part="wizard" class="${orClasses5.wizard}" ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.root}>
1011
1072
  ${view.wizardError === void 0 ? "" : `<p part="wizard-error" role="alert" class="${orClasses5.paymentStatusDetail}">${escapeHtml5(view.wizardError)}</p>`}
1012
1073
  ${methodPicker}
1074
+ ${selection.selectedMethod === null && keepOrderNote.length > 0 ? `<div class="${orClasses5.wizardBody}">${keepOrderNote}</div>` : ""}
1013
1075
  ${selection.selectedMethod === null ? "" : `
1014
1076
  <div class="${orClasses5.wizardBody}">
1015
1077
  ${breadcrumbs}
@@ -1066,6 +1128,7 @@ function renderPaymentWizardHtml(view = {}) {
1066
1128
  }).join("")}
1067
1129
  </div>
1068
1130
  `}
1131
+ ${keepOrderNote}
1069
1132
  </div>
1070
1133
  `}
1071
1134
  ${renderTutorialModalHtml(
@@ -1079,6 +1142,26 @@ function renderPaymentWizardHtml(view = {}) {
1079
1142
  </section>
1080
1143
  `;
1081
1144
  }
1145
+ function renderElementKeepOrderNoteHtml(view) {
1146
+ if (view.resumable !== true) return "";
1147
+ const reference = view.reference ?? "";
1148
+ const url = currentCheckoutUrl2();
1149
+ if (reference.length === 0 && url === void 0) return "";
1150
+ return `
1151
+ <div part="keep-order" class="${orClasses5.keepOrder}">
1152
+ <p class="${orClasses5.swapSectionTitle}">${escapeHtml5(checkoutLabels5.keepOrderTitle)}</p>
1153
+ <p class="${orClasses5.keepOrderBody}">${escapeHtml5(checkoutLabels5.keepOrderBody)}</p>
1154
+ <dl part="swap-details" class="${orClasses5.swapDetails}">
1155
+ ${reference.length === 0 ? "" : renderElementSwapCopyDetailHtml(checkoutLabels5.keepOrderIdLabel, reference, {
1156
+ selectable: true
1157
+ })}
1158
+ ${url === void 0 ? "" : renderElementSwapCopyDetailHtml(checkoutLabels5.keepOrderUrlLabel, url, {
1159
+ selectable: true
1160
+ })}
1161
+ </dl>
1162
+ </div>
1163
+ `;
1164
+ }
1082
1165
  function renderElementCompactPaymentSelectorHtml(swapAssetOptions, view) {
1083
1166
  const limitContext = elementsSwapLimitContext(view);
1084
1167
  const display = createMethodGridDisplay({
@@ -1113,6 +1196,7 @@ function renderElementCompactPaymentSelectorHtml(swapAssetOptions, view) {
1113
1196
  </span>
1114
1197
  <span class="${orClasses5.methodTitleWrap}">
1115
1198
  <span class="${orClasses5.methodTitle}">${escapeHtml5(method.title)}</span>
1199
+ <span class="${orClasses5.methodTileDetail}">${escapeHtml5(method.detail)}</span>
1116
1200
  </span>
1117
1201
  </button>`;
1118
1202
  }
@@ -1221,7 +1305,6 @@ function renderElementSwapMethodGroupHtml(group, view, gridBusy, continueButtonH
1221
1305
  pickerKey,
1222
1306
  selected,
1223
1307
  displayOption,
1224
- selectedOption,
1225
1308
  multiNetwork,
1226
1309
  starting,
1227
1310
  disabled,
@@ -1229,7 +1312,7 @@ function renderElementSwapMethodGroupHtml(group, view, gridBusy, continueButtonH
1229
1312
  limitMessage,
1230
1313
  panelId
1231
1314
  } = group;
1232
- const networkDetail = !disabled && multiNetwork ? selected && selectedOption !== void 0 ? `${escapeHtml5(selectedOption.network_label)} network` : escapeHtml5(checkoutLabels5.selectNetwork) : void 0;
1315
+ const networkDetail = formatMethodNetworkDetail(group.options);
1233
1316
  const mobileReveal = multiNetwork ? `
1234
1317
  <div class="${orClasses5.methodNetworkRevealAnim} ${selected ? orClasses5.methodNetworkRevealAnimOpen : orClasses5.methodNetworkRevealAnimClosed}">
1235
1318
  <div class="${orClasses5.methodNetworkRevealInner}">
@@ -1257,7 +1340,7 @@ function renderElementSwapMethodGroupHtml(group, view, gridBusy, continueButtonH
1257
1340
  </span>
1258
1341
  <span class="${orClasses5.methodTitleWrap}">
1259
1342
  <span class="${orClasses5.methodTitle}">${escapeHtml5(group.label)}</span>
1260
- ${networkDetail === void 0 ? "" : `<span class="${orClasses5.methodDetailMobile}">${networkDetail}</span>`}
1343
+ ${networkDetail.length === 0 ? "" : `<span class="${orClasses5.methodTileDetail}">${escapeHtml5(networkDetail)}</span>`}
1261
1344
  </span>
1262
1345
  </button>
1263
1346
  ${disabled && limitMessage !== void 0 ? `<span class="${orClasses5.methodLimitHint}">${escapeHtml5(limitMessage)}</span>` : ""}
@@ -1554,6 +1637,7 @@ function defineElements(options = {}) {
1554
1637
  syncResumePath: (reference) => {
1555
1638
  this.syncResumePath(reference);
1556
1639
  },
1640
+ resumePaymentHash: () => this.resumePaymentHash(),
1557
1641
  resolvePollPrefix: (reference) => this.resolvePollPrefix(reference),
1558
1642
  dispatchError: (error) => {
1559
1643
  this.dispatchError(error);
@@ -1580,6 +1664,7 @@ function defineElements(options = {}) {
1580
1664
  OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.syncUrl,
1581
1665
  OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.resumePathPrefix,
1582
1666
  OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.routeReference,
1667
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.resumePaymentHash,
1583
1668
  OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.resumable,
1584
1669
  OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.polling,
1585
1670
  OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.pollIntervalMs,
@@ -1709,6 +1794,17 @@ function defineElements(options = {}) {
1709
1794
  this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.syncUrl)
1710
1795
  ) === true;
1711
1796
  }
1797
+ /**
1798
+ * The swap attempt this order already has in flight, if the host named one.
1799
+ *
1800
+ * Read from the attribute at prepare time rather than captured at
1801
+ * construction: a host that learns the hash asynchronously (its own order
1802
+ * fetch) sets the attribute late, and the create lifecycle re-runs.
1803
+ */
1804
+ resumePaymentHash() {
1805
+ const value = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.resumePaymentHash);
1806
+ return value === null || value.length === 0 ? void 0 : value;
1807
+ }
1712
1808
  /** Order data belongs to the host; this only performs optional History API sync. */
1713
1809
  syncResumePath(reference) {
1714
1810
  const syncUrl = parseBooleanAttribute(
@@ -1999,7 +2095,7 @@ function defineElements(options = {}) {
1999
2095
  }
2000
2096
  const swapInvoice = this.currentSwapInvoice();
2001
2097
  if (swapInvoice !== void 0) {
2002
- const display = createSwapDisplayModel2(swapInvoice, { resumable: this.isResumable() });
2098
+ const display = createSwapDisplayModel3(swapInvoice, { resumable: this.isResumable() });
2003
2099
  const swapCountdown = root.querySelector('[part="swap-countdown"]');
2004
2100
  if (swapCountdown !== null && display !== void 0) {
2005
2101
  swapCountdown.textContent = display.countdownLabel;