@openreceive/elements 0.1.1 → 0.2.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.
@@ -0,0 +1,2488 @@
1
+ // src/index.ts
2
+ import {
3
+ createThemeToggleElement,
4
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES4,
5
+ OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS as OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS2,
6
+ OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME as OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME2,
7
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES as OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES2,
8
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_EVENTS,
9
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME as OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME2
10
+ } from "@openreceive/browser/headless";
11
+
12
+ // src/define-elements.ts
13
+ import {
14
+ buildMethodGridEntries as buildMethodGridEntries2,
15
+ copyInvoice,
16
+ createCheckoutActionEvent,
17
+ createCheckoutController,
18
+ createCheckoutErrorEvent,
19
+ createCheckoutProviderCopyEvent,
20
+ createCheckoutSnapshotFromInvoice as createCheckoutSnapshotFromInvoice2,
21
+ createCheckoutStateEvent,
22
+ createCheckoutStatusModel as createCheckoutStatusModel2,
23
+ createPaymentWizardSelection,
24
+ createSwapDisplayModel as createSwapDisplayModel2,
25
+ createThemeChangeEvent,
26
+ createQrPayloadSvg,
27
+ createQrSvg,
28
+ deriveStatus as deriveStatus2,
29
+ enterCheckoutResumePath,
30
+ findSwapGridGroup as findSwapGridGroup2,
31
+ getSwapRefundFormError,
32
+ OPENRECEIVE_CHECKOUT_DATA_SELECTORS,
33
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3,
34
+ OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS,
35
+ OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS,
36
+ OPENRECEIVE_DEFAULT_PREFIX as OPENRECEIVE_DEFAULT_PREFIX2,
37
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7,
38
+ OPENRECEIVE_PAYMENT_WIZARD_SELECTORS as OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3,
39
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES,
40
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS,
41
+ OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
42
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME,
43
+ paymentMethods as paymentMethods2,
44
+ orClasses as orClasses7,
45
+ overlaySwapRefundStaging,
46
+ parseBooleanAttribute,
47
+ parseMethodPickerKey,
48
+ parseOptionalInteger,
49
+ parsePaymentMethod,
50
+ parseResolvedTheme,
51
+ parseThemePreference,
52
+ requestSwapRefund,
53
+ syncStoredThemeControls,
54
+ toggleStoredThemeControls,
55
+ updatePaymentWizardSelection,
56
+ updateSelectedSwapNetworks
57
+ } from "@openreceive/browser/headless";
58
+
59
+ // src/element-checkout-session.ts
60
+ import {
61
+ applyCheckoutElementAttributes,
62
+ createCheckoutElementAttributes,
63
+ createCheckoutSession,
64
+ mergeAttemptIntoCheckout,
65
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES,
66
+ OPENRECEIVE_DEFAULT_PREFIX,
67
+ prepareCheckout,
68
+ requestCheckout
69
+ } from "@openreceive/browser/headless";
70
+ function createElementCheckoutSession(host) {
71
+ let creating = false;
72
+ let createdKey;
73
+ let createError;
74
+ let applyingOwnAttributes = 0;
75
+ function currentPrefix() {
76
+ return host.element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.prefix) ?? OPENRECEIVE_DEFAULT_PREFIX;
77
+ }
78
+ function currentReference() {
79
+ const reference = host.element.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES.reference);
80
+ return reference === null || reference.length === 0 ? void 0 : reference;
81
+ }
82
+ function currentCreateKey() {
83
+ const reference = currentReference();
84
+ return reference === void 0 ? void 0 : `${currentPrefix()}::${reference}`;
85
+ }
86
+ function writeOwnAttributes(write) {
87
+ applyingOwnAttributes += 1;
88
+ try {
89
+ write();
90
+ } finally {
91
+ applyingOwnAttributes -= 1;
92
+ }
93
+ }
94
+ function applyOwnAttributes(attributes) {
95
+ writeOwnAttributes(() => {
96
+ applyCheckoutElementAttributes(host.element, attributes);
97
+ });
98
+ }
99
+ function publishSnapshot(snapshot) {
100
+ host.handleControllerSnapshot(snapshot);
101
+ const prefix = currentPrefix();
102
+ applyOwnAttributes(
103
+ createCheckoutElementAttributes(snapshot, {
104
+ prefix,
105
+ ...host.currentThemeOption()
106
+ })
107
+ );
108
+ host.render();
109
+ host.startCheckoutController();
110
+ }
111
+ const session = createCheckoutSession({
112
+ snapshot: () => host.latestCheckoutSnapshot(),
113
+ reference: currentReference,
114
+ requestCheckout: (reference) => {
115
+ const metadata = host.createMetadata();
116
+ return requestCheckout({
117
+ prefix: currentPrefix(),
118
+ reference,
119
+ ...metadata === void 0 ? {} : { metadata },
120
+ fetch: globalThis.fetch
121
+ });
122
+ },
123
+ onSnapshot: publishSnapshot,
124
+ swapPrefix: () => host.resolvePollPrefix(currentReference()),
125
+ fetch: () => globalThis.fetch,
126
+ swapSelection: host.swapSelection,
127
+ // A swap attempt is NOT written back as attributes: a bolt11 attribute
128
+ // would take the element out of create mode. It re-keys the poll
129
+ // controller onto the merged snapshot and nothing else.
130
+ onSwapStarted: (invoice) => {
131
+ const reference = currentReference();
132
+ if (reference === void 0) return;
133
+ const previous = host.latestCheckoutSnapshot() ?? host.currentCheckoutSnapshot();
134
+ host.handleControllerSnapshot(mergeAttemptIntoCheckout(invoice, previous, reference));
135
+ host.startCheckoutController();
136
+ },
137
+ logger: host.logger,
138
+ onError: (error) => host.dispatchError(error),
139
+ onChange: () => host.render()
140
+ });
141
+ async function createCheckout() {
142
+ const reference = currentReference();
143
+ if (reference === void 0) return;
144
+ const prefix = currentPrefix();
145
+ const key = `${prefix}::${reference}`;
146
+ if (creating) return;
147
+ if (createdKey === key) {
148
+ host.startCheckoutController();
149
+ return;
150
+ }
151
+ creating = true;
152
+ createdKey = key;
153
+ session.resetLightningRequest();
154
+ try {
155
+ createError = void 0;
156
+ host.syncResumePath(reference);
157
+ const checkout = await prepareCheckout({
158
+ prefix,
159
+ reference,
160
+ fetch: globalThis.fetch
161
+ });
162
+ if (currentCreateKey() !== key) return;
163
+ host.handleControllerSnapshot(checkout);
164
+ applyOwnAttributes(
165
+ createCheckoutElementAttributes(checkout, {
166
+ prefix,
167
+ ...host.currentThemeOption()
168
+ })
169
+ );
170
+ host.render();
171
+ host.startCheckoutController();
172
+ } catch (error) {
173
+ if (currentCreateKey() !== key) return;
174
+ createError = error instanceof Error && error.message.length > 0 ? error.message : "Could not start checkout.";
175
+ host.dispatchError(error);
176
+ host.render();
177
+ } finally {
178
+ creating = false;
179
+ const current = currentCreateKey();
180
+ if (host.element.isConnected && current !== void 0 && current !== key && host.isCreateMode()) {
181
+ void createCheckout();
182
+ }
183
+ }
184
+ }
185
+ function retryCreateCheckout() {
186
+ createdKey = void 0;
187
+ createError = void 0;
188
+ host.render();
189
+ void createCheckout();
190
+ }
191
+ return {
192
+ get createError() {
193
+ return createError;
194
+ },
195
+ get wizardError() {
196
+ return session.wizardError;
197
+ },
198
+ get swapStartError() {
199
+ return session.swapStartError;
200
+ },
201
+ get lightningRequested() {
202
+ return session.lightningRequested;
203
+ },
204
+ get mintingLightning() {
205
+ return session.mintingLightning;
206
+ },
207
+ get startingSwapAsset() {
208
+ return session.startingSwapAsset;
209
+ },
210
+ get swapQuotes() {
211
+ return session.swapQuotes;
212
+ },
213
+ get applyingOwnAttributes() {
214
+ return applyingOwnAttributes > 0;
215
+ },
216
+ createCheckout,
217
+ retryCreateCheckout,
218
+ ensureLightning: () => session.ensureLightning(),
219
+ startSwap: (payInAsset) => session.startSwap(payInAsset),
220
+ applyOwnAttributes,
221
+ writeOwnAttributes,
222
+ forgetCreateKey() {
223
+ createdKey = void 0;
224
+ }
225
+ };
226
+ }
227
+
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
+ // src/element-styles.ts
359
+ import { checkoutElementStyles } from "@openreceive/browser/headless";
360
+ var checkoutStyleTag = `<style>${checkoutElementStyles}</style>`;
361
+ var sheetsByDocument = /* @__PURE__ */ new WeakMap();
362
+ function adoptCheckoutStyles(root) {
363
+ const ownerDocument = root.ownerDocument;
364
+ if (ownerDocument === null) return false;
365
+ const view = ownerDocument.defaultView;
366
+ const SheetConstructor = view?.CSSStyleSheet ?? globalThis.CSSStyleSheet;
367
+ if (SheetConstructor === void 0 || !Array.isArray(root.adoptedStyleSheets)) return false;
368
+ let sheet = sheetsByDocument.get(ownerDocument);
369
+ if (sheet === void 0) {
370
+ try {
371
+ const created = new SheetConstructor();
372
+ if (typeof created.replaceSync !== "function") return false;
373
+ created.replaceSync(checkoutElementStyles);
374
+ sheet = created;
375
+ } catch {
376
+ return false;
377
+ }
378
+ sheetsByDocument.set(ownerDocument, sheet);
379
+ }
380
+ if (!root.adoptedStyleSheets.includes(sheet)) {
381
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
382
+ }
383
+ return true;
384
+ }
385
+
386
+ // src/render-checkout.ts
387
+ import {
388
+ assertDisplayInvoice,
389
+ createCheckoutStatusModel,
390
+ createLightningInvoiceDecodeUrl as createLightningInvoiceDecodeUrl2,
391
+ createPaymentDataEntries,
392
+ deriveCheckoutStateLabels,
393
+ deriveStatus,
394
+ escapeHtml as escapeHtml6,
395
+ formatAmountCaption,
396
+ OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES,
397
+ OPENRECEIVE_CHECKOUT_ELEMENT_PARTS,
398
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES6,
399
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_PARTS,
400
+ checkoutLabels as checkoutLabels6,
401
+ orClasses as orClasses6
402
+ } from "@openreceive/browser/headless";
403
+
404
+ // src/render-wizard.ts
405
+ import {
406
+ assetButtonClasses,
407
+ buildMethodGridEntries,
408
+ checkoutLabels as checkoutLabels5,
409
+ createPaymentWizardModel,
410
+ createSwapUnavailableModel,
411
+ createWizardRouteAssetDisplays,
412
+ createWizardRouteDisplays,
413
+ escapeHtml as escapeHtml5,
414
+ findSwapGridGroup,
415
+ formatChooseNetworkHeading,
416
+ formatNetworkSummary,
417
+ getNetworkIcon,
418
+ getPaymentMethodIcon,
419
+ getSwapOptionIcon,
420
+ getWizardEmptyMessage,
421
+ networkButtonClasses,
422
+ networkCheckClasses,
423
+ networkMobileRevealClasses,
424
+ networkSummaryIconClasses,
425
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5,
426
+ orClasses as orClasses5,
427
+ paymentAccentId,
428
+ paymentMethods,
429
+ swapAssetMatchesRoute as swapAssetMatchesRoute2,
430
+ swapGroupLimitOption,
431
+ swapPickerKey,
432
+ wizardNetworkGroupIds
433
+ } from "@openreceive/browser/headless";
434
+
435
+ // src/render-provider-tutorial.ts
436
+ import {
437
+ createLightningInvoiceDecodeUrl,
438
+ escapeHtml as escapeHtml2,
439
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2,
440
+ checkoutLabels as checkoutLabels2,
441
+ orClasses as orClasses2
442
+ } from "@openreceive/browser/headless";
443
+ function renderProviderOpenActionHtml(provider) {
444
+ if (provider.tutorials.length === 0) {
445
+ return `<a class="${orClasses2.providerOpen}" href="${escapeHtml2(provider.url)}" rel="noreferrer" target="_blank">${escapeHtml2(provider.openLabel)}</a>`;
446
+ }
447
+ return `
448
+ <button
449
+ part="provider-open"
450
+ class="${orClasses2.providerOpen}"
451
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2.providerTutorial}="${escapeHtml2(provider.id)}"
452
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2.providerTutorialIndex}="0"
453
+ type="button"
454
+ >${escapeHtml2(provider.openLabel)}</button>
455
+ `;
456
+ }
457
+ function renderTutorialModalHtml(routes, activeProviderId, activeTutorialIndex, copied, lightningInvoice, decodeLinkUrl) {
458
+ if (activeProviderId === null) return "";
459
+ const provider = routes.flatMap((route) => route.providers).find((candidate) => candidate.id === activeProviderId);
460
+ if (provider === void 0 || provider.tutorials.length === 0) return "";
461
+ const totalSteps = provider.tutorials.length + 1;
462
+ const stepIndex = Math.max(0, Math.min(provider.tutorials.length, activeTutorialIndex));
463
+ const tutorial = stepIndex === 0 ? void 0 : provider.tutorials[stepIndex - 1];
464
+ const previousIndex = Math.max(0, stepIndex - 1);
465
+ const nextIndex = Math.min(provider.tutorials.length, stepIndex + 1);
466
+ const isFinalStep = stepIndex === provider.tutorials.length;
467
+ const decodeHref = lightningInvoice === void 0 || lightningInvoice.trim() === "" ? void 0 : createLightningInvoiceDecodeUrl(lightningInvoice, decodeLinkUrl);
468
+ const decodeButton = decodeHref === void 0 ? "" : `<a part="tutorial-decode" class="${orClasses2.tutorialCopy}" href="${escapeHtml2(decodeHref)}" rel="noreferrer" target="_blank">${escapeHtml2(checkoutLabels2.decodeInvoice)}</a>`;
469
+ const body = stepIndex === 0 ? `
470
+ <div part="tutorial-intro" class="${orClasses2.tutorialIntro}">
471
+ <img part="tutorial-provider-logo" alt="" src="${escapeHtml2(provider.icon)}" class="${orClasses2.tutorialProviderLogo}">
472
+ <p>${escapeHtml2(checkoutLabels2.tutorialIntroPrefix)} ${escapeHtml2(provider.name)}.</p>
473
+ <p>${escapeHtml2(checkoutLabels2.tutorialIntroCopy)}</p>
474
+ <button part="tutorial-copy" class="${orClasses2.tutorialCopy}" type="button">${escapeHtml2(checkoutLabels2.copyInvoice)}</button>
475
+ ${decodeButton}
476
+ ${copied ? `<p part="tutorial-copy-message" class="${orClasses2.tutorialCopyMessage}">${escapeHtml2(checkoutLabels2.tutorialCopiedContinue)}</p>` : ""}
477
+ </div>
478
+ ` : `
479
+ <div part="tutorial-frame" class="${orClasses2.tutorialFrame}">
480
+ <img part="tutorial-image" class="${orClasses2.tutorialImage}" alt="${escapeHtml2(tutorial?.caption ?? "")}" src="${escapeHtml2(tutorial?.image ?? "")}">
481
+ </div>
482
+ <p part="tutorial-caption" class="${orClasses2.tutorialCaption}">${escapeHtml2(tutorial?.caption ?? "")}</p>
483
+ `;
484
+ return `
485
+ <div part="tutorial" class="${orClasses2.tutorialModal}" role="dialog" aria-modal="true" aria-label="${escapeHtml2(checkoutLabels2.tutorialTitlePrefix)} ${escapeHtml2(provider.name)}" tabindex="-1">
486
+ <div part="tutorial-dialog" class="${orClasses2.tutorialBox}">
487
+ <div part="tutorial-header" class="${orClasses2.tutorialHeader}">
488
+ <div part="tutorial-title" class="${orClasses2.tutorialTitle}">
489
+ <img part="tutorial-header-logo" alt="" src="${escapeHtml2(provider.icon)}" class="${orClasses2.tutorialHeaderLogo}">
490
+ <h3>${escapeHtml2(checkoutLabels2.tutorialTitlePrefix)} ${escapeHtml2(provider.name)}</h3>
491
+ </div>
492
+ <button
493
+ part="tutorial-close"
494
+ class="${orClasses2.tutorialClose}"
495
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2.providerTutorial}=""
496
+ type="button"
497
+ aria-label="${escapeHtml2(checkoutLabels2.tutorialClose)}"
498
+ >X</button>
499
+ </div>
500
+ ${body}
501
+ <div part="tutorial-steps" class="${orClasses2.tutorialSteps}" aria-hidden="true">
502
+ ${Array.from(
503
+ { length: totalSteps },
504
+ (_, index) => `
505
+ <span part="${index === stepIndex ? "tutorial-step-active" : "tutorial-step"}" class="${index === stepIndex ? orClasses2.tutorialStepActive : orClasses2.tutorialStep}"></span>
506
+ `
507
+ ).join("")}
508
+ </div>
509
+ <p part="tutorial-progress" class="${orClasses2.tutorialProgress}">Step ${stepIndex + 1} of ${totalSteps}</p>
510
+ <div part="tutorial-controls" class="${orClasses2.tutorialControls}">
511
+ <button
512
+ part="tutorial-nav"
513
+ class="${orClasses2.btn}"
514
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2.providerTutorial}="${escapeHtml2(provider.id)}"
515
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2.providerTutorialIndex}="${previousIndex}"
516
+ type="button"
517
+ ${stepIndex === 0 ? "disabled" : ""}
518
+ >${escapeHtml2(checkoutLabels2.tutorialBack)}</button>
519
+ <button
520
+ part="tutorial-nav"
521
+ class="${orClasses2.btn}"
522
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2.providerTutorial}="${isFinalStep ? "" : escapeHtml2(provider.id)}"
523
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES2.providerTutorialIndex}="${nextIndex}"
524
+ type="button"
525
+ >${escapeHtml2(isFinalStep ? checkoutLabels2.tutorialExit : checkoutLabels2.tutorialNext)}</button>
526
+ </div>
527
+ </div>
528
+ </div>
529
+ `;
530
+ }
531
+
532
+ // src/render-swap-panel.ts
533
+ import {
534
+ createSwapDisplayModel,
535
+ escapeHtml as escapeHtml4,
536
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4,
537
+ checkoutLabels as checkoutLabels4,
538
+ swapAssetMatchesRoute,
539
+ swapOptionLimitMessage,
540
+ orClasses as orClasses4
541
+ } from "@openreceive/browser/headless";
542
+
543
+ // src/transaction-details.ts
544
+ import {
545
+ escapeHtml as escapeHtml3,
546
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES as OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES3,
547
+ OPENRECEIVE_PAYMENT_WIZARD_SELECTORS as OPENRECEIVE_PAYMENT_WIZARD_SELECTORS2,
548
+ checkoutLabels as checkoutLabels3,
549
+ orClasses as orClasses3,
550
+ resolveTransactionDetailRows
551
+ } from "@openreceive/browser/headless";
552
+ function renderTransactionDetailsHtml(source, options = {}) {
553
+ const rows = resolveTransactionDetailRows(source);
554
+ if (rows.length === 0) return "";
555
+ const openAttr = options.open === true ? " open" : "";
556
+ const className = options.className ?? orClasses3.transactionDetails;
557
+ return `
558
+ <details part="transaction-details" class="${escapeHtml3(className)}"${openAttr}>
559
+ <summary class="${orClasses3.transactionDetailsTitle}">${escapeHtml3(checkoutLabels3.transactionDetails)}</summary>
560
+ <div class="${orClasses3.transactionDetailsContent}">
561
+ <dl part="swap-details" class="${orClasses3.swapDetails}">
562
+ ${rows.map(
563
+ (row) => renderElementSwapCopyDetailHtml(row.label, row.copyValue ?? row.value, {
564
+ displayValue: row.value,
565
+ ...row.href === void 0 ? {} : { href: row.href },
566
+ ...row.hrefLabel === void 0 ? {} : { hrefLabel: row.hrefLabel }
567
+ })
568
+ ).join("")}
569
+ </dl>
570
+ </div>
571
+ </details>
572
+ `;
573
+ }
574
+ function createTransactionDetailsElement(source, options = {}) {
575
+ const html = renderTransactionDetailsHtml(source, options);
576
+ if (html === "") return null;
577
+ const doc = options.document ?? globalThis.document;
578
+ const host = doc.createElement("div");
579
+ host.innerHTML = html.trim();
580
+ const details = host.firstElementChild;
581
+ if (!(details instanceof HTMLElement)) return null;
582
+ wireTransactionDetailsCopy(details, options.onCopyError);
583
+ return details;
584
+ }
585
+ function wireTransactionDetailsCopy(root, onCopyError) {
586
+ wireSwapSelectAllInputs(root);
587
+ for (const button of root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS2.swapCopy)) {
588
+ if (!(button instanceof HTMLButtonElement)) continue;
589
+ button.addEventListener("click", () => {
590
+ const value = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES3.swapCopy);
591
+ if (value === null || value === "") return;
592
+ void globalThis.navigator?.clipboard?.writeText(value).then(() => showElementCopyFeedback(button)).catch((error) => onCopyError?.(error));
593
+ });
594
+ }
595
+ }
596
+
597
+ // src/render-swap-panel.ts
598
+ function renderElementSwapActionsHtml(routeKey, options, view) {
599
+ const shown = options.filter((option) => option.provider.length > 0).filter((option) => swapAssetMatchesRoute(routeKey, option.pay_in_asset));
600
+ if (shown.length === 0) return "";
601
+ return `
602
+ <div part="swap-actions" class="${orClasses4.swapActions}">
603
+ ${shown.map((option) => {
604
+ const disabled = option.available === false;
605
+ const limitMessage = elementsSwapLimitMessage(option, view);
606
+ const info = disabled ? limitMessage === void 0 ? "" : `<p part="swap-warning" class="${orClasses4.swapWarning}">${escapeHtml4(limitMessage)}</p>` : option.pay_amount === void 0 ? "" : `<p part="swap-estimate" class="${orClasses4.swapEstimate}">Estimated ${escapeHtml4(option.pay_amount)} ${escapeHtml4(option.label)} to settle this checkout.</p>`;
607
+ return `
608
+ <div class="${orClasses4.swapAction}">
609
+ ${info}
610
+ <button
611
+ part="swap-start"
612
+ class="${orClasses4.swapStart}"
613
+ ${disabled ? "" : `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapStart}="${escapeHtml4(option.pay_in_asset)}"`}
614
+ ${disabled ? 'disabled aria-disabled="true"' : ""}
615
+ type="button"
616
+ >${escapeHtml4(
617
+ checkoutLabels4.createPaymentAddress.replace("{asset}", option.label).replace("{network}", option.network_label)
618
+ )}</button>
619
+ </div>
620
+ `;
621
+ }).join("")}
622
+ </div>
623
+ `;
624
+ }
625
+ function elementsSwapLimitMessage(option, view) {
626
+ const checkout = view.amountMsats === void 0 ? void 0 : {
627
+ amount_msats: view.amountMsats,
628
+ ...view.fiat?.currency === void 0 || view.fiat.value === void 0 ? {} : { fiat: { currency: view.fiat.currency, value: view.fiat.value } }
629
+ };
630
+ return swapOptionLimitMessage(option, checkout);
631
+ }
632
+ function renderElementSwapPanelHtml(invoice, view = {}) {
633
+ const display = createSwapDisplayModel(invoice);
634
+ if (display === void 0) return "";
635
+ const backButton = `
636
+ <button part="swap-back" class="${orClasses4.swapBack}" ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapBack} type="button">${escapeHtml4(checkoutLabels4.payWithLightningInstead)}</button>
637
+ `;
638
+ const supportDetails = renderElementSwapSupportDetailsHtml(display);
639
+ const heading = `
640
+ <div part="swap-heading" class="${orClasses4.swapHeading}">
641
+ <strong class="${orClasses4.swapHeadingTitle}">${escapeHtml4(display.providerStateLabel)}</strong>
642
+ <span class="${orClasses4.swapHeadingDetail}">${escapeHtml4(display.providerStateDetail)}</span>
643
+ </div>
644
+ `;
645
+ if (display.state === "creating") {
646
+ return `
647
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
648
+ <div part="status" class="${orClasses4.paymentStatus}">
649
+ <span part="spinner" class="${orClasses4.spinner}" aria-hidden="true"></span>
650
+ <div class="${orClasses4.paymentStatusBody}">
651
+ <strong class="${orClasses4.paymentStatusTitle}">${escapeHtml4(display.providerStateLabel)}</strong>
652
+ <p class="${orClasses4.paymentStatusDetail}">${escapeHtml4(display.providerStateDetail)}</p>
653
+ </div>
654
+ </div>
655
+ ${backButton}
656
+ </section>
657
+ `;
658
+ }
659
+ if (display.state === "deposit") {
660
+ const feeBreakdown = renderElementSwapFeeBreakdownHtml(display.feeBreakdown);
661
+ const waitingStatus = `
662
+ <div part="status" class="${orClasses4.paymentStatus}">
663
+ <span part="spinner" class="${orClasses4.spinner}" aria-hidden="true"></span>
664
+ <div class="${orClasses4.paymentStatusBody}">
665
+ <div class="${orClasses4.swapWaitingTitle}">
666
+ <strong class="${orClasses4.paymentStatusTitle}">${escapeHtml4(display.providerStateLabel)}</strong>
667
+ <strong part="swap-countdown" class="${orClasses4.swapCountdown}">${escapeHtml4(display.countdownLabel)}</strong>
668
+ </div>
669
+ <p class="${orClasses4.paymentStatusDetail}">${escapeHtml4(display.providerStateDetail)}</p>
670
+ </div>
671
+ </div>
672
+ `;
673
+ return `
674
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
675
+ <p part="swap-instruction" class="${orClasses4.swapInstruction}">Pay <strong>${escapeHtml4(display.depositAmount)} ${escapeHtml4(display.assetLabel)}</strong> to this address</p>
676
+ ${renderElementSwapNetworkWarningHtml(display)}
677
+ <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>
679
+ <div part="swap-deposit-side" class="${orClasses4.swapDepositSide}">
680
+ <dl part="swap-details" class="${orClasses4.swapDetails}">
681
+ ${renderElementSwapCopyDetailHtml("Address", display.depositAddress, {
682
+ selectable: true
683
+ })}
684
+ ${display.depositMemo === void 0 ? "" : renderElementSwapCopyDetailHtml("Memo", display.depositMemo)}
685
+ ${renderElementSwapCopyDetailHtml("Amount", display.depositAmount, { selectable: true })}
686
+ </dl>
687
+ ${waitingStatus}
688
+ ${feeBreakdown}
689
+ </div>
690
+ </div>
691
+ ${backButton}
692
+ </section>
693
+ `;
694
+ }
695
+ if (display.state === "settled") {
696
+ return `
697
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
698
+ ${heading}
699
+ <dl part="swap-details" class="${orClasses4.swapDetails}">
700
+ ${display.depositTxId === void 0 ? "" : renderElementSwapCopyDetailHtml("Deposit transaction", display.depositTxId, { kind: "tx", payInAsset: display.payInAsset })}
701
+ ${display.payoutTxId === void 0 ? "" : renderElementSwapCopyDetailHtml("Lightning payout", display.payoutTxId)}
702
+ ${display.providerOrderId === void 0 ? "" : renderElementSwapCopyDetailHtml("Provider order", display.providerOrderId)}
703
+ </dl>
704
+ ${renderElementTransactionDetailsHtml(invoice, view)}
705
+ </section>
706
+ `;
707
+ }
708
+ if (display.state === "progress") {
709
+ return `
710
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
711
+ <div part="status" class="${orClasses4.paymentStatus}">
712
+ <span part="spinner" class="${orClasses4.spinner}" aria-hidden="true"></span>
713
+ <div class="${orClasses4.paymentStatusBody}">
714
+ <strong class="${orClasses4.paymentStatusTitle}">${escapeHtml4(display.providerStateLabel)}</strong>
715
+ <p class="${orClasses4.paymentStatusDetail}">${escapeHtml4(display.providerStateDetail)}</p>
716
+ </div>
717
+ </div>
718
+ ${supportDetails}
719
+ </section>
720
+ `;
721
+ }
722
+ if (display.state === "expired") {
723
+ return `
724
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
725
+ ${heading}
726
+ <p part="swap-warning" class="${orClasses4.swapWarning}">This payment address expired without a detected payment. Create a new payment address to try again.</p>
727
+ ${supportDetails}
728
+ ${backButton}
729
+ </section>
730
+ `;
731
+ }
732
+ if (display.state === "refund_required") {
733
+ const stagedRefundAddress = display.refundAddress;
734
+ const refundFacts = renderElementSwapRefundFactsHtml(display);
735
+ return `
736
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
737
+ ${heading}
738
+ ${refundFacts}
739
+ <p part="swap-warning" class="${orClasses4.swapWarning}">Use a ${escapeHtml4(display.networkLabel)} address you control. Do not paste the deposit address.</p>
740
+ ${stagedRefundAddress === void 0 ? `
741
+ <form
742
+ part="swap-refund"
743
+ class="${orClasses4.swapRefund}"
744
+ novalidate
745
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundForm}="${escapeHtml4(display.attemptId)}"
746
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundPayInAsset}="${escapeHtml4(display.payInAsset)}"
747
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundNetworkLabel}="${escapeHtml4(display.networkLabel)}"
748
+ ${display.refundAllowed ? `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAllowed}="true"` : ""}
749
+ >
750
+ <input
751
+ class="${orClasses4.swapRefundInput}"
752
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAddress}
753
+ name="refund_address"
754
+ placeholder="${escapeHtml4(checkoutLabels4.refundAddressPlaceholder.replace("{network}", display.networkLabel))}"
755
+ type="text"
756
+ autocomplete="off"
757
+ required
758
+ >
759
+ <p
760
+ part="swap-refund-error"
761
+ class="${orClasses4.swapRefundError}"
762
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundError}
763
+ hidden
764
+ role="alert"
765
+ ></p>
766
+ <p part="swap-refund-hint" class="${orClasses4.swapRefundHint}">Make sure you control this ${escapeHtml4(display.networkLabel)} address. Refunds sent to the wrong address usually cannot be recovered.</p>
767
+ <button class="${orClasses4.btn}" type="submit">${escapeHtml4(checkoutLabels4.reviewRefundAddress)}</button>
768
+ </form>
769
+ ` : `
770
+ <form
771
+ part="swap-refund"
772
+ class="${orClasses4.swapRefund}"
773
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundForm}="${escapeHtml4(display.attemptId)}"
774
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundPayInAsset}="${escapeHtml4(display.payInAsset)}"
775
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundNetworkLabel}="${escapeHtml4(display.networkLabel)}"
776
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundConfirm}="true"
777
+ ${display.refundAllowed ? `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAllowed}="true"` : ""}
778
+ >
779
+ <p part="swap-warning" class="${orClasses4.swapWarning}">${escapeHtml4(checkoutLabels4.confirmRefundTo.replace("{address}", stagedRefundAddress))}</p>
780
+ <input
781
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES4.swapRefundAddress}
782
+ name="refund_address"
783
+ type="hidden"
784
+ value="${escapeHtml4(stagedRefundAddress)}"
785
+ >
786
+ <button class="${orClasses4.btn}" type="submit">${escapeHtml4(checkoutLabels4.confirmRefund)}</button>
787
+ </form>
788
+ `}
789
+ ${supportDetails}
790
+ ${renderElementSwapRefundReturnWarningHtml()}
791
+ </section>
792
+ `;
793
+ }
794
+ if (display.state === "refund_pending" || display.state === "refunded") {
795
+ const refundFacts = renderElementSwapRefundFactsHtml(display);
796
+ return `
797
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
798
+ ${heading}
799
+ ${refundFacts}
800
+ <dl part="swap-details" class="${orClasses4.swapDetails}">
801
+ ${display.refundAddress === void 0 ? "" : renderElementSwapCopyDetailHtml("Refund address", display.refundAddress, { kind: "address", payInAsset: display.payInAsset })}
802
+ ${display.refundTxId === void 0 ? "" : renderElementSwapCopyDetailHtml("Refund transaction", display.refundTxId, { kind: "tx", payInAsset: display.payInAsset })}
803
+ </dl>
804
+ ${supportDetails}
805
+ ${renderElementSwapRefundReturnWarningHtml()}
806
+ </section>
807
+ `;
808
+ }
809
+ return `
810
+ <section part="swap-panel" class="${orClasses4.swapPanel}">
811
+ ${heading}
812
+ <p part="swap-warning" class="${orClasses4.swapWarning}">${escapeHtml4(checkoutLabels4.supportReviewNeeded)}</p>
813
+ ${supportDetails}
814
+ ${backButton}
815
+ </section>
816
+ `;
817
+ }
818
+ function renderElementSwapRefundReturnWarningHtml() {
819
+ return `
820
+ <p part="swap-refund-return" class="${orClasses4.swapWarning}">${escapeHtml4(checkoutLabels4.refundReturnWarning)}</p>
821
+ `;
822
+ }
823
+ function renderElementSwapRefundFactsHtml(display) {
824
+ const rows = [
825
+ display.depositReceivedAmount === void 0 ? "" : renderElementSwapCopyDetailHtml(
826
+ "Amount received",
827
+ `${display.depositReceivedAmount} ${display.assetLabel}`
828
+ ),
829
+ display.depositReceivedAmount === void 0 ? "" : renderElementSwapCopyDetailHtml(
830
+ "Amount required",
831
+ `${display.depositAmount} ${display.assetLabel}`
832
+ ),
833
+ display.refundAmount === void 0 ? "" : renderElementSwapCopyDetailHtml(
834
+ "Estimated refund",
835
+ `${display.refundAmount} ${display.assetLabel}`
836
+ )
837
+ ].join("");
838
+ if (rows.length === 0) return "";
839
+ return `<dl part="swap-details" class="${orClasses4.swapDetails}">${rows}</dl>`;
840
+ }
841
+ function renderElementSwapNetworkWarningHtml(display) {
842
+ const emphasisStart = display.networkWarning.indexOf(display.networkWarningEmphasis);
843
+ const before = emphasisStart === -1 ? escapeHtml4(display.networkWarning) : escapeHtml4(display.networkWarning.slice(0, emphasisStart));
844
+ const after = emphasisStart === -1 ? "" : escapeHtml4(
845
+ display.networkWarning.slice(emphasisStart + display.networkWarningEmphasis.length)
846
+ );
847
+ const emphasis = emphasisStart === -1 ? "" : `<strong class="${orClasses4.swapNetworkWarningEmphasis}">${escapeHtml4(display.networkWarningEmphasis)}</strong>`;
848
+ return `
849
+ <div part="swap-network-warning" role="alert" class="${orClasses4.swapNetworkWarning}">
850
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="${orClasses4.swapNetworkWarningIcon}" aria-hidden="true">
851
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="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" />
852
+ </svg>
853
+ <div class="${orClasses4.swapNetworkWarningContent}">
854
+ <p class="${orClasses4.swapNetworkWarningTitle}">${escapeHtml4(display.networkWarningTitle)}</p>
855
+ <p class="${orClasses4.swapNetworkWarningBody}">${before}${emphasis}${after}</p>
856
+ </div>
857
+ </div>
858
+ `;
859
+ }
860
+ function renderElementTransactionDetailsHtml(invoice, view) {
861
+ const bolt11 = typeof invoice.invoice === "string" ? invoice.invoice : view.lightningInvoice;
862
+ return renderTransactionDetailsHtml({
863
+ ...view.reference === void 0 ? {} : { reference: view.reference },
864
+ ...view.checkoutId === void 0 ? {} : { checkout_id: view.checkoutId },
865
+ invoice_id: invoice.invoice_id,
866
+ ...bolt11 === void 0 ? {} : { invoice: bolt11 },
867
+ rail: invoice.rail,
868
+ ...invoice.payment_hash === void 0 ? view.paymentHash === void 0 ? {} : { payment_hash: view.paymentHash } : { payment_hash: invoice.payment_hash },
869
+ ...invoice.amount_msats === void 0 ? view.amountMsats === void 0 ? {} : { amount_msats: view.amountMsats } : { amount_msats: invoice.amount_msats },
870
+ ...invoice.fiat_quote === void 0 ? view.fiat?.currency === void 0 || view.fiat.value === void 0 ? {} : { fiat_quote: { fiat: { currency: view.fiat.currency, value: view.fiat.value } } } : { fiat_quote: invoice.fiat_quote },
871
+ ...invoice.transaction_state === void 0 ? {} : { transaction_state: invoice.transaction_state },
872
+ ...invoice.workflow_state === void 0 ? {} : { workflow_state: invoice.workflow_state },
873
+ ...invoice.expires_at === void 0 ? {} : { expires_at: invoice.expires_at },
874
+ ...invoice.settled_at === void 0 ? {} : { settled_at: invoice.settled_at },
875
+ ...invoice.swap === void 0 ? {} : { swap: invoice.swap }
876
+ });
877
+ }
878
+ function renderElementSwapFeeBreakdownHtml(breakdown) {
879
+ if (breakdown === void 0) return "";
880
+ const feeValue = breakdown.feePercent === void 0 ? breakdown.fee : `${breakdown.fee} (${breakdown.feePercent})`;
881
+ return `
882
+ <div part="swap-breakdown" class="${orClasses4.swapBreakdown}">
883
+ <p part="swap-breakdown-title" class="${orClasses4.swapBreakdownTitle}">${escapeHtml4(checkoutLabels4.paymentBreakdown)}</p>
884
+ <dl part="swap-details" class="${orClasses4.swapBreakdownRows}">
885
+ <dt>${escapeHtml4(checkoutLabels4.cartTotal)}</dt>
886
+ <dd>${escapeHtml4(breakdown.cartTotal)}</dd>
887
+ <dt>${escapeHtml4(checkoutLabels4.youSend)}</dt>
888
+ <dd>${escapeHtml4(breakdown.youSend)}</dd>
889
+ <dt>${escapeHtml4(checkoutLabels4.swapAndNetworkFees)}</dt>
890
+ <dd>${escapeHtml4(feeValue)}</dd>
891
+ </dl>
892
+ </div>
893
+ `;
894
+ }
895
+ function renderElementSwapSupportDetailsHtml(display) {
896
+ if (display.depositTxId === void 0 && display.payoutTxId === void 0 && display.refundTxId === void 0 && display.providerOrderId === void 0) {
897
+ return "";
898
+ }
899
+ return `
900
+ <details part="swap-support" class="${orClasses4.swapSupport}">
901
+ <summary class="${orClasses4.swapSupportTitle}">Payment details</summary>
902
+ <div class="${orClasses4.swapSupportContent}">
903
+ <dl part="swap-details" class="${orClasses4.swapDetails}">
904
+ ${display.depositTxId === void 0 ? "" : renderElementSwapCopyDetailHtml("Deposit transaction", display.depositTxId, { kind: "tx", payInAsset: display.payInAsset })}
905
+ ${display.payoutTxId === void 0 ? "" : renderElementSwapCopyDetailHtml("Lightning payout", display.payoutTxId)}
906
+ ${display.refundTxId === void 0 ? "" : renderElementSwapCopyDetailHtml("Refund transaction", display.refundTxId, { kind: "tx", payInAsset: display.payInAsset })}
907
+ ${display.providerOrderId === void 0 ? "" : renderElementSwapCopyDetailHtml("Provider order", display.providerOrderId)}
908
+ </dl>
909
+ </div>
910
+ </details>
911
+ `;
912
+ }
913
+
914
+ // src/render-wizard.ts
915
+ function wizardStartingAsset(view) {
916
+ const asset = view.startingSwapAsset;
917
+ return asset !== void 0 && asset !== null && asset.length > 0 ? asset : void 0;
918
+ }
919
+ function swapGroupIsStarting(group, startingAsset) {
920
+ return startingAsset !== void 0 && group.options.some((option) => option.pay_in_asset === startingAsset);
921
+ }
922
+ function renderElementSwapUnavailableHtml(quote, checkout) {
923
+ const model = createSwapUnavailableModel(quote, checkout);
924
+ return `<section part="swap-panel" class="${orClasses5.swapPanel}">
925
+ <div part="swap-heading" class="${orClasses5.swapHeading}">
926
+ <strong class="${orClasses5.swapHeadingTitle}">${escapeHtml5(model.title)}</strong>
927
+ </div>
928
+ <p part="swap-warning" class="${orClasses5.swapWarning}">${escapeHtml5(model.detail)}</p>
929
+ ${model.range === void 0 ? "" : `<p class="${orClasses5.swapWarning}">${escapeHtml5(model.range)}</p>`}
930
+ <p class="${orClasses5.swapProgress}">${escapeHtml5(model.hint)}</p>
931
+ </section>`;
932
+ }
933
+ function renderPaymentWizardHtml(view = {}) {
934
+ const selection = {
935
+ selectedMethod: view.selectedMethod ?? null,
936
+ selectedBitcoinRoute: view.selectedBitcoinRoute ?? null
937
+ };
938
+ const model = createPaymentWizardModel(selection);
939
+ const { wizard } = model;
940
+ const routeAssetDisplays = createWizardRouteAssetDisplays(model.routeAssets, {
941
+ selectedRoute: model.selectedRoute
942
+ });
943
+ const routeDisplays = createWizardRouteDisplays(wizard.routes);
944
+ const showRoutePicker = routeAssetDisplays.length > 0 && (model.selectedRoute === null || routeDisplays.length === 0);
945
+ const breadcrumbs = selection.selectedMethod === null ? "" : renderWizardBreadcrumbsHtml({
946
+ method: selection.selectedMethod,
947
+ selectedRoute: model.selectedRoute,
948
+ routeAssets: routeAssetDisplays
949
+ });
950
+ const swapAssetOptions = (view.swapOptions ?? []).filter((option) => option.provider.length > 0);
951
+ const selectedSwapAsset = view.selectedSwapAsset ?? null;
952
+ const selectedSwapOption = selectedSwapAsset === null ? void 0 : swapAssetOptions.find((option) => option.pay_in_asset === selectedSwapAsset);
953
+ if (selectedSwapAsset !== null) {
954
+ const label = selectedSwapOption === void 0 ? "this coin" : `${selectedSwapOption.label} \xB7 ${selectedSwapOption.network_label}`;
955
+ const activeSwap = view.swapInvoice !== void 0 && view.swapInvoice.swap?.pay_in_asset === selectedSwapAsset ? view.swapInvoice : void 0;
956
+ return `
957
+ <section part="wizard" class="${orClasses5.wizard}" ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.root}>
958
+ <div class="${orClasses5.wizardBody}">
959
+ <div part="wizard-breadcrumbs" class="${orClasses5.breadcrumbs}">
960
+ <button
961
+ part="wizard-breadcrumb"
962
+ class="${orClasses5.btnGhost}"
963
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.breadcrumb}="swap-asset"
964
+ type="button"
965
+ >${escapeHtml5(checkoutLabels5.switchPaymentMethod)}</button>
966
+ <span aria-hidden="true">/</span>
967
+ <span part="wizard-breadcrumb-current" class="${orClasses5.breadcrumbCurrent}">${escapeHtml5(label)}</span>
968
+ </div>
969
+ <div part="wizard-results" class="${orClasses5.wizardResults}">
970
+ ${activeSwap !== void 0 ? renderElementSwapPanelHtml(activeSwap, view) : view.swapStartError !== void 0 ? `<section part="swap-panel" class="${orClasses5.swapPanel}">
971
+ <div part="swap-error" role="alert" class="${orClasses5.paymentStatus}">
972
+ <div class="${orClasses5.paymentStatusBody}">
973
+ <strong class="${orClasses5.paymentStatusTitle}">${escapeHtml5(checkoutLabels5.swapStartFailedTitle)}</strong>
974
+ <p class="${orClasses5.paymentStatusDetail}">${escapeHtml5(view.swapStartError)}</p>
975
+ <button
976
+ part="swap-retry"
977
+ class="${orClasses5.btn}"
978
+ type="button"
979
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.swapStart}="${escapeHtml5(selectedSwapAsset)}"
980
+ >${escapeHtml5(checkoutLabels5.tryAgain)}</button>
981
+ </div>
982
+ </div>
983
+ </section>` : view.unavailableSwapQuote !== void 0 ? renderElementSwapUnavailableHtml(
984
+ view.unavailableSwapQuote,
985
+ view.swapLimitContext
986
+ ) : `<section part="swap-panel" class="${orClasses5.swapPanel}">
987
+ <div part="status" class="${orClasses5.paymentStatus}">
988
+ <span part="spinner" class="${orClasses5.spinner}" aria-hidden="true"></span>
989
+ <div class="${orClasses5.paymentStatusBody}">
990
+ <strong class="${orClasses5.paymentStatusTitle}">${escapeHtml5(checkoutLabels5.preparingPaymentAddress)}</strong>
991
+ <p class="${orClasses5.paymentStatusDetail}">${escapeHtml5(
992
+ checkoutLabels5.preparingPaymentAddressDetail.replace(
993
+ "{asset}",
994
+ selectedSwapOption?.label ?? "coin"
995
+ )
996
+ )}</p>
997
+ </div>
998
+ </div>
999
+ </section>`}
1000
+ </div>
1001
+ </div>
1002
+ </section>
1003
+ `;
1004
+ }
1005
+ const methodPicker = selection.selectedMethod === null ? renderElementCompactPaymentSelectorHtml(swapAssetOptions, view) : "";
1006
+ return `
1007
+ <section part="wizard" class="${orClasses5.wizard}" ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.root}>
1008
+ ${view.wizardError === void 0 ? "" : `<p part="wizard-error" role="alert" class="${orClasses5.paymentStatusDetail}">${escapeHtml5(view.wizardError)}</p>`}
1009
+ ${methodPicker}
1010
+ ${selection.selectedMethod === null ? "" : `
1011
+ <div class="${orClasses5.wizardBody}">
1012
+ ${breadcrumbs}
1013
+ ${showRoutePicker ? `
1014
+ <div part="route-picker" class="${orClasses5.routePicker}">
1015
+ ${routeAssetDisplays.map(
1016
+ (asset) => `
1017
+ <button
1018
+ part="route${asset.selected ? " selected" : ""}"
1019
+ class="${asset.selected ? orClasses5.routeButtonSelected : orClasses5.routeButton}"
1020
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.route}="${escapeHtml5(asset.id)}"
1021
+ type="button"
1022
+ >
1023
+ <img class="${orClasses5.methodIcon}" alt="" src="${escapeHtml5(asset.icon)}">
1024
+ <strong class="${orClasses5.methodTitle}">${escapeHtml5(asset.label)}</strong>
1025
+ <small class="${orClasses5.methodDetail}">${escapeHtml5(asset.subtitle)}</small>
1026
+ </button>
1027
+ `
1028
+ ).join("")}
1029
+ </div>
1030
+ ` : ""}
1031
+ ${`
1032
+ <div part="wizard-results" class="${orClasses5.wizardResults}">
1033
+ ${routeDisplays.length === 0 ? `
1034
+ <p part="wizard-empty" class="${orClasses5.wizardEmpty}">${escapeHtml5(
1035
+ getWizardEmptyMessage()
1036
+ )}</p>
1037
+ ` : routeDisplays.map((route) => {
1038
+ const activeSwap = view.swapInvoice !== void 0 && swapAssetMatchesRoute2(route.key, view.swapInvoice.swap?.pay_in_asset) ? view.swapInvoice : void 0;
1039
+ return `
1040
+ <section part="wizard-route" class="${orClasses5.wizardRoute}">
1041
+ <h3 class="${orClasses5.wizardRouteHeading}">
1042
+ ${escapeHtml5(route.title)}
1043
+ </h3>
1044
+ ${activeSwap === void 0 ? renderElementSwapActionsHtml(route.key, view.swapOptions ?? [], view) : renderElementSwapPanelHtml(activeSwap, view)}
1045
+ ${activeSwap === void 0 ? `<div part="provider-grid" class="${orClasses5.providerGrid}">
1046
+ ${route.providers.map(
1047
+ (provider) => `
1048
+ <article part="provider" class="${orClasses5.providerCard}">
1049
+ <div part="provider-heading" class="${orClasses5.providerHeading}">
1050
+ <img class="${orClasses5.providerIcon}" alt="" src="${escapeHtml5(provider.icon)}">
1051
+ <h4 class="${orClasses5.providerName}">${escapeHtml5(provider.name)}</h4>
1052
+ </div>
1053
+ <p part="provider-kind" class="${orClasses5.providerKind}">${escapeHtml5(provider.kind)}</p>
1054
+ <div part="provider-actions" class="${orClasses5.providerActions}">
1055
+ ${renderProviderOpenActionHtml(provider)}
1056
+ </div>
1057
+ </article>
1058
+ `
1059
+ ).join("")}
1060
+ </div>` : ""}
1061
+ </section>
1062
+ `;
1063
+ }).join("")}
1064
+ </div>
1065
+ `}
1066
+ </div>
1067
+ `}
1068
+ ${renderTutorialModalHtml(
1069
+ routeDisplays,
1070
+ view.activeTutorialProviderId ?? null,
1071
+ view.activeTutorialIndex ?? 0,
1072
+ view.activeTutorialCopied ?? false,
1073
+ view.lightningInvoice,
1074
+ view.decodeLinkUrl
1075
+ )}
1076
+ </section>
1077
+ `;
1078
+ }
1079
+ function renderElementCompactPaymentSelectorHtml(swapAssetOptions, view) {
1080
+ const entries = buildMethodGridEntries(paymentMethods, swapAssetOptions);
1081
+ const currenciesLoading = view.currenciesLoading === true && swapAssetOptions.length === 0;
1082
+ const selectedKey = view.selectedPickerKey ?? null;
1083
+ const selectedGroup = findSwapGridGroup(entries, selectedKey);
1084
+ const networkRequired = selectedGroup !== void 0 && selectedGroup.options.length > 1;
1085
+ const selectedNetworks = view.selectedSwapNetworks ?? {};
1086
+ const selectedGroupKey = selectedGroup?.label.trim().toUpperCase();
1087
+ const selectedNetworkAsset = selectedGroupKey === void 0 ? void 0 : selectedNetworks[selectedGroupKey];
1088
+ const selectedNetworkOption = selectedGroup === void 0 || selectedNetworkAsset === void 0 ? void 0 : selectedGroup.options.find((option) => option.pay_in_asset === selectedNetworkAsset);
1089
+ const startingAsset = wizardStartingAsset(view);
1090
+ const gridBusy = startingAsset !== void 0;
1091
+ let continueDisabled = selectedNetworkOption === void 0 || gridBusy;
1092
+ let continueAttr = "";
1093
+ let continueLabel = escapeHtml5(checkoutLabels5.continue);
1094
+ const continueStarting = selectedNetworkOption !== void 0 && selectedNetworkOption.pay_in_asset === startingAsset;
1095
+ if (selectedNetworkOption !== void 0) {
1096
+ const disabled = selectedNetworkOption.available === false;
1097
+ const limitMessage = elementsSwapLimitMessage(selectedNetworkOption, view);
1098
+ continueDisabled = disabled || gridBusy;
1099
+ continueAttr = disabled || gridBusy ? "" : `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.swapStart}="${escapeHtml5(selectedNetworkOption.pay_in_asset)}"`;
1100
+ if (disabled && limitMessage !== void 0) continueLabel = escapeHtml5(limitMessage);
1101
+ else if (continueStarting) continueLabel = escapeHtml5(checkoutLabels5.preparingPayment);
1102
+ } else if (networkRequired) {
1103
+ continueDisabled = true;
1104
+ }
1105
+ const continueButton = (className) => renderElementMethodConfirmHtml({
1106
+ className,
1107
+ disabled: continueDisabled,
1108
+ starting: continueStarting,
1109
+ swapStartAsset: continueAttr.length === 0 || selectedNetworkOption === void 0 ? void 0 : selectedNetworkOption.pay_in_asset,
1110
+ label: continueLabel
1111
+ });
1112
+ const tiles = entries.map((entry) => {
1113
+ if (entry.kind === "method") {
1114
+ const method = entry.method;
1115
+ const accent = paymentAccentId(method.id);
1116
+ return `
1117
+ <button
1118
+ part="method"
1119
+ type="button"
1120
+ class="${assetButtonClasses({ accent, selected: false, disabled: gridBusy })}"
1121
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.method}="${escapeHtml5(method.id)}"
1122
+ ${gridBusy ? 'disabled aria-disabled="true"' : ""}
1123
+ >
1124
+ <span aria-hidden="true" class="${orClasses5.methodIconWrap}">
1125
+ <img class="${orClasses5.methodIcon}" alt="" src="${escapeHtml5(getPaymentMethodIcon(method.id))}">
1126
+ </span>
1127
+ <span class="${orClasses5.methodTitleWrap}">
1128
+ <span class="${orClasses5.methodTitle}">${escapeHtml5(method.title)}</span>
1129
+ </span>
1130
+ </button>`;
1131
+ }
1132
+ return renderElementSwapMethodGroupHtml(
1133
+ entry.group,
1134
+ view,
1135
+ selectedKey,
1136
+ selectedKey === swapPickerKey(entry.group.label) ? continueButton(orClasses5.methodConfirmDesktop) : void 0
1137
+ );
1138
+ }).join("");
1139
+ const loadingTile = currenciesLoading ? `<div part="currencies-loading" role="status" aria-live="polite" class="${orClasses5.methodCurrenciesLoading}">
1140
+ <span part="spinner" class="${orClasses5.spinner}" aria-hidden="true"></span>
1141
+ <span class="${orClasses5.methodTitle}">${escapeHtml5(checkoutLabels5.loadingCurrencies)}</span>
1142
+ </div>` : "";
1143
+ const desktopReveal = networkRequired && selectedGroup !== void 0 ? `<div class="${orClasses5.methodNetworkRevealDesktop}">${renderElementNetworkSelectorHtml(
1144
+ selectedGroup,
1145
+ view,
1146
+ continueButton(orClasses5.methodConfirmDesktop),
1147
+ false
1148
+ )}</div>` : "";
1149
+ return `
1150
+ <header class="${orClasses5.wizardHeader}">
1151
+ <h2 id="payment-method-heading" class="${orClasses5.wizardHeaderTitle}">${escapeHtml5(checkoutLabels5.wizardTitle)}</h2>
1152
+ <p class="${orClasses5.wizardHeaderSubtitle}">${escapeHtml5(checkoutLabels5.wizardSubtitle)}</p>
1153
+ </header>
1154
+ <div class="${orClasses5.wizardBody}" aria-labelledby="payment-method-heading">
1155
+ <div part="method-grid" role="group" aria-label="${escapeHtml5(checkoutLabels5.paymentMethod)}" class="${orClasses5.methodGrid}">
1156
+ ${tiles}${loadingTile}
1157
+ </div>
1158
+ ${desktopReveal}
1159
+ </div>
1160
+ `;
1161
+ }
1162
+ function renderElementNetworkSelectorHtml(group, view, continueButtonHtml, mobile) {
1163
+ const accent = paymentAccentId(group.label);
1164
+ const groupKey = group.label.trim().toUpperCase();
1165
+ const selectedNetworks = view.selectedSwapNetworks ?? {};
1166
+ const selectedAsset = selectedNetworks[groupKey];
1167
+ const selectedOption = selectedAsset === void 0 ? void 0 : group.options.find((option) => option.pay_in_asset === selectedAsset);
1168
+ const { panelId, headingId } = wizardNetworkGroupIds(groupKey);
1169
+ const networkButtons = group.options.map((option) => {
1170
+ const optionDisabled = option.available === false;
1171
+ const optionSelected = option.pay_in_asset === selectedOption?.pay_in_asset;
1172
+ const optionLimit = elementsSwapLimitMessage(option, view);
1173
+ return `
1174
+ <div class="${orClasses5.methodTile}">
1175
+ <button
1176
+ type="button"
1177
+ aria-pressed="${optionSelected ? "true" : "false"}"
1178
+ class="${networkButtonClasses({
1179
+ accent,
1180
+ selected: optionSelected,
1181
+ disabled: optionDisabled
1182
+ })}"
1183
+ ${optionDisabled ? 'disabled aria-disabled="true"' : ""}
1184
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.swapNetwork}="${escapeHtml5(groupKey)}"
1185
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.swapNetworkValue}="${escapeHtml5(option.pay_in_asset)}"
1186
+ >
1187
+ <span aria-hidden="true" class="grid size-6 shrink-0 place-items-center">
1188
+ <img class="${orClasses5.methodNetworkIcon}" alt="" src="${escapeHtml5(getNetworkIcon(option.network_label))}">
1189
+ </span>
1190
+ <span class="truncate">${escapeHtml5(option.network_label)}</span>
1191
+ ${optionSelected ? `<span aria-hidden="true" class="${networkCheckClasses(accent)}">\u2713</span>` : ""}
1192
+ </button>
1193
+ ${optionDisabled && optionLimit !== void 0 ? `<span class="${orClasses5.methodLimitHint}">${escapeHtml5(optionLimit)}</span>` : ""}
1194
+ </div>`;
1195
+ }).join("");
1196
+ const summary = selectedOption === void 0 ? "" : `<p aria-live="polite" class="${orClasses5.methodNetworkSummary}">
1197
+ <span aria-hidden="true" class="${networkSummaryIconClasses(accent)}">\u2713</span>
1198
+ ${escapeHtml5(formatNetworkSummary(group.label, selectedOption.network_label))}
1199
+ </p>`;
1200
+ return `
1201
+ <div
1202
+ id="${panelId}"
1203
+ role="group"
1204
+ aria-labelledby="${headingId}"
1205
+ class="${mobile ? networkMobileRevealClasses(accent) : orClasses5.methodNetworkReveal}"
1206
+ >
1207
+ <div class="${orClasses5.methodNetworkLayout}">
1208
+ <div>
1209
+ <h3 id="${headingId}" class="${orClasses5.methodNetworkHeading}">${escapeHtml5(
1210
+ formatChooseNetworkHeading(group.label)
1211
+ )}</h3>
1212
+ <p class="${orClasses5.methodNetworkHint}">${escapeHtml5(
1213
+ checkoutLabels5.selectNetworkToContinue
1214
+ )}</p>
1215
+ </div>
1216
+ <div role="group" aria-labelledby="${headingId}" class="${orClasses5.methodNetworkGrid}">
1217
+ ${networkButtons}
1218
+ </div>
1219
+ ${continueButtonHtml}
1220
+ </div>
1221
+ ${summary}
1222
+ </div>`;
1223
+ }
1224
+ function renderElementMethodConfirmHtml(options) {
1225
+ const swapStart = options.disabled || options.swapStartAsset === void 0 ? "" : `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.swapStart}="${escapeHtml5(options.swapStartAsset)}"`;
1226
+ return `
1227
+ <button
1228
+ type="button"
1229
+ part="method-confirm"
1230
+ class="${options.className}"
1231
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.pickerContinue}=""
1232
+ ${swapStart}
1233
+ ${options.disabled ? 'disabled aria-disabled="true"' : ""}
1234
+ ${options.starting ? 'aria-busy="true"' : ""}
1235
+ >${options.starting ? `<span part="spinner" class="${orClasses5.continueSpinner}" aria-hidden="true"></span>` : ""}${options.label}</button>`;
1236
+ }
1237
+ function renderElementSwapMethodGroupHtml(group, view, selectedKey, continueButtonHtml) {
1238
+ const selectedNetworks = view.selectedSwapNetworks ?? {};
1239
+ const groupKey = group.label.trim().toUpperCase();
1240
+ const pickerKey = swapPickerKey(group.label);
1241
+ const selected = selectedKey === pickerKey;
1242
+ const displayOption = group.options.find((option) => option.available !== false) ?? group.options[0];
1243
+ if (displayOption === void 0) return "";
1244
+ const multiNetwork = group.options.length > 1;
1245
+ const selectedAsset = selectedNetworks[groupKey];
1246
+ const selectedOption = selectedAsset === void 0 ? void 0 : group.options.find((option) => option.pay_in_asset === selectedAsset);
1247
+ const activeOption = selectedOption ?? displayOption;
1248
+ const startingAsset = wizardStartingAsset(view);
1249
+ const starting = swapGroupIsStarting(group, startingAsset);
1250
+ const gridBusy = startingAsset !== void 0;
1251
+ const disabled = group.options.every((option) => option.available === false);
1252
+ const accent = paymentAccentId(group.label);
1253
+ const limitOption = disabled ? swapGroupLimitOption(group.options) ?? activeOption : activeOption;
1254
+ const limitMessage = elementsSwapLimitMessage(limitOption, view);
1255
+ const { panelId } = wizardNetworkGroupIds(groupKey);
1256
+ const networkDetail = !disabled && multiNetwork ? selected && selectedOption !== void 0 ? `${escapeHtml5(selectedOption.network_label)} network` : escapeHtml5(checkoutLabels5.selectNetwork) : void 0;
1257
+ const mobileReveal = multiNetwork ? `
1258
+ <div class="${orClasses5.methodNetworkRevealAnim} ${selected ? orClasses5.methodNetworkRevealAnimOpen : orClasses5.methodNetworkRevealAnimClosed}">
1259
+ <div class="${orClasses5.methodNetworkRevealInner}">
1260
+ ${selected ? renderElementNetworkSelectorHtml(group, view, continueButtonHtml ?? "", true) : ""}
1261
+ </div>
1262
+ </div>` : "";
1263
+ return `
1264
+ <div class="${orClasses5.methodTile}">
1265
+ <button
1266
+ part="method"
1267
+ type="button"
1268
+ aria-pressed="${starting || multiNetwork && selected ? "true" : "false"}"
1269
+ ${multiNetwork ? `aria-expanded="${selected ? "true" : "false"}" aria-controls="${panelId}"` : ""}
1270
+ class="${assetButtonClasses({
1271
+ accent,
1272
+ selected: starting || multiNetwork && selected,
1273
+ disabled: disabled || gridBusy && !starting
1274
+ })}"
1275
+ ${disabled || gridBusy ? 'disabled aria-disabled="true"' : ""}
1276
+ ${starting ? 'aria-busy="true"' : ""}
1277
+ ${disabled || gridBusy ? "" : multiNetwork ? `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.pickerSelect}="${escapeHtml5(pickerKey)}"` : `${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.swapStart}="${escapeHtml5(displayOption.pay_in_asset)}"`}
1278
+ >
1279
+ <span aria-hidden="true" class="${orClasses5.methodIconWrap}">
1280
+ ${starting ? `<span part="spinner" class="${orClasses5.spinner}" aria-hidden="true"></span>` : `<img class="${orClasses5.methodIcon}" alt="" src="${escapeHtml5(getSwapOptionIcon(displayOption))}">`}
1281
+ </span>
1282
+ <span class="${orClasses5.methodTitleWrap}">
1283
+ <span class="${orClasses5.methodTitle}">${escapeHtml5(group.label)}</span>
1284
+ ${networkDetail === void 0 ? "" : `<span class="${orClasses5.methodDetailMobile}">${networkDetail}</span>`}
1285
+ </span>
1286
+ </button>
1287
+ ${disabled && limitMessage !== void 0 ? `<span class="${orClasses5.methodLimitHint}">${escapeHtml5(limitMessage)}</span>` : ""}
1288
+ ${mobileReveal}
1289
+ </div>`;
1290
+ }
1291
+ function renderWizardBreadcrumbsHtml(options) {
1292
+ const method = paymentMethods.find((candidate) => candidate.id === options.method);
1293
+ const methodLabel = method?.title ?? checkoutLabels5.paymentMethod;
1294
+ const routeLabel = options.selectedRoute === null || options.routeAssets.length <= 1 ? null : options.routeAssets.find((asset) => asset.id === options.selectedRoute)?.label ?? options.selectedRoute;
1295
+ return `
1296
+ <nav part="wizard-breadcrumbs" class="${orClasses5.breadcrumbs}" aria-label="Payment path">
1297
+ <button
1298
+ part="wizard-breadcrumb"
1299
+ class="${orClasses5.btnGhost}"
1300
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.breadcrumb}="method"
1301
+ type="button"
1302
+ >
1303
+ <span>${escapeHtml5(checkoutLabels5.switchPaymentMethod)}</span>
1304
+ </button>
1305
+ <span part="wizard-breadcrumb-separator" aria-hidden="true">/</span>
1306
+ ${routeLabel === null ? `<span part="wizard-breadcrumb-current" class="${orClasses5.breadcrumbCurrent}">${escapeHtml5(methodLabel)}</span>` : `
1307
+ <button
1308
+ part="wizard-breadcrumb"
1309
+ class="${orClasses5.btnGhost}"
1310
+ ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES5.breadcrumb}="route"
1311
+ type="button"
1312
+ >
1313
+ <span>${escapeHtml5(methodLabel)}</span>
1314
+ </button>
1315
+ <span part="wizard-breadcrumb-separator" aria-hidden="true">/</span>
1316
+ <span part="wizard-breadcrumb-current" class="${orClasses5.breadcrumbCurrent}">${escapeHtml5(routeLabel)}</span>
1317
+ `}
1318
+ </nav>
1319
+ `;
1320
+ }
1321
+
1322
+ // src/views.ts
1323
+ import {
1324
+ createCheckoutSnapshotFromInvoice,
1325
+ createCheckoutState
1326
+ } from "@openreceive/browser/headless";
1327
+ function parseElementInvoiceId(value) {
1328
+ if (value === null || value.trim() === "") return void 0;
1329
+ return value;
1330
+ }
1331
+ function createElementCheckoutState(view) {
1332
+ const invoiceId = parseElementInvoiceId(view.invoice_id ?? null);
1333
+ if (invoiceId === void 0) return void 0;
1334
+ return createCheckoutState(
1335
+ createCheckoutSnapshotFromInvoice({
1336
+ invoice_id: invoiceId,
1337
+ invoice: view.invoice,
1338
+ rail: view.rail ?? "lightning",
1339
+ ...view.payment_hash === void 0 ? {} : { payment_hash: view.payment_hash },
1340
+ ...view.amount_msats === void 0 ? {} : { amount_msats: view.amount_msats },
1341
+ ...view.fiat_quote === void 0 ? {} : { fiat_quote: view.fiat_quote },
1342
+ ...view.status === void 0 ? {} : { transaction_state: transactionStateFromStatus(view.status) },
1343
+ ...view.expires_at === void 0 ? {} : { expires_at: view.expires_at }
1344
+ })
1345
+ );
1346
+ }
1347
+ function transactionStateFromStatus(status) {
1348
+ if (status === "settled") return "settled";
1349
+ if (status === "expired") return "expired";
1350
+ if (status === "failed") return "failed";
1351
+ return "pending";
1352
+ }
1353
+ function parseElementStatus(value) {
1354
+ if (value === "pending" || value === "settled" || value === "expired" || value === "failed") {
1355
+ return value;
1356
+ }
1357
+ return void 0;
1358
+ }
1359
+
1360
+ // src/render-checkout.ts
1361
+ function renderCheckoutHtml(view) {
1362
+ if (view.invoice !== "") assertDisplayInvoice(view.invoice);
1363
+ const checkoutState = view.liveState ?? createElementCheckoutState(view);
1364
+ const labels = deriveCheckoutStateLabels(view);
1365
+ const amountCaption = formatAmountCaption({
1366
+ amountLabel: labels.amountLabel,
1367
+ fiatLabel: labels.fiatLabel,
1368
+ fiatCurrency: view.fiat_quote?.fiat?.currency
1369
+ });
1370
+ const satsDetail = amountCaption === void 0 ? "" : `<div part="sats-detail" class="${orClasses6.satsDetail}">${escapeHtml6(amountCaption)}</div>`;
1371
+ const statusLabel = view.status ?? (checkoutState === void 0 ? deriveStatus(view) : deriveStatus(checkoutState));
1372
+ const showSummaryMeta = statusLabel === "settled" || statusLabel === "expired";
1373
+ const stateClass = statusLabel === "settled" ? orClasses6.stateSettled : orClasses6.statePending;
1374
+ const stateLabel = showSummaryMeta ? `<span part="state" class="${stateClass}" data-state="${escapeHtml6(statusLabel)}">${escapeHtml6(statusLabel)}</span>` : "";
1375
+ const status = checkoutState === void 0 ? "" : renderElementPaymentStatusHtml(checkoutState);
1376
+ const statusModel = checkoutState === void 0 ? void 0 : createCheckoutStatusModel(checkoutState);
1377
+ const expired = statusModel?.phase === "expired";
1378
+ const settled = statusLabel === "settled";
1379
+ const swapFocused = (view.wizard?.selectedSwapAsset ?? null) !== null;
1380
+ const hideLightning = !settled && (view.lightningRequested === false || swapFocused && !expired);
1381
+ const wizard = expired && !swapFocused || settled || view.payment_wizard === false ? "" : renderPaymentWizardHtml(view.wizard);
1382
+ const copyButton = `<button part="${OPENRECEIVE_CHECKOUT_ELEMENT_PARTS.copy}" class="${orClasses6.btn}" type="button">${COPY_INVOICE_ICON}<span ${OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES6.swapCopyLabel}>${escapeHtml6(checkoutLabels6.copyInvoice)}</span></button>`;
1383
+ const decodeInvoice = view.invoice.trim() !== "" ? view.invoice : typeof view.wizard?.lightningInvoice === "string" && view.wizard.lightningInvoice.trim() !== "" ? view.wizard.lightningInvoice : void 0;
1384
+ const decodeHref = decodeInvoice === void 0 ? void 0 : createLightningInvoiceDecodeUrl2(decodeInvoice, view.decodeLinkUrl);
1385
+ const decodeButton = decodeHref === void 0 ? "" : `<a part="decode-invoice" class="${orClasses6.btn}" href="${escapeHtml6(decodeHref)}" rel="noreferrer" target="_blank">${escapeHtml6(checkoutLabels6.decodeInvoice)}</a>`;
1386
+ const startOverButton = `<button part="${OPENRECEIVE_CHECKOUT_ELEMENT_PARTS.startOver}" class="${orClasses6.btn}" type="button">${escapeHtml6(checkoutLabels6.startOver)}</button>`;
1387
+ const lightningPane = hideLightning || expired || settled ? "" : `<div part="lightning-pane" class="${orClasses6.lightningPane}">
1388
+ <div part="qr" class="${orClasses6.qr}" ${OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES.qr}></div>
1389
+ ${satsDetail}
1390
+ </div>`;
1391
+ const paymentLayoutClass = expired || settled ? orClasses6.paymentLayoutExpired : orClasses6.paymentLayout;
1392
+ const metaRow = stateLabel === "" ? "" : `<div part="meta" class="${orClasses6.meta}">${stateLabel}</div>`;
1393
+ const invoiceTitle = expired || settled ? "" : `<p part="invoice-title" class="${orClasses6.invoiceTitle}">${escapeHtml6(checkoutLabels6.bitcoinLightningInvoice)}</p>`;
1394
+ const actions = settled ? (
1395
+ // No state means no attempt to derive one from (a standalone caller that
1396
+ // passed `status: "settled"` and no invoice-id), so the panel reads the
1397
+ // attributes directly.
1398
+ renderElementPaymentDataHtml(checkoutState ?? { ...view, rail: view.rail ?? "lightning" })
1399
+ ) : expired ? `<div part="actions" class="${orClasses6.actions}">${startOverButton}</div>` : `<div part="actions" class="${orClasses6.actions}">${copyButton}${decodeButton}</div>`;
1400
+ const resolvedTheme = view.theme ?? "light";
1401
+ return `
1402
+ ${styleTag(view.inlineStyles)}
1403
+ <section part="root" data-theme="${escapeHtml6(resolvedTheme)}" class="${orClasses6.root}">
1404
+ ${hideLightning ? "" : `<div part="payment-layout" class="${paymentLayoutClass}">
1405
+ ${lightningPane}
1406
+ <div part="payment-info" class="${orClasses6.paymentInfo}">
1407
+ ${invoiceTitle}
1408
+ ${status}
1409
+ ${metaRow}
1410
+ ${actions}
1411
+ </div>
1412
+ </div>`}
1413
+ ${wizard}
1414
+ </section>
1415
+ `;
1416
+ }
1417
+ function styleTag(inlineStyles) {
1418
+ return inlineStyles === false ? "" : checkoutStyleTag;
1419
+ }
1420
+ function renderCheckoutCreateErrorHtml(message, options = {}) {
1421
+ const resolvedTheme = options.theme ?? "light";
1422
+ const retryButton = `<button part="retry" class="${orClasses6.btn}" type="button">Try again</button>`;
1423
+ return `
1424
+ ${styleTag(options.inlineStyles)}
1425
+ <section part="root" data-theme="${escapeHtml6(resolvedTheme)}" class="${orClasses6.root}" data-openreceive-create-error>
1426
+ <div part="status" role="alert" class="${orClasses6.creating}">
1427
+ <div><strong>Could not start checkout.</strong></div>
1428
+ <p>${escapeHtml6(message)}</p>
1429
+ ${retryButton}
1430
+ </div>
1431
+ </section>
1432
+ `;
1433
+ }
1434
+ function renderCheckoutCreatingHtml(options = {}) {
1435
+ const resolvedTheme = options.theme ?? "light";
1436
+ return `
1437
+ ${styleTag(options.inlineStyles)}
1438
+ <section part="root" data-theme="${escapeHtml6(resolvedTheme)}" class="${orClasses6.root}" data-openreceive-creating>
1439
+ <div part="status" class="${orClasses6.creating}">
1440
+ <span part="spinner" class="${orClasses6.spinner}" aria-hidden="true"></span>
1441
+ <div><strong>Creating checkout\u2026</strong></div>
1442
+ </div>
1443
+ </section>
1444
+ `;
1445
+ }
1446
+ function renderThemeToggleHtml(label, options = {}) {
1447
+ return `
1448
+ ${styleTag(options.inlineStyles)}
1449
+ <button
1450
+ aria-label="${escapeHtml6(label)}"
1451
+ class="${orClasses6.themeToggle}"
1452
+ part="${OPENRECEIVE_THEME_TOGGLE_ELEMENT_PARTS.button}"
1453
+ title="${escapeHtml6(label)}"
1454
+ type="button"
1455
+ ${OPENRECEIVE_CHECKOUT_DATA_ATTRIBUTES.themeToggle}
1456
+ >${escapeHtml6(label)}</button>
1457
+ `;
1458
+ }
1459
+ var SETTLED_CHECK_ICON = `<svg part="settled-icon" class="${orClasses6.settledIcon}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true" focusable="false"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg>`;
1460
+ function renderElementPaymentStatusHtml(state) {
1461
+ const status = createCheckoutStatusModel(state);
1462
+ const countdown = status.countdownLabel === void 0 ? "" : `<small part="countdown" class="${orClasses6.countdown}">${escapeHtml6(status.countdownPrefix)} <strong class="${orClasses6.countdownStrong}">${escapeHtml6(status.countdownLabel)}</strong></small>`;
1463
+ return `
1464
+ <div part="status" role="status" aria-live="polite" class="${orClasses6.paymentStatus}">
1465
+ ${status.waiting ? `<span part="spinner" class="${orClasses6.spinner}" aria-hidden="true"></span>` : ""}
1466
+ ${status.phase === "settled" ? SETTLED_CHECK_ICON : ""}
1467
+ <div class="${orClasses6.paymentStatusBody}">
1468
+ <strong class="${orClasses6.paymentStatusTitle}">${escapeHtml6(status.title)}</strong>
1469
+ <p class="${orClasses6.paymentStatusDetail}">${escapeHtml6(status.detail)}</p>
1470
+ ${countdown}
1471
+ </div>
1472
+ </div>
1473
+ `;
1474
+ }
1475
+ function renderElementPaymentDataHtml(source) {
1476
+ const entries = createPaymentDataEntries(source);
1477
+ if (entries.length === 0) return "";
1478
+ const rows = entries.map(
1479
+ (entry) => `
1480
+ <div part="payment-data-row" class="${orClasses6.paymentDataRow}">
1481
+ <span class="${orClasses6.paymentDataKey}">${escapeHtml6(entry.label)}</span>
1482
+ <p class="${orClasses6.paymentDataValue}">${escapeHtml6(entry.value)}</p>
1483
+ </div>`
1484
+ ).join("");
1485
+ return `
1486
+ <details part="payment-data" class="${orClasses6.paymentData}">
1487
+ <summary part="payment-data-summary" class="${orClasses6.paymentDataTitle}">${escapeHtml6(checkoutLabels6.viewPaymentData)}</summary>
1488
+ <div class="${orClasses6.paymentDataBody}">${rows}</div>
1489
+ </details>
1490
+ `;
1491
+ }
1492
+
1493
+ // src/define-elements.ts
1494
+ var DEFAULT_TAG_NAME = OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME;
1495
+ function markElementConfirmButtonBusy(button) {
1496
+ button.disabled = true;
1497
+ button.setAttribute("aria-disabled", "true");
1498
+ button.setAttribute("aria-busy", "true");
1499
+ if (button.querySelector('[part="spinner"]') !== null) return;
1500
+ const spinner = button.ownerDocument.createElement("span");
1501
+ spinner.setAttribute("part", "spinner");
1502
+ spinner.className = orClasses7.continueSpinner;
1503
+ spinner.setAttribute("aria-hidden", "true");
1504
+ button.prepend(spinner);
1505
+ }
1506
+ function checkoutSnapshotDisplayKey(snapshot) {
1507
+ const { active: _active, paid_at: _paidAt, invoices, ...display } = snapshot;
1508
+ return JSON.stringify({
1509
+ ...display,
1510
+ invoices: invoices.map(
1511
+ ({ amount_msats: _amountMsats, fiat_quote: _fiatQuote, ...invoice }) => invoice
1512
+ )
1513
+ });
1514
+ }
1515
+ function defineElements(options = {}) {
1516
+ const registry = options.registry ?? globalThis.customElements;
1517
+ const HTMLElementCtor = globalThis.HTMLElement;
1518
+ const tagName = options.tagName ?? DEFAULT_TAG_NAME;
1519
+ const themeToggleTagName = options.themeToggleTagName ?? OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME;
1520
+ if (registry === void 0 || HTMLElementCtor === void 0) {
1521
+ throw new Error("Custom elements are unavailable in this environment.");
1522
+ }
1523
+ class CheckoutElement extends HTMLElementCtor {
1524
+ selection = createPaymentWizardSelection();
1525
+ activeTutorialProviderId = null;
1526
+ activeTutorialIndex = 0;
1527
+ activeTutorialCopied = false;
1528
+ swapOptions = [];
1529
+ swapOptionsLoaded = false;
1530
+ selectedSwapNetworks = {};
1531
+ selectedPickerKey = null;
1532
+ selectedSwapAsset = null;
1533
+ startedSwapInvoice;
1534
+ latestCheckoutSnapshot;
1535
+ /** Skip full shadow rebuilds when a poll returns the same payable UI. */
1536
+ lastSnapshotDisplayKey;
1537
+ dismissedSwapInvoiceId = null;
1538
+ controller;
1539
+ announcedSettledReference;
1540
+ /** Last applied state, used to detect countdown-only ticks (partial DOM update). */
1541
+ lastCheckoutState;
1542
+ /** Refund-address draft survives poll rebuilds of the shadow tree. */
1543
+ refundAddressDraft = "";
1544
+ refundAddressDraftFocused = false;
1545
+ refundAddressDraftSelectionStart = null;
1546
+ refundAddressDraftSelectionEnd = null;
1547
+ /** Tutorial provider whose dialog was last focused, so re-renders don't re-steal focus. */
1548
+ focusedTutorialProviderId = null;
1549
+ /**
1550
+ * Create mode's whole request lifecycle — prepare-once, the deferred
1551
+ * Lightning mint, the swap start — plus the guard that keeps attributes the
1552
+ * element writes itself out of attributeChangedCallback. Every one of those
1553
+ * is a double-POST guard, which is why they live together.
1554
+ */
1555
+ session = createElementCheckoutSession({
1556
+ element: this,
1557
+ logger: options.logger,
1558
+ swapSelection: {
1559
+ started: () => this.startedSwapInvoice,
1560
+ setStarted: (invoice) => {
1561
+ this.startedSwapInvoice = invoice;
1562
+ },
1563
+ dismissedInvoiceId: () => this.dismissedSwapInvoiceId,
1564
+ setDismissedInvoiceId: (invoiceId) => {
1565
+ this.dismissedSwapInvoiceId = invoiceId;
1566
+ },
1567
+ setSelectedAsset: (payInAsset) => {
1568
+ this.selectedSwapAsset = payInAsset;
1569
+ }
1570
+ },
1571
+ isCreateMode: () => this.isCreateMode(),
1572
+ render: () => {
1573
+ this.render();
1574
+ },
1575
+ startCheckoutController: () => {
1576
+ this.startCheckoutController();
1577
+ },
1578
+ handleControllerSnapshot: (snapshot) => {
1579
+ this.handleControllerSnapshot(snapshot);
1580
+ },
1581
+ latestCheckoutSnapshot: () => this.latestCheckoutSnapshot,
1582
+ currentCheckoutSnapshot: () => this.currentCheckoutSnapshot(),
1583
+ currentThemeOption: () => this.currentThemeOption(),
1584
+ createMetadata: () => this.createMetadata(),
1585
+ syncResumePath: (reference) => {
1586
+ this.syncResumePath(reference);
1587
+ },
1588
+ resolvePollPrefix: (reference) => this.resolvePollPrefix(reference),
1589
+ dispatchError: (error) => {
1590
+ this.dispatchError(error);
1591
+ }
1592
+ });
1593
+ /** When `theme` is unset, follow the nearest ancestor `[data-theme]` (e.g. ThemeScope). */
1594
+ themeAncestorObserver;
1595
+ observedThemeAncestor = null;
1596
+ static get observedAttributes() {
1597
+ return [
1598
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.reference,
1599
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.prefix,
1600
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoiceId,
1601
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoice,
1602
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.rail,
1603
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.paymentHash,
1604
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.amountMsats,
1605
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.fiatCurrency,
1606
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.fiatValue,
1607
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.status,
1608
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.expiresAt,
1609
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.theme,
1610
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.paymentWizard,
1611
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.syncUrl,
1612
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.resumePathPrefix,
1613
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.routeReference,
1614
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.polling,
1615
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.pollIntervalMs,
1616
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.decodeLinkUrl
1617
+ ];
1618
+ }
1619
+ connectedCallback() {
1620
+ this.render();
1621
+ this.syncThemeAncestorObserver();
1622
+ if (this.isCreateMode()) {
1623
+ void this.session.createCheckout();
1624
+ return;
1625
+ }
1626
+ this.startCheckoutController();
1627
+ }
1628
+ attributeChangedCallback(name, oldValue, newValue) {
1629
+ if (!this.isConnected || this.session.applyingOwnAttributes) return;
1630
+ if (oldValue === newValue) return;
1631
+ const displayOnly = name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.theme || name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.syncUrl || name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.resumePathPrefix || name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.routeReference || name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.decodeLinkUrl;
1632
+ if (displayOnly) {
1633
+ this.render();
1634
+ this.syncThemeAncestorObserver();
1635
+ return;
1636
+ }
1637
+ const pollingChanged = name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.polling || name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.pollIntervalMs;
1638
+ if (pollingChanged) {
1639
+ this.render();
1640
+ this.syncThemeAncestorObserver();
1641
+ this.startCheckoutController();
1642
+ return;
1643
+ }
1644
+ const createInputChanged = name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.reference || name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.prefix || name === OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoice;
1645
+ if (createInputChanged) {
1646
+ this.session.forgetCreateKey();
1647
+ }
1648
+ if (this.isCreateMode()) {
1649
+ this.render();
1650
+ this.syncThemeAncestorObserver();
1651
+ if (createInputChanged) {
1652
+ void this.session.createCheckout();
1653
+ }
1654
+ return;
1655
+ }
1656
+ this.render();
1657
+ this.syncThemeAncestorObserver();
1658
+ this.startCheckoutController();
1659
+ }
1660
+ disconnectedCallback() {
1661
+ this.stopCheckoutController();
1662
+ this.stopThemeAncestorObserver();
1663
+ }
1664
+ // Create mode: a `reference` is set but no `invoice` snapshot is provided. The element
1665
+ // owns the whole lifecycle — it prepares the checkout against
1666
+ // `${prefix}/checkouts/prepare` (locking the amount without minting), mints a Lightning
1667
+ // invoice only when the payer picks Bitcoin, then polls status against
1668
+ // `${prefix}/payments/check` and drives swaps under the prefix.
1669
+ isCreateMode() {
1670
+ const invoice = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoice);
1671
+ const reference = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.reference);
1672
+ return (invoice === null || invoice === "") && reference !== null && reference.length > 0;
1673
+ }
1674
+ /**
1675
+ * Create-time metadata from the JSON `metadata` attribute.
1676
+ *
1677
+ * Read lazily, at mint time — which is why `metadata` is deliberately NOT a
1678
+ * create input: a host that changes it after mount is picked up by the next
1679
+ * mint, and re-keying the prepared checkout for it would orphan the
1680
+ * prepared attempt for nothing.
1681
+ *
1682
+ * Host-authored like `poll-interval-ms`, and ruled the same way: a value
1683
+ * that is not a JSON object is a host typo and must be heard, not silently
1684
+ * dropped from the create request.
1685
+ */
1686
+ createMetadata() {
1687
+ const raw = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.metadata);
1688
+ if (raw === null || raw.length === 0) return void 0;
1689
+ let parsed;
1690
+ try {
1691
+ parsed = JSON.parse(raw);
1692
+ } catch (error) {
1693
+ throw new TypeError(
1694
+ `metadata must be a JSON object: ${error instanceof Error ? error.message : String(error)}`
1695
+ );
1696
+ }
1697
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
1698
+ throw new TypeError("metadata must be a JSON object");
1699
+ }
1700
+ return parsed;
1701
+ }
1702
+ /** Order data belongs to the host; this only performs optional History API sync. */
1703
+ syncResumePath(reference) {
1704
+ const syncUrl = parseBooleanAttribute(
1705
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.syncUrl)
1706
+ );
1707
+ if (syncUrl) {
1708
+ const resumePathPrefix = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.resumePathPrefix) ?? "/checkout";
1709
+ const routeReference = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.routeReference) ?? void 0;
1710
+ enterCheckoutResumePath(reference, {
1711
+ pathPrefix: resumePathPrefix,
1712
+ ...routeReference === void 0 || routeReference.length === 0 ? {} : { routeReference }
1713
+ });
1714
+ }
1715
+ }
1716
+ handleControllerSnapshot(snapshot) {
1717
+ this.latestCheckoutSnapshot = snapshot;
1718
+ if (snapshot.payment_methods !== void 0) {
1719
+ this.swapOptions = snapshot.payment_methods;
1720
+ this.swapOptionsLoaded = true;
1721
+ }
1722
+ const swapInvoice = snapshot.invoices.find(
1723
+ (invoice) => invoice.rail === "swap" && invoice.swap !== void 0
1724
+ );
1725
+ if (swapInvoice !== void 0) {
1726
+ this.startedSwapInvoice = overlaySwapRefundStaging(swapInvoice, this.startedSwapInvoice);
1727
+ }
1728
+ const displayKey = checkoutSnapshotDisplayKey(snapshot);
1729
+ if (this.lastSnapshotDisplayKey === displayKey) return;
1730
+ this.lastSnapshotDisplayKey = displayKey;
1731
+ this.render();
1732
+ }
1733
+ render() {
1734
+ this.captureRefundAddressDraft();
1735
+ const invoiceAttr = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoice);
1736
+ const deferredReady = this.isCreateMode() && this.latestCheckoutSnapshot !== void 0 && (invoiceAttr === null || invoiceAttr === "");
1737
+ if ((invoiceAttr === null || invoiceAttr === "") && !deferredReady) {
1738
+ if (this.isCreateMode()) {
1739
+ const { root: root2, inlineStyles: inlineStyles2 } = this.prepareShadowRoot();
1740
+ if (this.session.createError !== void 0) {
1741
+ root2.innerHTML = renderCheckoutCreateErrorHtml(this.session.createError, {
1742
+ theme: this.resolveTheme(),
1743
+ inlineStyles: inlineStyles2
1744
+ });
1745
+ root2.querySelector('[part="retry"]')?.addEventListener("click", () => this.session.retryCreateCheckout());
1746
+ return;
1747
+ }
1748
+ root2.innerHTML = renderCheckoutCreatingHtml({
1749
+ theme: this.resolveTheme(),
1750
+ inlineStyles: inlineStyles2
1751
+ });
1752
+ return;
1753
+ }
1754
+ this.replaceChildren();
1755
+ return;
1756
+ }
1757
+ const invoiceId = parseElementInvoiceId(
1758
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoiceId)
1759
+ );
1760
+ const invoice = invoiceAttr ?? "";
1761
+ const lightningRequested = !this.isCreateMode() || this.session.lightningRequested || invoice.length > 0;
1762
+ const decodeLinkUrl = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.decodeLinkUrl) ?? void 0;
1763
+ const selectedQuote = this.selectedSwapAsset === null ? void 0 : this.session.swapQuotes[this.selectedSwapAsset];
1764
+ const unavailableSwapQuote = selectedQuote?.available === false ? selectedQuote : void 0;
1765
+ const { root, inlineStyles } = this.prepareShadowRoot();
1766
+ root.innerHTML = renderCheckoutHtml({
1767
+ inlineStyles,
1768
+ ...decodeLinkUrl === void 0 ? {} : { decodeLinkUrl },
1769
+ invoice_id: invoiceId,
1770
+ invoice,
1771
+ rail: parseElementRail(this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.rail)),
1772
+ payment_hash: this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.paymentHash) ?? void 0,
1773
+ amount_msats: readElementAmountMsats(this),
1774
+ fiat_quote: readElementFiatQuote(this),
1775
+ status: parseElementStatus(
1776
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.status)
1777
+ ),
1778
+ expires_at: readElementExpiresAt(this),
1779
+ theme: this.resolveTheme(),
1780
+ payment_wizard: parseBooleanAttribute(
1781
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.paymentWizard)
1782
+ ),
1783
+ lightningRequested: this.session.mintingLightning ? false : lightningRequested,
1784
+ wizard: {
1785
+ selectedMethod: this.selection.selectedMethod,
1786
+ selectedBitcoinRoute: this.selection.selectedBitcoinRoute,
1787
+ swapOptions: this.swapOptions,
1788
+ currenciesLoading: !this.swapOptionsLoaded,
1789
+ selectedSwapNetworks: this.selectedSwapNetworks,
1790
+ selectedPickerKey: this.selectedPickerKey,
1791
+ startingSwapAsset: this.session.startingSwapAsset,
1792
+ selectedSwapAsset: this.selectedSwapAsset,
1793
+ ...this.latestCheckoutSnapshot?.amount_msats === void 0 ? {} : { amountMsats: this.latestCheckoutSnapshot.amount_msats },
1794
+ ...this.latestCheckoutSnapshot?.fiat === void 0 ? {} : { fiat: this.latestCheckoutSnapshot.fiat },
1795
+ ...this.latestCheckoutSnapshot?.reference === void 0 ? {} : { reference: this.latestCheckoutSnapshot.reference },
1796
+ ...this.latestCheckoutSnapshot?.checkout_id === void 0 ? {} : { checkoutId: this.latestCheckoutSnapshot.checkout_id },
1797
+ lightningInvoice: invoice,
1798
+ ...decodeLinkUrl === void 0 ? {} : { decodeLinkUrl },
1799
+ ...this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.paymentHash) === null ? {} : {
1800
+ paymentHash: this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.paymentHash) ?? void 0
1801
+ },
1802
+ swapInvoice: this.currentSwapInvoice(),
1803
+ activeTutorialProviderId: this.activeTutorialProviderId,
1804
+ activeTutorialIndex: this.activeTutorialIndex,
1805
+ activeTutorialCopied: this.activeTutorialCopied,
1806
+ ...this.session.swapStartError === void 0 ? {} : { swapStartError: this.session.swapStartError },
1807
+ ...unavailableSwapQuote === void 0 ? {} : { unavailableSwapQuote },
1808
+ ...this.latestCheckoutSnapshot === void 0 ? {} : { swapLimitContext: this.latestCheckoutSnapshot },
1809
+ ...this.session.wizardError === void 0 ? {} : { wizardError: this.session.wizardError }
1810
+ },
1811
+ ...this.lastCheckoutState === void 0 ? {} : { liveState: this.lastCheckoutState }
1812
+ });
1813
+ const copyButton = root.querySelector(OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS.copy);
1814
+ if (invoice.length > 0) {
1815
+ copyButton?.addEventListener("click", () => {
1816
+ void (this.controller?.copyInvoice() ?? copyInvoice({ invoice, logger: options.logger })).then(() => {
1817
+ showElementCopyFeedback(copyButton);
1818
+ this.dispatchEvent(
1819
+ createCheckoutActionEvent(OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.copy)
1820
+ );
1821
+ }).catch((error) => this.dispatchError(error));
1822
+ });
1823
+ }
1824
+ root.querySelector(OPENRECEIVE_CHECKOUT_ELEMENT_PART_SELECTORS.startOver)?.addEventListener("click", () => {
1825
+ this.dispatchEvent(
1826
+ createCheckoutActionEvent(OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.startOver)
1827
+ );
1828
+ });
1829
+ const qrTarget = root.querySelector(OPENRECEIVE_CHECKOUT_DATA_SELECTORS.qr);
1830
+ if (qrTarget !== null && invoice.length > 0) {
1831
+ void createQrSvg(invoice, {
1832
+ encoder: options.qrEncoder,
1833
+ width: 256
1834
+ }).then((svg) => {
1835
+ if (this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoice) !== invoice) {
1836
+ return;
1837
+ }
1838
+ qrTarget.innerHTML = svg;
1839
+ }).catch((error) => this.dispatchError(error));
1840
+ }
1841
+ this.bindWizard(root, invoice, options.logger);
1842
+ this.renderSwapQrCodes(root);
1843
+ }
1844
+ /**
1845
+ * Shadow root plus the shared compiled stylesheet. `inlineStyles` is true only
1846
+ * where constructable stylesheets are unavailable and the markup must carry a
1847
+ * `<style>` of its own.
1848
+ */
1849
+ prepareShadowRoot() {
1850
+ const root = this.shadowRoot ?? this.attachShadow({ mode: "open" });
1851
+ return { root, inlineStyles: !adoptCheckoutStyles(root) };
1852
+ }
1853
+ captureRefundAddressDraft() {
1854
+ const root = this.shadowRoot;
1855
+ if (root === null) return;
1856
+ const input = root.querySelector(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapRefundAddress);
1857
+ if (!(input instanceof HTMLInputElement) || input.type === "hidden") return;
1858
+ this.refundAddressDraft = input.value;
1859
+ this.refundAddressDraftFocused = root.activeElement === input;
1860
+ this.refundAddressDraftSelectionStart = input.selectionStart;
1861
+ this.refundAddressDraftSelectionEnd = input.selectionEnd;
1862
+ }
1863
+ clearRefundAddressDraft() {
1864
+ this.refundAddressDraft = "";
1865
+ this.refundAddressDraftFocused = false;
1866
+ this.refundAddressDraftSelectionStart = null;
1867
+ this.refundAddressDraftSelectionEnd = null;
1868
+ }
1869
+ startCheckoutController() {
1870
+ const attributeSnapshot = this.currentCheckoutSnapshot();
1871
+ const latest = this.latestCheckoutSnapshot;
1872
+ const snapshot = latest?.active?.rail === "swap" ? latest : attributeSnapshot ?? latest;
1873
+ const prefix = this.resolvePollPrefix(snapshot?.reference);
1874
+ if (snapshot === void 0) {
1875
+ this.stopCheckoutController();
1876
+ return;
1877
+ }
1878
+ const polling = parseBooleanAttribute(
1879
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.polling)
1880
+ ) !== false;
1881
+ const pollIntervalMs = parseOptionalInteger(
1882
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.pollIntervalMs),
1883
+ { label: "poll-interval-ms" }
1884
+ );
1885
+ this.stopCheckoutController();
1886
+ this.controller = createCheckoutController({
1887
+ snapshot,
1888
+ ...prefix === void 0 || !polling ? {} : { prefix },
1889
+ ...pollIntervalMs === void 0 ? {} : { pollIntervalMs },
1890
+ logger: options.logger,
1891
+ onError: (error) => this.dispatchError(error),
1892
+ onState: (nextState) => this.applyCheckoutState(nextState),
1893
+ onSnapshot: (snapshot2) => this.handleControllerSnapshot(snapshot2)
1894
+ });
1895
+ this.controller.start();
1896
+ void this.controller.reloadState().catch((error) => this.dispatchError(error));
1897
+ }
1898
+ stopCheckoutController() {
1899
+ this.controller?.stop();
1900
+ this.controller = void 0;
1901
+ }
1902
+ /**
1903
+ * The mount every server route is derived from, matching React snapshot
1904
+ * mode: the `prefix` attribute, default `/openreceive`. Answers `undefined`
1905
+ * when there is no order to act on — nothing to poll, nothing to swap.
1906
+ */
1907
+ resolvePollPrefix(reference) {
1908
+ const id = reference ?? this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.reference);
1909
+ if (id === null || id === void 0 || id.length === 0) return void 0;
1910
+ return this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.prefix) ?? OPENRECEIVE_DEFAULT_PREFIX2;
1911
+ }
1912
+ currentCheckoutSnapshot() {
1913
+ const reference = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.reference);
1914
+ const invoiceId = parseElementInvoiceId(
1915
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoiceId)
1916
+ );
1917
+ const invoice = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.invoice);
1918
+ if (invoiceId === void 0 || invoice === null) return void 0;
1919
+ const amountMsats = readElementAmountMsats(this);
1920
+ const expiresAt = readElementExpiresAt(this);
1921
+ const fiatQuote = readElementFiatQuote(this);
1922
+ const paymentHash = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.paymentHash);
1923
+ return createCheckoutSnapshotFromInvoice2(
1924
+ {
1925
+ invoice_id: invoiceId,
1926
+ invoice,
1927
+ rail: parseElementRail(this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.rail)),
1928
+ ...paymentHash === null ? {} : { payment_hash: paymentHash },
1929
+ ...amountMsats === void 0 ? {} : { amount_msats: amountMsats },
1930
+ ...fiatQuote === void 0 ? {} : { fiat_quote: fiatQuote },
1931
+ transaction_state: transactionStateFromStatus(
1932
+ parseElementStatus(this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.status)) ?? "pending"
1933
+ ),
1934
+ ...expiresAt === void 0 ? {} : { expires_at: expiresAt }
1935
+ },
1936
+ { ...reference === null ? {} : { reference } }
1937
+ );
1938
+ }
1939
+ applyCheckoutState(state) {
1940
+ const previous = this.lastCheckoutState;
1941
+ this.lastCheckoutState = state;
1942
+ this.session.writeOwnAttributes(() => {
1943
+ this.setAttributeIfChanged(
1944
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.status,
1945
+ deriveStatus2(state)
1946
+ );
1947
+ if (state.expires_at !== void 0) {
1948
+ this.setAttributeIfChanged(
1949
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.expiresAt,
1950
+ String(state.expires_at)
1951
+ );
1952
+ }
1953
+ });
1954
+ if (previous !== void 0 && this.isCountdownOnlyTick(previous, state)) {
1955
+ this.updateCountdownText(state);
1956
+ } else {
1957
+ this.render();
1958
+ }
1959
+ this.dispatchEvent(
1960
+ createCheckoutStateEvent(OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.state, state)
1961
+ );
1962
+ if (state.settled && state.reference !== this.announcedSettledReference) {
1963
+ this.announcedSettledReference = state.reference;
1964
+ this.dispatchEvent(
1965
+ createCheckoutStateEvent(OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.settled, state)
1966
+ );
1967
+ }
1968
+ }
1969
+ isCountdownOnlyTick(previous, next) {
1970
+ return previous.checkout_id === next.checkout_id && previous.invoice_id === next.invoice_id && previous.invoice === next.invoice && previous.rail === next.rail && previous.payment_hash === next.payment_hash && previous.transaction_state === next.transaction_state && previous.workflow_state === next.workflow_state && previous.phase === next.phase && previous.settled === next.settled && previous.terminal === next.terminal && previous.paid === next.paid && previous.expires_at === next.expires_at && previous.swap?.provider_state === next.swap?.provider_state;
1971
+ }
1972
+ /** Patch the countdown text nodes without rebuilding the shadow DOM. */
1973
+ updateCountdownText(state) {
1974
+ const root = this.shadowRoot;
1975
+ if (root === null) return;
1976
+ const model = createCheckoutStatusModel2(state);
1977
+ const countdown = root.querySelector('[part="countdown"] strong');
1978
+ if (countdown !== null && model.countdownLabel !== void 0) {
1979
+ countdown.textContent = model.countdownLabel;
1980
+ }
1981
+ const swapInvoice = this.currentSwapInvoice();
1982
+ if (swapInvoice !== void 0) {
1983
+ const display = createSwapDisplayModel2(swapInvoice, {});
1984
+ const swapCountdown = root.querySelector('[part="swap-countdown"]');
1985
+ if (swapCountdown !== null && display !== void 0) {
1986
+ swapCountdown.textContent = display.countdownLabel;
1987
+ }
1988
+ }
1989
+ }
1990
+ setAttributeIfChanged(name, value) {
1991
+ if (this.getAttribute(name) !== value) this.setAttribute(name, value);
1992
+ }
1993
+ bindWizard(root, invoice, logger) {
1994
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.method).forEach((button) => {
1995
+ button.addEventListener("click", () => {
1996
+ if (button.hasAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.pickerContinue)) return;
1997
+ if (button.hasAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.pickerSelect)) return;
1998
+ const method = parsePaymentMethod(
1999
+ button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.method)
2000
+ );
2001
+ if (method === null) return;
2002
+ this.selectedPickerKey = null;
2003
+ this.selection = updatePaymentWizardSelection(this.selection, {
2004
+ type: "select_method",
2005
+ method
2006
+ });
2007
+ if (method === "bitcoin") {
2008
+ void this.session.ensureLightning();
2009
+ }
2010
+ this.render();
2011
+ });
2012
+ });
2013
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.pickerSelect).forEach((button) => {
2014
+ button.addEventListener("click", () => {
2015
+ if (!(button instanceof HTMLButtonElement) || button.disabled) return;
2016
+ const key = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.pickerSelect);
2017
+ if (key === null || key.length === 0) return;
2018
+ const methodPick = parseMethodPickerKey(key);
2019
+ if (methodPick !== null) {
2020
+ const method = parsePaymentMethod(methodPick.methodId);
2021
+ if (method === null) return;
2022
+ this.selectedPickerKey = null;
2023
+ this.selection = updatePaymentWizardSelection(this.selection, {
2024
+ type: "select_method",
2025
+ method
2026
+ });
2027
+ if (method === "bitcoin") {
2028
+ void this.session.ensureLightning();
2029
+ }
2030
+ this.render();
2031
+ return;
2032
+ }
2033
+ const previousKey = this.selectedPickerKey;
2034
+ this.selectedPickerKey = key;
2035
+ const entries = buildMethodGridEntries2(paymentMethods2, this.swapOptions);
2036
+ const nextGroup = findSwapGridGroup2(entries, key);
2037
+ if (nextGroup !== void 0 && nextGroup.options.length === 1) {
2038
+ const option = nextGroup.options.find((entry) => entry.available !== false) ?? nextGroup.options[0];
2039
+ if (option === void 0 || option.available === false) return;
2040
+ this.selectedPickerKey = null;
2041
+ void this.session.startSwap(option.pay_in_asset);
2042
+ return;
2043
+ }
2044
+ this.selectedSwapNetworks = updateSelectedSwapNetworks({
2045
+ entries,
2046
+ nextKey: key,
2047
+ previousKey,
2048
+ selectedNetworks: this.selectedSwapNetworks
2049
+ });
2050
+ this.render();
2051
+ });
2052
+ });
2053
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.pickerContinue).forEach((button) => {
2054
+ button.addEventListener("click", () => {
2055
+ if (!(button instanceof HTMLButtonElement) || button.disabled) return;
2056
+ const method = parsePaymentMethod(
2057
+ button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.method)
2058
+ );
2059
+ if (method !== null) {
2060
+ this.selection = updatePaymentWizardSelection(this.selection, {
2061
+ type: "select_method",
2062
+ method
2063
+ });
2064
+ this.render();
2065
+ return;
2066
+ }
2067
+ const payInAsset = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapStart);
2068
+ if (payInAsset === null) return;
2069
+ markElementConfirmButtonBusy(button);
2070
+ void this.session.startSwap(payInAsset);
2071
+ });
2072
+ });
2073
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.breadcrumb).forEach((button) => {
2074
+ button.addEventListener("click", () => {
2075
+ const target = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.breadcrumb);
2076
+ if (target === "swap-asset") {
2077
+ this.selectedSwapAsset = null;
2078
+ this.selectedPickerKey = null;
2079
+ this.selectedSwapNetworks = {};
2080
+ this.render();
2081
+ return;
2082
+ }
2083
+ if (target === "method") {
2084
+ this.selection = updatePaymentWizardSelection(this.selection, {
2085
+ type: "change_method"
2086
+ });
2087
+ this.render();
2088
+ return;
2089
+ }
2090
+ if (target === "route") {
2091
+ this.selection = updatePaymentWizardSelection(this.selection, {
2092
+ type: "change_route"
2093
+ });
2094
+ this.render();
2095
+ }
2096
+ });
2097
+ });
2098
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.route).forEach((button) => {
2099
+ button.addEventListener("click", () => {
2100
+ const route = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.route);
2101
+ if (route === null) return;
2102
+ this.selection = updatePaymentWizardSelection(this.selection, {
2103
+ type: "select_route",
2104
+ route
2105
+ });
2106
+ this.render();
2107
+ });
2108
+ });
2109
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapStart).forEach((button) => {
2110
+ button.addEventListener("click", () => {
2111
+ if (button.hasAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.pickerContinue)) return;
2112
+ const payInAsset = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapStart);
2113
+ if (payInAsset === null) return;
2114
+ if (button instanceof HTMLButtonElement) markElementConfirmButtonBusy(button);
2115
+ void this.session.startSwap(payInAsset);
2116
+ });
2117
+ });
2118
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapNetworkValue).forEach((button) => {
2119
+ button.addEventListener("click", () => {
2120
+ if (!(button instanceof HTMLButtonElement) || button.disabled) return;
2121
+ const groupKey = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapNetwork);
2122
+ const payInAsset = button.getAttribute(
2123
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapNetworkValue
2124
+ );
2125
+ if (groupKey === null || groupKey.length === 0 || payInAsset === null) return;
2126
+ const details = button.closest("details");
2127
+ if (details instanceof HTMLDetailsElement) details.open = false;
2128
+ this.selectedSwapNetworks = {
2129
+ ...this.selectedSwapNetworks,
2130
+ [groupKey]: payInAsset
2131
+ };
2132
+ this.render();
2133
+ });
2134
+ });
2135
+ root.querySelector(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapBack)?.addEventListener("click", () => {
2136
+ const current = this.currentSwapInvoice();
2137
+ this.dismissedSwapInvoiceId = current?.invoice_id ?? null;
2138
+ this.selectedSwapAsset = null;
2139
+ this.selectedPickerKey = null;
2140
+ this.selectedSwapNetworks = {};
2141
+ this.clearRefundAddressDraft();
2142
+ void this.session.ensureLightning();
2143
+ this.render();
2144
+ });
2145
+ wireSwapSelectAllInputs(root);
2146
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapCopy).forEach((button) => {
2147
+ button.addEventListener("click", () => {
2148
+ const value = button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapCopy);
2149
+ if (value === null) return;
2150
+ void globalThis.navigator?.clipboard?.writeText(value).then(() => showElementCopyFeedback(button)).catch((error) => this.dispatchError(error));
2151
+ });
2152
+ });
2153
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapRefundForm).forEach((form) => {
2154
+ const input = form.querySelector(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapRefundAddress);
2155
+ const errorEl = form.querySelector(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapRefundError);
2156
+ const payInAsset = form.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapRefundPayInAsset) ?? "";
2157
+ const networkLabel = form.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapRefundNetworkLabel) ?? "refund";
2158
+ const setRefundAddressError = (message) => {
2159
+ if (input instanceof HTMLInputElement) {
2160
+ input.className = message === void 0 ? orClasses7.swapRefundInput : orClasses7.swapRefundInputInvalid;
2161
+ if (message === void 0) input.removeAttribute("aria-invalid");
2162
+ else input.setAttribute("aria-invalid", "true");
2163
+ }
2164
+ if (errorEl instanceof HTMLElement) {
2165
+ if (message === void 0) {
2166
+ errorEl.textContent = "";
2167
+ errorEl.hidden = true;
2168
+ } else {
2169
+ errorEl.textContent = message;
2170
+ errorEl.hidden = false;
2171
+ }
2172
+ }
2173
+ };
2174
+ const validateRefundAddress = (address, showEmpty) => {
2175
+ if (address.length === 0 && !showEmpty) return void 0;
2176
+ return getSwapRefundFormError(payInAsset, address, networkLabel);
2177
+ };
2178
+ if (input instanceof HTMLInputElement && input.type !== "hidden") {
2179
+ if (this.refundAddressDraft.length > 0) {
2180
+ input.value = this.refundAddressDraft;
2181
+ }
2182
+ input.addEventListener("input", () => {
2183
+ this.refundAddressDraft = input.value;
2184
+ const address = input.value.trim();
2185
+ if (address.length === 0) {
2186
+ setRefundAddressError(void 0);
2187
+ return;
2188
+ }
2189
+ setRefundAddressError(validateRefundAddress(address, false));
2190
+ });
2191
+ input.addEventListener("blur", () => {
2192
+ const address = input.value.trim();
2193
+ if (address.length === 0) return;
2194
+ setRefundAddressError(validateRefundAddress(address, false));
2195
+ });
2196
+ if (this.refundAddressDraftFocused) {
2197
+ input.focus();
2198
+ const start = this.refundAddressDraftSelectionStart ?? input.value.length;
2199
+ const end = this.refundAddressDraftSelectionEnd ?? input.value.length;
2200
+ input.setSelectionRange(start, end);
2201
+ }
2202
+ const restoredError = validateRefundAddress(input.value.trim(), false);
2203
+ if (restoredError !== void 0) setRefundAddressError(restoredError);
2204
+ }
2205
+ form.addEventListener("submit", (event) => {
2206
+ event.preventDefault();
2207
+ const attemptId = form.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapRefundForm);
2208
+ const refundAllowed = form.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapRefundAllowed) === "true";
2209
+ const confirm = form.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapRefundConfirm) === "true";
2210
+ const refundAddress = input instanceof HTMLInputElement ? input.value.trim() : "";
2211
+ if (attemptId === null || !refundAllowed) return;
2212
+ const error = validateRefundAddress(refundAddress, true);
2213
+ if (error !== void 0) {
2214
+ setRefundAddressError(error);
2215
+ return;
2216
+ }
2217
+ setRefundAddressError(void 0);
2218
+ void this.refundSwap(attemptId, refundAddress, confirm);
2219
+ });
2220
+ });
2221
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.providerTutorial).forEach((button) => {
2222
+ button.addEventListener("click", () => {
2223
+ const providerId = button.getAttribute(
2224
+ OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.providerTutorial
2225
+ );
2226
+ if (providerId === null) return;
2227
+ if (providerId === "") {
2228
+ this.activeTutorialProviderId = null;
2229
+ this.activeTutorialIndex = 0;
2230
+ this.activeTutorialCopied = false;
2231
+ this.render();
2232
+ return;
2233
+ }
2234
+ const index = Number(
2235
+ button.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.providerTutorialIndex) ?? "0"
2236
+ );
2237
+ if (this.activeTutorialProviderId !== providerId) {
2238
+ this.activeTutorialCopied = false;
2239
+ }
2240
+ this.activeTutorialProviderId = providerId;
2241
+ this.activeTutorialIndex = Number.isSafeInteger(index) && index >= 0 ? index : 0;
2242
+ this.render();
2243
+ });
2244
+ });
2245
+ root.querySelector('[part="tutorial-copy"]')?.addEventListener("click", () => {
2246
+ void copyInvoice({ invoice, logger }).then(() => {
2247
+ this.activeTutorialCopied = true;
2248
+ if (this.activeTutorialProviderId !== null) {
2249
+ this.dispatchEvent(createCheckoutProviderCopyEvent(this.activeTutorialProviderId));
2250
+ }
2251
+ this.dispatchEvent(createCheckoutActionEvent(OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS.copy));
2252
+ this.render();
2253
+ }).catch((error) => this.dispatchError(error));
2254
+ });
2255
+ const tutorial = root.querySelector('[part="tutorial"]');
2256
+ tutorial?.addEventListener("click", (event) => {
2257
+ if (event.target !== event.currentTarget) return;
2258
+ this.activeTutorialProviderId = null;
2259
+ this.activeTutorialIndex = 0;
2260
+ this.activeTutorialCopied = false;
2261
+ this.render();
2262
+ });
2263
+ tutorial?.addEventListener("keydown", (event) => {
2264
+ if (!(event instanceof KeyboardEvent)) return;
2265
+ if (event.key !== "Escape" || this.activeTutorialProviderId === null) return;
2266
+ this.activeTutorialProviderId = null;
2267
+ this.activeTutorialIndex = 0;
2268
+ this.activeTutorialCopied = false;
2269
+ this.render();
2270
+ });
2271
+ if (tutorial instanceof HTMLElement && this.activeTutorialProviderId !== null && this.focusedTutorialProviderId !== this.activeTutorialProviderId) {
2272
+ this.focusedTutorialProviderId = this.activeTutorialProviderId;
2273
+ tutorial.focus();
2274
+ }
2275
+ if (this.activeTutorialProviderId === null) {
2276
+ this.focusedTutorialProviderId = null;
2277
+ }
2278
+ }
2279
+ async refundSwap(attemptId, refundAddress, confirm) {
2280
+ const reference = this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.reference);
2281
+ const prefix = this.resolvePollPrefix(reference ?? void 0);
2282
+ if (prefix === void 0) return;
2283
+ try {
2284
+ this.startedSwapInvoice = await requestSwapRefund({
2285
+ fetch: globalThis.fetch,
2286
+ prefix,
2287
+ ...reference === null ? {} : { reference },
2288
+ invoices: [this.startedSwapInvoice, ...this.latestCheckoutSnapshot?.invoices ?? []],
2289
+ attemptId,
2290
+ refundAddress,
2291
+ confirm,
2292
+ logger: options.logger
2293
+ });
2294
+ this.dismissedSwapInvoiceId = null;
2295
+ this.render();
2296
+ } catch (error) {
2297
+ this.dispatchError(error);
2298
+ }
2299
+ }
2300
+ currentSwapInvoice() {
2301
+ const fromSnapshot = this.latestCheckoutSnapshot?.invoices.find(
2302
+ (invoice) => invoice.rail === "swap" && invoice.swap !== void 0 && invoice.invoice_id !== this.dismissedSwapInvoiceId
2303
+ );
2304
+ if (this.startedSwapInvoice === void 0 || this.startedSwapInvoice.invoice_id === this.dismissedSwapInvoiceId) {
2305
+ return fromSnapshot;
2306
+ }
2307
+ const matched = this.latestCheckoutSnapshot?.invoices.find(
2308
+ (invoice) => invoice.invoice_id === this.startedSwapInvoice?.invoice_id
2309
+ ) ?? this.startedSwapInvoice;
2310
+ return overlaySwapRefundStaging(matched, this.startedSwapInvoice);
2311
+ }
2312
+ renderSwapQrCodes(root) {
2313
+ root.querySelectorAll(OPENRECEIVE_PAYMENT_WIZARD_SELECTORS3.swapQr).forEach((target) => {
2314
+ const payload = target.getAttribute(OPENRECEIVE_PAYMENT_WIZARD_ATTRIBUTES7.swapQr);
2315
+ if (payload === null) return;
2316
+ void createQrPayloadSvg(payload, {
2317
+ encoder: options.qrEncoder,
2318
+ width: 220
2319
+ }).then((svg) => {
2320
+ target.innerHTML = svg;
2321
+ }).catch((error) => this.dispatchError(error));
2322
+ });
2323
+ }
2324
+ currentThemeOption() {
2325
+ const theme = parseResolvedTheme(
2326
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.theme)
2327
+ );
2328
+ return theme === void 0 ? {} : { theme };
2329
+ }
2330
+ /** Explicit `theme` attr wins; otherwise inherit nearest ancestor `[data-theme]`. */
2331
+ resolveTheme() {
2332
+ const attr = parseResolvedTheme(
2333
+ this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.theme)
2334
+ );
2335
+ if (attr !== void 0) return attr;
2336
+ const ancestor = this.closest("[data-theme]");
2337
+ const inherited = parseResolvedTheme(ancestor?.getAttribute("data-theme"));
2338
+ if (inherited !== void 0) return inherited;
2339
+ return "light";
2340
+ }
2341
+ syncThemeAncestorObserver() {
2342
+ const hasOwnTheme = parseResolvedTheme(this.getAttribute(OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES3.theme)) !== void 0;
2343
+ if (hasOwnTheme) {
2344
+ this.stopThemeAncestorObserver();
2345
+ return;
2346
+ }
2347
+ const ancestor = this.closest("[data-theme]");
2348
+ if (ancestor === this.observedThemeAncestor && this.themeAncestorObserver !== void 0) {
2349
+ return;
2350
+ }
2351
+ this.stopThemeAncestorObserver();
2352
+ if (ancestor === null) return;
2353
+ const MutationObserverCtor = globalThis.MutationObserver;
2354
+ if (MutationObserverCtor === void 0) return;
2355
+ this.observedThemeAncestor = ancestor;
2356
+ this.themeAncestorObserver = new MutationObserverCtor(() => {
2357
+ this.render();
2358
+ this.syncThemeAncestorObserver();
2359
+ });
2360
+ this.themeAncestorObserver.observe(ancestor, {
2361
+ attributes: true,
2362
+ attributeFilter: ["data-theme"]
2363
+ });
2364
+ }
2365
+ stopThemeAncestorObserver() {
2366
+ this.themeAncestorObserver?.disconnect();
2367
+ this.themeAncestorObserver = void 0;
2368
+ this.observedThemeAncestor = null;
2369
+ }
2370
+ dispatchError(error) {
2371
+ this.dispatchEvent(createCheckoutErrorEvent(error));
2372
+ }
2373
+ }
2374
+ class ThemeToggleElement extends HTMLElementCtor {
2375
+ observer;
2376
+ observedTarget = null;
2377
+ static get observedAttributes() {
2378
+ return [
2379
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.rootSelector,
2380
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.checkoutSelector,
2381
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.defaultTheme,
2382
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.storageKey
2383
+ ];
2384
+ }
2385
+ connectedCallback() {
2386
+ this.render();
2387
+ this.startObserver();
2388
+ }
2389
+ attributeChangedCallback() {
2390
+ if (!this.isConnected) return;
2391
+ this.render();
2392
+ this.startObserver();
2393
+ }
2394
+ disconnectedCallback() {
2395
+ this.stopObserver();
2396
+ }
2397
+ render() {
2398
+ const root = this.shadowRoot ?? this.attachShadow({ mode: "open" });
2399
+ const inlineStyles = !adoptCheckoutStyles(root);
2400
+ const theme = this.syncTheme();
2401
+ root.innerHTML = renderThemeToggleHtml(theme.toggleLabel, { inlineStyles });
2402
+ root.querySelector(OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS.button)?.addEventListener("click", () => {
2403
+ const nextTheme = toggleStoredThemeControls(this.themeTargets(), this.themeOptions());
2404
+ this.dispatchEvent(createThemeChangeEvent(nextTheme));
2405
+ this.render();
2406
+ });
2407
+ }
2408
+ syncTheme() {
2409
+ return syncStoredThemeControls(this.themeTargets(), this.themeOptions());
2410
+ }
2411
+ /**
2412
+ * Watch only what can invalidate the toggle: the theme attributes it mirrors,
2413
+ * and children arriving under the same wrapper (a checkout element mounted
2414
+ * after the toggle). Observing the whole page body with `subtree` ran a
2415
+ * querySelector sweep on every unrelated DOM mutation on the host page.
2416
+ */
2417
+ startObserver() {
2418
+ const MutationObserverCtor = globalThis.MutationObserver;
2419
+ if (MutationObserverCtor === void 0) return;
2420
+ const target = this.themeTargets().root ?? this.ownerDocument.documentElement;
2421
+ if (target === null || target === void 0) return;
2422
+ if (this.observer !== void 0 && this.observedTarget === target) return;
2423
+ this.stopObserver();
2424
+ this.observedTarget = target;
2425
+ this.observer = new MutationObserverCtor(() => {
2426
+ this.syncTheme();
2427
+ });
2428
+ this.observer.observe(target, {
2429
+ attributes: true,
2430
+ attributeFilter: ["data-theme", "data-openreceive-theme"],
2431
+ childList: true
2432
+ });
2433
+ }
2434
+ stopObserver() {
2435
+ this.observer?.disconnect();
2436
+ this.observer = void 0;
2437
+ this.observedTarget = null;
2438
+ }
2439
+ themeTargets() {
2440
+ const rootSelector = this.getAttribute(
2441
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.rootSelector
2442
+ );
2443
+ const checkoutSelector = this.getAttribute(
2444
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.checkoutSelector
2445
+ );
2446
+ const button = this.shadowRoot?.querySelector(OPENRECEIVE_THEME_TOGGLE_ELEMENT_PART_SELECTORS.button) ?? null;
2447
+ const defaultRoot = this.closest("[data-openreceive-theme]");
2448
+ return {
2449
+ root: rootSelector === null ? defaultRoot ?? void 0 : this.ownerDocument.querySelector(rootSelector) ?? void 0,
2450
+ checkout: checkoutSelector === null ? defaultRoot?.querySelector(tagName) ?? void 0 : this.ownerDocument.querySelector(checkoutSelector) ?? void 0,
2451
+ toggle: button
2452
+ };
2453
+ }
2454
+ themeOptions() {
2455
+ const defaultTheme = parseThemePreference(
2456
+ this.getAttribute(OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.defaultTheme)
2457
+ );
2458
+ return {
2459
+ ...defaultTheme === void 0 ? {} : { defaultTheme },
2460
+ ...this.getAttribute(OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.storageKey) === null ? {} : {
2461
+ storageKey: this.getAttribute(OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES.storageKey) ?? void 0
2462
+ }
2463
+ };
2464
+ }
2465
+ }
2466
+ if (registry.get(tagName) === void 0) {
2467
+ registry.define(tagName, CheckoutElement);
2468
+ }
2469
+ if (registry.get(themeToggleTagName) === void 0) {
2470
+ registry.define(themeToggleTagName, ThemeToggleElement);
2471
+ }
2472
+ }
2473
+
2474
+ export {
2475
+ renderTransactionDetailsHtml,
2476
+ createTransactionDetailsElement,
2477
+ renderCheckoutHtml,
2478
+ renderCheckoutCreateErrorHtml,
2479
+ renderThemeToggleHtml,
2480
+ defineElements,
2481
+ createThemeToggleElement,
2482
+ OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES4 as OPENRECEIVE_CHECKOUT_ELEMENT_ATTRIBUTES,
2483
+ OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS2 as OPENRECEIVE_CHECKOUT_ELEMENT_EVENTS,
2484
+ OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME2 as OPENRECEIVE_CHECKOUT_ELEMENT_TAG_NAME,
2485
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES2 as OPENRECEIVE_THEME_TOGGLE_ELEMENT_ATTRIBUTES,
2486
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_EVENTS,
2487
+ OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME2 as OPENRECEIVE_THEME_TOGGLE_ELEMENT_TAG_NAME
2488
+ };