@eos3/connect 0.1.13 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui.js ADDED
@@ -0,0 +1,740 @@
1
+ import { createEosConnect } from './index.js';
2
+ const EOS_CONNECT_DEFAULT_STYLES = `
3
+ :root {
4
+ --eos-connect-accent: #2f80ed;
5
+ --eos-connect-accent-strong: #1f6fd1;
6
+ --eos-connect-surface: #ffffff;
7
+ --eos-connect-surface-soft: #f5f7fb;
8
+ --eos-connect-border: #e5e7eb;
9
+ --eos-connect-text: #111827;
10
+ --eos-connect-muted: #6b7280;
11
+ --eos-connect-shadow: 0 18px 55px rgba(15, 23, 42, 0.18);
12
+ }
13
+ eos-connect-button,
14
+ eos-connect,
15
+ eos-connect-modal {
16
+ box-sizing: border-box;
17
+ color: var(--eos-connect-text);
18
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
19
+ font-size: 16px;
20
+ line-height: 1.4;
21
+ -webkit-text-size-adjust: 100%;
22
+ text-size-adjust: 100%;
23
+ }
24
+ eos-connect *,
25
+ eos-connect *::before,
26
+ eos-connect *::after,
27
+ eos-connect-button *,
28
+ eos-connect-button *::before,
29
+ eos-connect-button *::after,
30
+ eos-connect-modal *,
31
+ eos-connect-modal *::before,
32
+ eos-connect-modal *::after {
33
+ box-sizing: border-box;
34
+ }
35
+ eos-connect-button[hidden],
36
+ eos-connect[hidden],
37
+ eos-connect-modal[hidden] {
38
+ display: none !important;
39
+ }
40
+ eos-connect,
41
+ eos-connect-modal {
42
+ position: fixed;
43
+ inset: 0;
44
+ z-index: 2147483000;
45
+ display: grid;
46
+ align-items: end;
47
+ justify-items: center;
48
+ min-width: 0;
49
+ padding: 12px 12px max(12px, env(safe-area-inset-bottom));
50
+ overflow: hidden;
51
+ }
52
+ eos-connect-button {
53
+ display: inline-block;
54
+ }
55
+ .eos-connect-button {
56
+ appearance: none;
57
+ -webkit-appearance: none;
58
+ min-height: 44px;
59
+ border: 0;
60
+ border-radius: 8px;
61
+ background: var(--eos-connect-accent);
62
+ color: #ffffff;
63
+ cursor: pointer;
64
+ font-family: inherit;
65
+ font-size: 15px;
66
+ line-height: 1.2;
67
+ font-weight: 700;
68
+ padding: 0 18px;
69
+ }
70
+ .eos-connect-sdk-backdrop {
71
+ appearance: none;
72
+ -webkit-appearance: none;
73
+ position: absolute;
74
+ inset: 0;
75
+ border: 0;
76
+ padding: 0;
77
+ background: rgba(15, 23, 42, 0.36);
78
+ cursor: pointer;
79
+ }
80
+ .eos-connect-sdk-sheet {
81
+ position: relative;
82
+ width: min(100%, 420px);
83
+ max-height: min(640px, calc(100dvh - 24px - env(safe-area-inset-bottom)));
84
+ border: 1px solid var(--eos-connect-border);
85
+ border-radius: 8px;
86
+ background: var(--eos-connect-surface);
87
+ box-shadow: var(--eos-connect-shadow);
88
+ padding: 16px;
89
+ overflow: auto;
90
+ -webkit-overflow-scrolling: touch;
91
+ }
92
+ .eos-connect-sdk-sheet--quick {
93
+ width: min(100%, 454px) !important;
94
+ border: 0 !important;
95
+ border-radius: 28px !important;
96
+ padding: 50px 24px 34px !important;
97
+ overflow: visible !important;
98
+ }
99
+ .eos-connect-sdk-close {
100
+ appearance: none;
101
+ -webkit-appearance: none;
102
+ position: absolute;
103
+ top: 24px !important;
104
+ right: 24px !important;
105
+ display: grid;
106
+ width: 48px !important;
107
+ height: 48px !important;
108
+ place-items: center;
109
+ border: 0 !important;
110
+ border-radius: 999px !important;
111
+ background: var(--eos-connect-surface-soft) !important;
112
+ color: #6b7280 !important;
113
+ cursor: pointer;
114
+ font-family: inherit !important;
115
+ font-size: 34px !important;
116
+ line-height: 1 !important;
117
+ font-weight: 300 !important;
118
+ padding: 0 !important;
119
+ }
120
+ .eos-connect-sdk-summary {
121
+ margin-bottom: 16px;
122
+ }
123
+ .eos-connect-sdk-summary--quick {
124
+ margin: 122px 0 38px !important;
125
+ text-align: center !important;
126
+ }
127
+ .eos-connect-sdk-summary h2 {
128
+ margin: 0 0 6px;
129
+ font-size: 22px;
130
+ line-height: 1.2;
131
+ }
132
+ .eos-connect-sdk-summary--quick h2 {
133
+ margin: 0 0 14px !important;
134
+ font-size: 28px !important;
135
+ line-height: 1.18 !important;
136
+ font-weight: 800 !important;
137
+ }
138
+ .eos-connect-sdk-summary p {
139
+ margin: 0;
140
+ color: var(--eos-connect-muted);
141
+ font-size: 15px;
142
+ line-height: 1.45;
143
+ }
144
+ .eos-connect-sdk-summary--quick p {
145
+ margin: 0 !important;
146
+ font-size: 17px !important;
147
+ line-height: 1.55 !important;
148
+ }
149
+ .eos-connect-sdk-summary--quick strong {
150
+ color: var(--eos-connect-text) !important;
151
+ }
152
+ .eos-connect-sdk-primary {
153
+ appearance: none;
154
+ -webkit-appearance: none;
155
+ display: flex;
156
+ width: 100%;
157
+ min-height: 58px;
158
+ align-items: center;
159
+ justify-content: space-between;
160
+ gap: 12px;
161
+ border: 0;
162
+ border-radius: 8px;
163
+ background: var(--eos-connect-accent);
164
+ color: #ffffff;
165
+ cursor: pointer;
166
+ font-family: inherit;
167
+ font-size: 15px;
168
+ line-height: 1.25;
169
+ font-weight: 700;
170
+ padding: 0 16px;
171
+ text-align: left;
172
+ }
173
+ .eos-connect-sdk-primary--quick {
174
+ display: grid !important;
175
+ min-height: 66px !important;
176
+ grid-template-columns: 54px minmax(0, 1fr) 54px !important;
177
+ align-items: center !important;
178
+ border-radius: 14px !important;
179
+ padding: 0 14px !important;
180
+ box-shadow: 0 14px 34px rgba(47, 128, 237, 0.26) !important;
181
+ font-family: inherit !important;
182
+ font-size: 18px !important;
183
+ line-height: 1.2 !important;
184
+ text-align: center !important;
185
+ }
186
+ .eos-connect-sdk-primary--quick[aria-busy="true"],
187
+ .eos-connect-sdk-primary--quick[disabled] {
188
+ opacity: 1 !important;
189
+ }
190
+ .eos-connect-sdk-primary--success {
191
+ background: #10b981 !important;
192
+ box-shadow: 0 14px 34px rgba(16, 185, 129, 0.22) !important;
193
+ }
194
+ .eos-connect-sdk-key-icon,
195
+ .eos-connect-sdk-send-icon,
196
+ .eos-connect-sdk-spinner-icon,
197
+ .eos-connect-sdk-success-icon,
198
+ .eos-connect-sdk-empty-icon {
199
+ display: grid !important;
200
+ width: 40px !important;
201
+ height: 40px !important;
202
+ place-items: center !important;
203
+ }
204
+ .eos-connect-sdk-key-icon {
205
+ border-radius: 11px !important;
206
+ background: #ffffff !important;
207
+ color: var(--eos-connect-accent) !important;
208
+ }
209
+ .eos-connect-sdk-spinner-icon,
210
+ .eos-connect-sdk-success-icon,
211
+ .eos-connect-sdk-empty-icon {
212
+ border-radius: 11px !important;
213
+ background: rgba(255, 255, 255, 0.18) !important;
214
+ color: #ffffff !important;
215
+ }
216
+ .eos-connect-sdk-spinner {
217
+ display: block !important;
218
+ width: 24px !important;
219
+ height: 24px !important;
220
+ border: 3px solid rgba(255, 255, 255, 0.42) !important;
221
+ border-top-color: #ffffff !important;
222
+ border-radius: 999px !important;
223
+ animation: eos-connect-sdk-spin 760ms linear infinite !important;
224
+ }
225
+ .eos-connect-sdk-success-icon svg {
226
+ width: 26px !important;
227
+ height: 26px !important;
228
+ fill: none !important;
229
+ stroke: currentColor !important;
230
+ stroke-width: 2.4 !important;
231
+ stroke-linecap: round !important;
232
+ stroke-linejoin: round !important;
233
+ }
234
+ .eos-connect-sdk-send-icon {
235
+ justify-self: end !important;
236
+ color: rgba(255, 255, 255, 0.86) !important;
237
+ }
238
+ .eos-connect-sdk-key-icon svg,
239
+ .eos-connect-sdk-send-icon svg {
240
+ width: 24px;
241
+ height: 24px;
242
+ fill: none;
243
+ stroke: currentColor;
244
+ stroke-width: 2;
245
+ stroke-linecap: round;
246
+ stroke-linejoin: round;
247
+ }
248
+ @keyframes eos-connect-sdk-spin {
249
+ to {
250
+ transform: rotate(360deg);
251
+ }
252
+ }
253
+ .eos-connect-sdk-primary span {
254
+ min-width: 0;
255
+ overflow-wrap: anywhere;
256
+ }
257
+ .eos-connect-sdk-primary[aria-disabled="true"] {
258
+ cursor: not-allowed;
259
+ opacity: 0.58;
260
+ }
261
+ @media (max-width: 480px) {
262
+ eos-connect,
263
+ eos-connect-modal {
264
+ padding: 8px 8px max(8px, env(safe-area-inset-bottom));
265
+ }
266
+ .eos-connect-sdk-sheet {
267
+ width: 100%;
268
+ max-height: min(620px, calc(100dvh - 16px - env(safe-area-inset-bottom)));
269
+ border-radius: 8px 8px 0 0;
270
+ padding: 14px;
271
+ }
272
+ .eos-connect-sdk-sheet--quick {
273
+ border-radius: 28px 28px 0 0 !important;
274
+ padding: 46px 24px 34px !important;
275
+ }
276
+ .eos-connect-sdk-close {
277
+ top: 22px !important;
278
+ right: 24px !important;
279
+ width: 48px !important;
280
+ height: 48px !important;
281
+ }
282
+ .eos-connect-sdk-summary {
283
+ margin-bottom: 14px;
284
+ }
285
+ .eos-connect-sdk-summary--quick {
286
+ margin: 118px 0 36px !important;
287
+ }
288
+ .eos-connect-sdk-summary h2 {
289
+ font-size: 20px;
290
+ }
291
+ .eos-connect-sdk-summary--quick h2 {
292
+ font-size: 28px !important;
293
+ }
294
+ .eos-connect-sdk-summary p {
295
+ font-size: 14px;
296
+ }
297
+ .eos-connect-sdk-summary--quick p {
298
+ font-size: 17px !important;
299
+ }
300
+ .eos-connect-sdk-primary {
301
+ min-height: 52px;
302
+ padding: 0 14px;
303
+ }
304
+ .eos-connect-sdk-primary--quick {
305
+ min-height: 66px !important;
306
+ grid-template-columns: 54px minmax(0, 1fr) 54px !important;
307
+ font-size: 18px !important;
308
+ }
309
+ }
310
+ `;
311
+ export function installEosConnectStyles(documentRef = globalThis.document) {
312
+ if (!documentRef || documentRef.querySelector('[data-eos-connect-ui-style]')) {
313
+ return;
314
+ }
315
+ const style = documentRef.createElement('style');
316
+ style.setAttribute('data-eos-connect-ui-style', '');
317
+ style.textContent = EOS_CONNECT_DEFAULT_STYLES;
318
+ documentRef.head.append(style);
319
+ }
320
+ function escapeHtml(value) {
321
+ return String(value ?? '')
322
+ .replace(/&/g, '&')
323
+ .replace(/</g, '&lt;')
324
+ .replace(/>/g, '&gt;')
325
+ .replace(/"/g, '&quot;');
326
+ }
327
+ const EOS_CONNECT_UI_MESSAGES = {
328
+ en: {
329
+ enableQuickPayment: 'Enable quick payment',
330
+ quickPaymentEnabled: 'Quick payment enabled',
331
+ quickPaymentChecking: 'Checking binding status...',
332
+ quickPaymentCheckingDescription: 'Finish binding in the opened page\nThis window will update automatically',
333
+ quickPaymentSuccess: 'Enabled successfully',
334
+ quickPaymentSuccessDescription: 'Quick payment is enabled\nYou can return to continue payment',
335
+ quickPaymentSetupDescription: 'Complete one binding\nEligible payments can be confirmed quickly',
336
+ localKeyMissingDescription: 'Complete one binding\nEligible payments can be confirmed quickly',
337
+ closeEosConnect: 'Close EOS Connect'
338
+ },
339
+ 'zh-CN': {
340
+ enableQuickPayment: '开启快捷支付',
341
+ quickPaymentEnabled: '快捷支付已开启',
342
+ quickPaymentChecking: '正在检测绑定状态...',
343
+ quickPaymentCheckingDescription: '请在打开的页面完成认证\n返回后会自动继续检测',
344
+ quickPaymentSuccess: '开启成功',
345
+ quickPaymentSuccessDescription: '快捷支付已开启\n可以返回继续支付',
346
+ quickPaymentSetupDescription: '完成一次绑定\n符合额度的支付可快速确认',
347
+ localKeyMissingDescription: '完成一次绑定\n符合额度的支付可快速确认',
348
+ closeEosConnect: '关闭 EOS Connect'
349
+ }
350
+ };
351
+ const EOS_CONNECT_QUICK_PAY_REFRESH_INTERVAL_MS = 1500;
352
+ function normalizeEosConnectUiLocale(locale) {
353
+ return String(locale ?? '').toLowerCase().startsWith('zh') ? 'zh-CN' : 'en';
354
+ }
355
+ function browserLanguage() {
356
+ const maybeNavigator = globalThis;
357
+ return maybeNavigator.navigator?.language;
358
+ }
359
+ function telegramLanguageCode(app) {
360
+ const maybeApp = app;
361
+ return maybeApp?.initDataUnsafe?.user?.language_code;
362
+ }
363
+ function resolveEosConnectUiLocale(options = {}) {
364
+ return normalizeEosConnectUiLocale(options.locale ?? telegramLanguageCode(options.telegramWebApp) ?? browserLanguage());
365
+ }
366
+ function createTranslator(options = {}) {
367
+ const locale = resolveEosConnectUiLocale(options);
368
+ return (key, values = {}) => {
369
+ let text = options.messages?.[key] ??
370
+ (key === 'quickPaymentSetupDescription' ? options.messages?.localKeyMissingDescription : undefined) ??
371
+ EOS_CONNECT_UI_MESSAGES[locale][key];
372
+ for (const [name, value] of Object.entries(values)) {
373
+ text = text.replaceAll(`{${name}}`, value);
374
+ }
375
+ return text;
376
+ };
377
+ }
378
+ function formatMultilineText(value) {
379
+ return value
380
+ .split('\n')
381
+ .map((line) => escapeHtml(line))
382
+ .join('<br>');
383
+ }
384
+ export function renderEosConnectButton(client, options = {}) {
385
+ const snapshot = client.getSnapshot();
386
+ const t = createTranslator(options);
387
+ const label = snapshot.status === 'connected' && snapshot.canUse
388
+ ? t('quickPaymentEnabled')
389
+ : t('enableQuickPayment');
390
+ return `<button class="eos-connect-button" type="button">${escapeHtml(label)}</button>`;
391
+ }
392
+ function renderQuickPaymentSheet(provider, t, flowState = 'idle') {
393
+ const isChecking = flowState === 'checking';
394
+ const isSuccess = flowState === 'success';
395
+ const disabled = isChecking || isSuccess || provider?.state !== 'available';
396
+ const title = isSuccess ? t('quickPaymentSuccess') : t('enableQuickPayment');
397
+ const description = isSuccess
398
+ ? t('quickPaymentSuccessDescription')
399
+ : isChecking
400
+ ? t('quickPaymentCheckingDescription')
401
+ : t('quickPaymentSetupDescription');
402
+ const label = isSuccess
403
+ ? t('quickPaymentEnabled')
404
+ : isChecking
405
+ ? t('quickPaymentChecking')
406
+ : t('enableQuickPayment');
407
+ const leadingIcon = isSuccess
408
+ ? `<span class="eos-connect-sdk-success-icon" aria-hidden="true">
409
+ <svg viewBox="0 0 24 24" focusable="false">
410
+ <path d="m5 12.4 4.2 4.2L19 6.8" />
411
+ </svg>
412
+ </span>`
413
+ : isChecking
414
+ ? `<span class="eos-connect-sdk-spinner-icon" aria-hidden="true">
415
+ <span class="eos-connect-sdk-spinner"></span>
416
+ </span>`
417
+ : `<span class="eos-connect-sdk-key-icon" aria-hidden="true">
418
+ <svg viewBox="0 0 24 24" focusable="false">
419
+ <path d="M7.5 14.5a4 4 0 1 1 3.6-2.26L20 3.35 20.65 4 18 6.65 20 8.65 18.65 10 16.65 8 15 9.65 17 11.65 15.65 13 13.65 11 11.76 12.9A4 4 0 0 1 7.5 14.5Z" />
420
+ <circle cx="7.5" cy="10.5" r="1.45" />
421
+ </svg>
422
+ </span>`;
423
+ const trailingIcon = isChecking || isSuccess
424
+ ? '<span class="eos-connect-sdk-empty-icon" aria-hidden="true"></span>'
425
+ : `<span class="eos-connect-sdk-send-icon" aria-hidden="true">
426
+ <svg viewBox="0 0 24 24" focusable="false">
427
+ <path d="M20.9 3.35 3.75 10.72c-.85.36-.78 1.59.1 1.85l6.1 1.79 1.82 6.05c.27.88 1.5.94 1.86.09l7.28-17.15Z" />
428
+ <path d="m10.28 14.02 4.76-4.76" />
429
+ </svg>
430
+ </span>`;
431
+ return `
432
+ <button type="button" class="eos-connect-sdk-backdrop" data-eos-connect-close aria-label="${escapeHtml(t('closeEosConnect'))}"></button>
433
+ <section class="eos-connect-sdk-sheet eos-connect-sdk-sheet--quick" role="dialog" aria-modal="true">
434
+ <button type="button" class="eos-connect-sdk-close" data-eos-connect-close aria-label="${escapeHtml(t('closeEosConnect'))}">×</button>
435
+ <div class="eos-connect-sdk-summary eos-connect-sdk-summary--quick">
436
+ <h2>${escapeHtml(title)}</h2>
437
+ <p>${formatMultilineText(description)}</p>
438
+ </div>
439
+ <button
440
+ type="button"
441
+ class="eos-connect-sdk-primary eos-connect-sdk-primary--quick${isSuccess ? ' eos-connect-sdk-primary--success' : ''}"
442
+ data-provider="${escapeHtml(provider?.id ?? 'telegram')}"
443
+ aria-disabled="${disabled}"
444
+ ${isChecking ? 'aria-busy="true"' : ''}
445
+ ${disabled ? 'disabled' : ''}
446
+ >
447
+ ${leadingIcon}
448
+ <span>${escapeHtml(label)}</span>
449
+ ${trailingIcon}
450
+ </button>
451
+ </section>
452
+ `;
453
+ }
454
+ export function renderEosConnectSheet(client, options = {}) {
455
+ const snapshot = client.getSnapshot();
456
+ const providers = client.getProviders();
457
+ const primary = providers.find((provider) => provider.id === 'telegram') ?? providers[0];
458
+ const t = createTranslator(options);
459
+ const flowState = options.flowState === 'success' || options.flowState === 'checking'
460
+ ? options.flowState
461
+ : snapshot.status === 'connected' && snapshot.canUse
462
+ ? 'success'
463
+ : 'idle';
464
+ return renderQuickPaymentSheet(primary, t, flowState);
465
+ }
466
+ export async function connectEosProvider(client, _provider = 'telegram', options = {}) {
467
+ return client.startTelegramWalletFlow(options);
468
+ }
469
+ function isQuickPaymentReadyView(view) {
470
+ return view?.status === 'ready' && view.canPay === true;
471
+ }
472
+ function isQuickPaymentReadyState(state) {
473
+ return state.status === 'connected' && state.canUse === true;
474
+ }
475
+ function isQuickPaymentTerminalView(view) {
476
+ return view?.status === 'error' || view?.status === 'unsupported';
477
+ }
478
+ function globalTelegramWebApp() {
479
+ const maybeWindow = globalThis;
480
+ return maybeWindow.window?.Telegram?.WebApp ?? maybeWindow.Telegram?.WebApp ?? null;
481
+ }
482
+ function networkFromAttribute(value) {
483
+ if (value === 'testnet' || value === 'mainnet') {
484
+ return value;
485
+ }
486
+ return undefined;
487
+ }
488
+ function resolveClient(host, configuredClient, options) {
489
+ if (configuredClient) {
490
+ return configuredClient;
491
+ }
492
+ const existing = host.__eosConnectClient;
493
+ if (existing) {
494
+ return existing;
495
+ }
496
+ const apiBaseUrl = host.getAttribute('api-base-url') ?? options.apiBaseUrl;
497
+ const botUsername = host.getAttribute('bot-username') ?? options.botUsername;
498
+ const network = networkFromAttribute(host.getAttribute('network')) ?? options.network;
499
+ const cacheKey = [network ?? '', apiBaseUrl ?? '', botUsername ?? ''].join('\u001f');
500
+ const clientCache = options.__eosConnectClientCache ?? new Map();
501
+ options.__eosConnectClientCache = clientCache;
502
+ const cachedClient = clientCache.get(cacheKey);
503
+ if (cachedClient) {
504
+ host.__eosConnectClient = cachedClient;
505
+ return cachedClient;
506
+ }
507
+ const client = createEosConnect({
508
+ ...(network ? { network } : {}),
509
+ ...(apiBaseUrl ? { apiBaseUrl } : {}),
510
+ ...(botUsername ? { botUsername } : {}),
511
+ telegramWebApp: options.telegramWebApp ?? globalTelegramWebApp()
512
+ });
513
+ clientCache.set(cacheKey, client);
514
+ host.__eosConnectClient = client;
515
+ return client;
516
+ }
517
+ function dispatchEosConnectError(host, detail) {
518
+ host.dispatchEvent(new CustomEvent('eos-connect-error', {
519
+ bubbles: true,
520
+ composed: true,
521
+ detail
522
+ }));
523
+ }
524
+ function defaultModalForButton(host) {
525
+ const root = host.getRootNode?.();
526
+ return root?.querySelector?.('eos-connect-modal,eos-connect') ?? globalThis.document?.querySelector?.('eos-connect-modal,eos-connect') ?? null;
527
+ }
528
+ function createButtonElement(options) {
529
+ const BaseElement = globalThis.HTMLElement ?? class {
530
+ };
531
+ return class EosConnectButton extends BaseElement {
532
+ unsubscribe = null;
533
+ client = null;
534
+ connectedCallback() {
535
+ this.client = resolveClient(this, options.client, options);
536
+ this.render();
537
+ this.unsubscribe = this.client.subscribe(() => this.render());
538
+ void this.client.checkWallet().catch((error) => {
539
+ dispatchEosConnectError(this, { error });
540
+ });
541
+ this.addEventListener('click', this.open);
542
+ }
543
+ disconnectedCallback() {
544
+ this.unsubscribe?.();
545
+ this.removeEventListener('click', this.open);
546
+ }
547
+ open = () => {
548
+ defaultModalForButton(this)?.removeAttribute('hidden');
549
+ this.dispatchEvent(new CustomEvent('eos-connect-open', {
550
+ bubbles: true,
551
+ composed: true
552
+ }));
553
+ };
554
+ render() {
555
+ if (!this.client)
556
+ return;
557
+ this.innerHTML = renderEosConnectButton(this.client, {
558
+ locale: options.locale,
559
+ messages: options.messages,
560
+ telegramWebApp: options.telegramWebApp ?? globalTelegramWebApp()
561
+ });
562
+ }
563
+ };
564
+ }
565
+ function createModalElement(options) {
566
+ const BaseElement = globalThis.HTMLElement ?? class {
567
+ };
568
+ return class EosConnectModal extends BaseElement {
569
+ unsubscribe = null;
570
+ client = null;
571
+ flowState = 'idle';
572
+ flowPromise = null;
573
+ quickPayRefreshTimer = null;
574
+ connectedCallback() {
575
+ this.client = resolveClient(this, options.client, options);
576
+ this.render();
577
+ this.unsubscribe = this.client.subscribe(() => this.render());
578
+ void this.client.checkWallet().catch((error) => {
579
+ dispatchEosConnectError(this, { error });
580
+ });
581
+ this.addEventListener('click', this.handleClick);
582
+ globalThis.addEventListener?.('focus', this.handleForeground);
583
+ globalThis.document?.addEventListener?.('visibilitychange', this.handleForeground);
584
+ }
585
+ disconnectedCallback() {
586
+ this.clearQuickPayRefresh();
587
+ this.unsubscribe?.();
588
+ this.removeEventListener('click', this.handleClick);
589
+ globalThis.removeEventListener?.('focus', this.handleForeground);
590
+ globalThis.document?.removeEventListener?.('visibilitychange', this.handleForeground);
591
+ }
592
+ handleClick = (event) => {
593
+ const target = event.target;
594
+ if (target?.closest('[data-eos-connect-close]')) {
595
+ this.flowState = 'idle';
596
+ this.flowPromise = null;
597
+ this.clearQuickPayRefresh();
598
+ this.setAttribute('hidden', '');
599
+ this.dispatchEvent(new CustomEvent('eos-connect-close', { bubbles: true, composed: true }));
600
+ return;
601
+ }
602
+ const provider = target?.closest('[data-provider]')?.dataset.provider;
603
+ if (provider && this.client) {
604
+ const providerConfig = this.client.getProviders().find((item) => item.id === provider);
605
+ if (providerConfig?.state && providerConfig.state !== 'available') {
606
+ return;
607
+ }
608
+ if (provider === 'telegram') {
609
+ if (this.flowState !== 'idle' || this.flowPromise) {
610
+ return;
611
+ }
612
+ this.flowState = 'checking';
613
+ this.render();
614
+ this.scheduleQuickPayRefresh();
615
+ }
616
+ this.flowPromise = connectEosProvider(this.client, provider, {
617
+ ...options.telegramOptions,
618
+ botUsername: options.telegramOptions?.botUsername ?? options.botUsername,
619
+ assetLimits: options.telegramOptions?.assetLimits ?? options.assetLimits,
620
+ replaceWallet: options.telegramOptions?.replaceWallet ?? options.replaceWallet,
621
+ openExternal: options.openExternal
622
+ }).then((view) => {
623
+ if (provider === 'telegram') {
624
+ if (isQuickPaymentReadyView(view) || isQuickPaymentReadyState(this.client.getSnapshot())) {
625
+ this.showQuickPaySuccess();
626
+ return;
627
+ }
628
+ if (isQuickPaymentTerminalView(view)) {
629
+ this.flowState = 'idle';
630
+ this.clearQuickPayRefresh();
631
+ this.render();
632
+ return;
633
+ }
634
+ this.flowState = 'checking';
635
+ this.render();
636
+ this.scheduleQuickPayRefresh();
637
+ }
638
+ }).catch((error) => {
639
+ if (provider === 'telegram') {
640
+ this.flowState = 'idle';
641
+ this.clearQuickPayRefresh();
642
+ this.render();
643
+ }
644
+ dispatchEosConnectError(this, { error, provider });
645
+ }).finally(() => {
646
+ this.flowPromise = null;
647
+ });
648
+ }
649
+ };
650
+ handleForeground = () => {
651
+ if (globalThis.document?.visibilityState && globalThis.document.visibilityState !== 'visible') {
652
+ return;
653
+ }
654
+ if (this.flowState !== 'checking') {
655
+ return;
656
+ }
657
+ this.clearQuickPayRefresh();
658
+ void this.refreshQuickPayStatus();
659
+ };
660
+ scheduleQuickPayRefresh(delayMs = EOS_CONNECT_QUICK_PAY_REFRESH_INTERVAL_MS) {
661
+ if (!this.client || this.flowState !== 'checking' || this.quickPayRefreshTimer) {
662
+ return;
663
+ }
664
+ this.quickPayRefreshTimer = globalThis.setTimeout(() => {
665
+ this.quickPayRefreshTimer = null;
666
+ void this.refreshQuickPayStatus();
667
+ }, delayMs);
668
+ }
669
+ clearQuickPayRefresh() {
670
+ if (this.quickPayRefreshTimer) {
671
+ globalThis.clearTimeout(this.quickPayRefreshTimer);
672
+ this.quickPayRefreshTimer = null;
673
+ }
674
+ }
675
+ async refreshQuickPayStatus() {
676
+ if (!this.client || this.flowState !== 'checking') {
677
+ return;
678
+ }
679
+ try {
680
+ const quickPay = await this.client.checkQuickPay();
681
+ if (this.flowState !== 'checking') {
682
+ return;
683
+ }
684
+ if (quickPay.enabled) {
685
+ this.showQuickPaySuccess();
686
+ return;
687
+ }
688
+ }
689
+ catch (error) {
690
+ dispatchEosConnectError(this, { error, provider: 'telegram' });
691
+ }
692
+ this.scheduleQuickPayRefresh();
693
+ }
694
+ showQuickPaySuccess() {
695
+ this.flowState = 'success';
696
+ this.clearQuickPayRefresh();
697
+ this.render();
698
+ }
699
+ render() {
700
+ if (!this.client)
701
+ return;
702
+ this.innerHTML = renderEosConnectSheet(this.client, {
703
+ locale: options.locale,
704
+ messages: options.messages,
705
+ telegramWebApp: options.telegramWebApp ?? globalTelegramWebApp(),
706
+ flowState: this.flowState
707
+ });
708
+ }
709
+ };
710
+ }
711
+ export function defineEosConnectElements({ client, network, apiBaseUrl, botUsername, locale, messages, assetLimits, replaceWallet, telegramOptions, openExternal, telegramWebApp, injectStyles = true, customElements: registry = globalThis.customElements }) {
712
+ if (injectStyles) {
713
+ installEosConnectStyles();
714
+ }
715
+ if (!registry) {
716
+ throw new Error('CustomElementRegistry is not available');
717
+ }
718
+ const elementOptions = {
719
+ client,
720
+ network,
721
+ apiBaseUrl,
722
+ botUsername,
723
+ locale,
724
+ messages,
725
+ assetLimits,
726
+ replaceWallet,
727
+ telegramOptions,
728
+ openExternal,
729
+ telegramWebApp
730
+ };
731
+ if (!registry.get('eos-connect')) {
732
+ registry.define('eos-connect', createModalElement(elementOptions));
733
+ }
734
+ if (!registry.get('eos-connect-button')) {
735
+ registry.define('eos-connect-button', createButtonElement(elementOptions));
736
+ }
737
+ if (!registry.get('eos-connect-modal')) {
738
+ registry.define('eos-connect-modal', createModalElement(elementOptions));
739
+ }
740
+ }