@gluwa/connect-kit 0.2.0-next.1 → 0.2.0-next.5

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.
Files changed (91) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/assets/creditwallet.png +0 -0
  3. package/assets/fonts/Inter-Medium.ttf +0 -0
  4. package/assets/fonts/Inter-Medium.woff2 +0 -0
  5. package/assets/fonts/Inter-Regular.ttf +0 -0
  6. package/assets/fonts/Inter-Regular.woff2 +0 -0
  7. package/assets/fonts/Inter-SemiBold.ttf +0 -0
  8. package/assets/fonts/Inter-SemiBold.woff2 +0 -0
  9. package/assets/graphic.png +0 -0
  10. package/assets/metamask.png +0 -0
  11. package/assets/wc-logo.svg +3 -0
  12. package/assets/wc-search.png +0 -0
  13. package/dist/chunk-EDNRW47A.js +401 -0
  14. package/dist/credit-connect.js +2 -409
  15. package/dist/index.css +1903 -390
  16. package/dist/index.d.ts +17 -10
  17. package/dist/index.js +1118 -871
  18. package/dist/package.json +7 -6
  19. package/package.json +8 -8
  20. package/src/ConnectKitProvider.tsx +90 -65
  21. package/src/api/asset.ts +10 -0
  22. package/src/assets.d.ts +5 -0
  23. package/src/components/actionItem/index.tsx +50 -0
  24. package/src/components/actionItem/style.scss +47 -0
  25. package/src/components/copyLink/index.tsx +16 -0
  26. package/src/components/copyLink/style.scss +16 -0
  27. package/src/components/qrArea/index.tsx +70 -0
  28. package/src/components/qrArea/style.scss +130 -0
  29. package/src/components/searchBar/asset/Search.tsx +20 -0
  30. package/src/components/searchBar/asset/XMarkCircle.tsx +24 -0
  31. package/src/components/searchBar/index.tsx +44 -0
  32. package/src/components/searchBar/style.scss +58 -0
  33. package/src/components/snackbar/index.tsx +25 -0
  34. package/src/components/snackbar/style.scss +51 -0
  35. package/src/components/toggle/index.tsx +27 -0
  36. package/src/components/toggle/style.scss +53 -0
  37. package/src/components/walletGrid/index.tsx +64 -0
  38. package/src/components/walletGrid/style.scss +108 -0
  39. package/src/components/walletItem/index.tsx +49 -0
  40. package/src/components/walletItem/style.scss +70 -0
  41. package/src/connector-meta.ts +12 -7
  42. package/src/core/config.ts +20 -1
  43. package/src/creditConnectConnector.ts +17 -25
  44. package/src/hooks/useWCState.ts +22 -5
  45. package/src/hooks/useWagmiConnect.ts +0 -1
  46. package/src/index.ts +4 -2
  47. package/src/layout/allWallets/index.tsx +52 -0
  48. package/src/layout/allWallets/style.scss +62 -0
  49. package/src/layout/connectDialog/asset/backIcon.tsx +24 -0
  50. package/src/layout/connectDialog/asset/checkIcon.tsx +28 -0
  51. package/src/layout/connectDialog/asset/closeIcon.tsx +21 -0
  52. package/src/layout/connectDialog/asset/copyIcon.tsx +28 -0
  53. package/src/layout/connectDialog/asset/linkIcon.tsx +24 -0
  54. package/src/layout/connectDialog/asset/spinner.tsx +21 -0
  55. package/src/layout/connectDialog/idle/index.tsx +32 -0
  56. package/src/layout/connectDialog/idle/style.scss +61 -0
  57. package/src/layout/connectDialog/index.tsx +286 -0
  58. package/src/layout/connectDialog/loading/index.tsx +13 -0
  59. package/src/layout/connectDialog/loading/style.scss +19 -0
  60. package/src/layout/connectDialog/metaMask/index.tsx +61 -0
  61. package/src/layout/connectDialog/metaMask/style.scss +65 -0
  62. package/src/layout/connectDialog/qr/index.tsx +33 -0
  63. package/src/layout/connectDialog/style.scss +95 -0
  64. package/src/layout/connectDialog/timeout/index.tsx +31 -0
  65. package/src/layout/connectDialog/timeout/style.scss +64 -0
  66. package/src/layout/connectDialog/walletConnect/index.tsx +45 -0
  67. package/src/layout/connectDialog/walletConnect/style.scss +48 -0
  68. package/src/layout/connectDialog/walletQR/index.tsx +37 -0
  69. package/src/layout/detailPanel/index.tsx +147 -0
  70. package/src/layout/detailPanel/style.scss +64 -0
  71. package/src/layout/selectorPanel/index.tsx +100 -0
  72. package/src/layout/selectorPanel/style.scss +113 -0
  73. package/src/style/color.scss +417 -0
  74. package/src/style/font.scss +28 -0
  75. package/src/style/index.scss +5 -0
  76. package/src/style/mixin.scss +217 -0
  77. package/src/style/reset.scss +110 -0
  78. package/src/style/variables.scss +13 -0
  79. package/src/types.ts +11 -8
  80. package/src/utils/platform.ts +6 -0
  81. package/tsconfig.json +5 -1
  82. package/tsup.config.ts +32 -2
  83. package/dist/chunk-DDA6FP6U.js +0 -7
  84. package/src/ConnectModal.scss +0 -665
  85. package/src/ConnectModal.tsx +0 -573
  86. package/src/components/QRFrame.tsx +0 -43
  87. package/src/views/CreditWalletView.tsx +0 -58
  88. package/src/views/IdleView.tsx +0 -10
  89. package/src/views/MetaMaskView.tsx +0 -66
  90. package/src/views/SwitchChainView.tsx +0 -72
  91. package/src/views/WalletConnectView.tsx +0 -206
@@ -1,573 +0,0 @@
1
- import { useState, useEffect, useCallback, useMemo, type FC, type ReactNode } from 'react';
2
- import './ConnectModal.scss';
3
- import { useAccount, useConfig, useDisconnect } from 'wagmi';
4
- import {
5
- type ConnectModalProps,
6
- type ConnectErrorContext,
7
- type ConnectErrorReason,
8
- type Connectors,
9
- type ConnectorId,
10
- type WCWallet,
11
- type WCSubView,
12
- } from './types';
13
- import { CONNECTOR_META } from './connector-meta';
14
- import { detectMetaMaskExtension } from './utils/platform';
15
- import { useWagmiConnect, resolveWagmiConnector } from './hooks/useWagmiConnect';
16
- import { useWCState, type WCState } from './hooks/useWCState';
17
- import { IdleView } from './views/IdleView';
18
- import { CreditWalletView } from './views/CreditWalletView';
19
- import { MetaMaskView } from './views/MetaMaskView';
20
- import { WalletConnectView } from './views/WalletConnectView';
21
- import { SwitchChainView } from './views/SwitchChainView';
22
-
23
- const RECENT_KEY = 'connect-kit:recent';
24
- const VALID_CONNECTOR_IDS: ReadonlySet<ConnectorId> = new Set<ConnectorId>([
25
- 'CREDIT_CONNECT',
26
- 'CREDIT_WALLET',
27
- 'METAMASK',
28
- 'WALLET_CONNECT',
29
- ]);
30
-
31
- const readRecentConnector = (): ConnectorId | null => {
32
- try {
33
- const raw = localStorage.getItem(RECENT_KEY);
34
- if (raw == null) return null;
35
- return VALID_CONNECTOR_IDS.has(raw as ConnectorId) ? (raw as ConnectorId) : null;
36
- } catch {
37
- return null;
38
- }
39
- };
40
-
41
- const writeRecentConnector = (
42
- id: ConnectorId,
43
- onLog?: (message: string, error?: Error) => void,
44
- ): void => {
45
- try {
46
- localStorage.setItem(RECENT_KEY, id);
47
- } catch (err) {
48
- const normalized = err instanceof Error ? err : new Error(String(err));
49
- onLog?.(`[connect-kit] writeRecentConnector failed: ${normalized.message}`, normalized);
50
- }
51
- };
52
-
53
- const REJECTED_ERROR_CODES = new Set<unknown>([
54
- 4001, // EIP-1193 user rejected
55
- 'ACTION_REJECTED', // ethers v6
56
- ]);
57
-
58
- const classifyError = (error: Error): ConnectErrorReason => {
59
- const code =
60
- typeof error === 'object' && error !== null && 'code' in error
61
- ? (error as unknown as { code: unknown }).code
62
- : undefined;
63
- if (code != null && REJECTED_ERROR_CODES.has(code)) return 'rejected';
64
- const message = error.message?.toLowerCase() ?? '';
65
- if (
66
- message.includes('user rejected') ||
67
- message.includes('user denied') ||
68
- message.includes('user cancel') ||
69
- message.includes('rejected by user') ||
70
- message.includes('action_rejected') ||
71
- message.includes('사용자가 거부') ||
72
- message.includes('사용자가 취소') ||
73
- message.includes('ユーザーが拒否') ||
74
- message.includes('ユーザーがキャンセル')
75
- ) {
76
- return 'rejected';
77
- }
78
- if (message.includes('unsupported') || message.includes('not installed')) return 'unsupported';
79
- return 'unknown';
80
- };
81
-
82
- interface SelectorPaneProps {
83
- connectors: ConnectorId[];
84
- selected: ConnectorId | null;
85
- recentConnector: ConnectorId | null;
86
- onSelect: (id: ConnectorId) => void;
87
- onClose: () => void;
88
- }
89
-
90
- const SelectorPane: FC<SelectorPaneProps> = ({
91
- connectors,
92
- selected,
93
- recentConnector,
94
- onSelect,
95
- onClose,
96
- }) => {
97
- const hasRecent = recentConnector !== null && connectors.includes(recentConnector);
98
- const recentConnectors = hasRecent ? [recentConnector] : [];
99
- const otherConnectors = connectors.filter((id) => id !== recentConnector);
100
-
101
- const downloadUrl = connectors
102
- .map((id) => CONNECTOR_META[id].downloadUrl)
103
- .find((url) => url != null);
104
-
105
- return (
106
- <div className="ck-pane ck-pane--selector">
107
- <div className="ck-pane__header">
108
- <h3 className="ck-pane__title">Connect Wallet</h3>
109
- <button
110
- type="button"
111
- className="ck-btn-close ck-mobile-only"
112
- onClick={onClose}
113
- aria-label="Close"
114
- />
115
- </div>
116
-
117
- <div className="ck-connector-list">
118
- {hasRecent && (
119
- <>
120
- {recentConnectors.map((id) => (
121
- <ConnectorItem
122
- key={id}
123
- id={id}
124
- isSelected={selected === id}
125
- isRecent
126
- onSelect={onSelect}
127
- />
128
- ))}
129
- {otherConnectors.length > 0 && (
130
- <div className="ck-divider">
131
- <span>OR</span>
132
- </div>
133
- )}
134
- </>
135
- )}
136
-
137
- {otherConnectors.map((id) => (
138
- <ConnectorItem
139
- key={id}
140
- id={id}
141
- isSelected={selected === id}
142
- isRecent={false}
143
- onSelect={onSelect}
144
- />
145
- ))}
146
- </div>
147
-
148
- {downloadUrl && (
149
- <div className="ck-pane__footer">
150
- <a
151
- href={downloadUrl}
152
- target="_blank"
153
- rel="nofollow noopener noreferrer"
154
- className="ck-link-no-wallet"
155
- >
156
- I don&apos;t have a wallet &gt;
157
- </a>
158
- </div>
159
- )}
160
- </div>
161
- );
162
- };
163
-
164
- interface ConnectorItemProps {
165
- id: ConnectorId;
166
- isSelected: boolean;
167
- isRecent: boolean;
168
- onSelect: (id: ConnectorId) => void;
169
- }
170
-
171
- const ConnectorItem: FC<ConnectorItemProps> = ({ id, isSelected, isRecent, onSelect }) => {
172
- const meta = CONNECTOR_META[id];
173
-
174
- return (
175
- <button
176
- type="button"
177
- className={`ck-connector-item ck-connector-item--${id.toLowerCase().replaceAll('_', '-')} ${isSelected ? 'is-active' : ''}`}
178
- onClick={() => {
179
- onSelect(id);
180
- }}
181
- >
182
- {meta.logoUrl ? (
183
- <img className="ck-connector-item__icon" src={meta.logoUrl} alt="" aria-hidden="true" />
184
- ) : (
185
- <span className="ck-connector-item__icon" aria-hidden="true" />
186
- )}
187
- <span className="ck-connector-item__label">{meta.label}</span>
188
- {isRecent && <span className="ck-connector-item__badge">Recent</span>}
189
- </button>
190
- );
191
- };
192
-
193
- interface DetailPaneProps {
194
- selectedConnector: ConnectorId | null;
195
- qrUri: string | null;
196
- hasMetaMaskExtension: boolean;
197
- connectorLogoMap: Partial<Record<ConnectorId, string>>;
198
- wc: WCState;
199
- errorOverride: ReactNode | null;
200
- onBack: () => void;
201
- onClose: () => void;
202
- }
203
-
204
- const DetailPane: FC<DetailPaneProps> = ({
205
- selectedConnector,
206
- qrUri,
207
- hasMetaMaskExtension,
208
- connectorLogoMap,
209
- wc,
210
- errorOverride,
211
- onBack,
212
- onClose,
213
- }) => {
214
- const title = getDetailTitle(
215
- selectedConnector,
216
- hasMetaMaskExtension,
217
- wc.subView,
218
- wc.selectedWallet,
219
- );
220
- const showBack = selectedConnector !== null;
221
-
222
- return (
223
- <div className="ck-pane ck-pane--detail">
224
- <div className="ck-pane__header">
225
- {showBack && (
226
- <button type="button" className="ck-btn-back" onClick={onBack} aria-label="Back" />
227
- )}
228
- <h3 className="ck-pane__title">{title}</h3>
229
- <button type="button" className="ck-btn-close" onClick={onClose} aria-label="Close" />
230
- </div>
231
-
232
- <div className="ck-pane__body">
233
- {errorOverride || (
234
- <>
235
- {!selectedConnector && <IdleView />}
236
-
237
- {(selectedConnector === 'CREDIT_CONNECT' || selectedConnector === 'CREDIT_WALLET') && (
238
- <CreditWalletView connectorId={selectedConnector} qrUri={qrUri} />
239
- )}
240
-
241
- {selectedConnector === 'METAMASK' && (
242
- <MetaMaskView
243
- qrUri={qrUri}
244
- hasExtension={hasMetaMaskExtension}
245
- logoUrl={connectorLogoMap.METAMASK}
246
- />
247
- )}
248
-
249
- {selectedConnector === 'WALLET_CONNECT' && (
250
- <WalletConnectView
251
- subView={wc.subView}
252
- qrUri={qrUri}
253
- logoUrl={connectorLogoMap.WALLET_CONNECT}
254
- walletList={wc.walletList}
255
- walletListLoading={wc.walletListLoading}
256
- walletListSearch={wc.walletListSearch}
257
- walletListFilterActive={wc.filterActive}
258
- selectedWallet={wc.selectedWallet}
259
- onShowList={wc.onShowList}
260
- onSelectWallet={wc.onSelectWallet}
261
- onSearchChange={wc.onSearchChange}
262
- onFilterToggle={wc.onFilterToggle}
263
- />
264
- )}
265
- </>
266
- )}
267
- </div>
268
- </div>
269
- );
270
- };
271
-
272
- const getDetailTitle = (
273
- connector: ConnectorId | null,
274
- hasMetaMaskExtension: boolean,
275
- wcSubView: WCSubView,
276
- wcSelectedWallet: WCWallet | null,
277
- ): string => {
278
- if (!connector) return '';
279
-
280
- if (connector === 'WALLET_CONNECT') {
281
- if (wcSubView === 'list') return 'All Wallets';
282
- if (wcSubView === 'wallet' && wcSelectedWallet) return `Scan with ${wcSelectedWallet.name}`;
283
- return 'Scan with WalletConnect';
284
- }
285
-
286
- if (connector === 'METAMASK' && hasMetaMaskExtension) return 'MetaMask';
287
-
288
- return CONNECTOR_META[connector].detailTitle;
289
- };
290
-
291
- const resolveConnectorsFromConfig = (connectorsConfig?: Connectors): ConnectorId[] => {
292
- if (!connectorsConfig) return [];
293
-
294
- const connectors: ConnectorId[] = [];
295
-
296
- if (connectorsConfig.creditWallet === 'walletConnect') connectors.push('CREDIT_WALLET');
297
- if (connectorsConfig.creditWallet === 'creditConnect') connectors.push('CREDIT_CONNECT');
298
- if (connectorsConfig.metamask) connectors.push('METAMASK');
299
- if (connectorsConfig.walletConnect) connectors.push('WALLET_CONNECT');
300
-
301
- return connectors;
302
- };
303
-
304
- export const ConnectModal: FC<ConnectModalProps> = (props) => {
305
- if (!props.open) return null;
306
-
307
- const resolvedConnectors = resolveConnectorsFromConfig(props.connectors);
308
-
309
- if (
310
- resolvedConnectors.includes('CREDIT_WALLET') &&
311
- resolvedConnectors.includes('CREDIT_CONNECT')
312
- ) {
313
- throw new Error('CREDIT_WALLET and CREDIT_CONNECT cannot be used together');
314
- }
315
- if (resolvedConnectors.length === 0) {
316
- throw new Error('At least one connector must be configured');
317
- }
318
- return <ConnectModalInner {...props} connectors={resolvedConnectors} />;
319
- };
320
-
321
- type ConnectModalInnerProps = Omit<ConnectModalProps, 'connectors'> & {
322
- connectors: ConnectorId[];
323
- };
324
-
325
- const ConnectModalInner: FC<ConnectModalInnerProps> = ({
326
- open,
327
- connectors,
328
- onConnect,
329
- onClose,
330
- onLog,
331
- wcProjectId,
332
- requiredChainId,
333
- renderConnectError,
334
- }) => {
335
- const [selectedConnector, setSelectedConnector] = useState<ConnectorId | null>(null);
336
- const [qrUri, setQrUri] = useState<string | null>(null);
337
- const [recentConnector, setRecentConnector] = useState<ConnectorId | null>(null);
338
- const [hasMetaMaskExtension, setHasMetaMaskExtension] = useState<boolean>(false);
339
- const [errorState, setErrorState] = useState<{ connectorId: ConnectorId; error: Error } | null>(
340
- null,
341
- );
342
-
343
- const wc = useWCState();
344
-
345
- const account = useAccount();
346
- const { disconnectAsync } = useDisconnect();
347
- const wagmiConfig = useConfig();
348
-
349
- const chainMismatch =
350
- requiredChainId != null &&
351
- account.status === 'connected' &&
352
- account.chainId != null &&
353
- account.chainId !== requiredChainId;
354
-
355
- const requiredChainName = useMemo<string | undefined>(() => {
356
- if (requiredChainId == null) return undefined;
357
- return wagmiConfig.chains.find((chain) => chain.id === requiredChainId)?.name;
358
- }, [wagmiConfig.chains, requiredChainId]);
359
-
360
- const handleQrUri = useCallback((uri: string | null) => {
361
- setQrUri(uri);
362
- }, []);
363
-
364
- const handleConnect = useCallback(
365
- (result: Parameters<typeof onConnect>[0]) => {
366
- setErrorState(null);
367
- onConnect(result);
368
- onClose();
369
- },
370
- [onConnect, onClose],
371
- );
372
-
373
- const handleError = useCallback(
374
- (error: unknown, connectorId: ConnectorId): void => {
375
- const normalizedError = error instanceof Error ? error : new Error(String(error));
376
- onLog?.(
377
- `[connect-kit] connection failed (${connectorId}): ${normalizedError.message}`,
378
- normalizedError,
379
- );
380
- setQrUri(null);
381
- wc.resetView();
382
- if (renderConnectError) {
383
- setErrorState({ connectorId, error: normalizedError });
384
- } else {
385
- setSelectedConnector(null);
386
- }
387
- },
388
- [onLog, wc.resetView, renderConnectError],
389
- );
390
-
391
- const { triggerConnect, cancelConnect } = useWagmiConnect({
392
- onConnect: handleConnect,
393
- onError: handleError,
394
- onQrUri: handleQrUri,
395
- });
396
-
397
- const connectorLogoMap = useMemo(() => {
398
- const map: Partial<Record<ConnectorId, string>> = {};
399
- const connectorIds: ConnectorId[] = [
400
- 'CREDIT_CONNECT',
401
- 'CREDIT_WALLET',
402
- 'METAMASK',
403
- 'WALLET_CONNECT',
404
- ];
405
- for (const connectorId of connectorIds) {
406
- const wagmiConnector = resolveWagmiConnector(wagmiConfig.connectors, connectorId);
407
- if (wagmiConnector?.icon) map[connectorId] = wagmiConnector.icon;
408
- }
409
- return map;
410
- }, [wagmiConfig.connectors]);
411
-
412
- useEffect(() => {
413
- setRecentConnector(readRecentConnector());
414
- setHasMetaMaskExtension(detectMetaMaskExtension());
415
- }, []);
416
-
417
- useEffect(() => {
418
- if (!open) {
419
- setSelectedConnector(null);
420
- setQrUri(null);
421
- setErrorState(null);
422
- wc.reset();
423
- cancelConnect();
424
- }
425
- }, [open, cancelConnect, wc.reset]);
426
-
427
- const handleSelectConnector = useCallback(
428
- (id: ConnectorId): void => {
429
- if (id === selectedConnector && !errorState) return;
430
- setSelectedConnector(id);
431
- setQrUri(null);
432
- setErrorState(null);
433
- wc.resetView();
434
- writeRecentConnector(id, onLog);
435
- setRecentConnector(id);
436
-
437
- if (id === 'WALLET_CONNECT' && wcProjectId) {
438
- wc.loadWalletList(wcProjectId);
439
- }
440
-
441
- cancelConnect();
442
- triggerConnect(id);
443
- },
444
- [
445
- selectedConnector,
446
- errorState,
447
- triggerConnect,
448
- cancelConnect,
449
- wcProjectId,
450
- wc.resetView,
451
- wc.loadWalletList,
452
- onLog,
453
- ],
454
- );
455
-
456
- const handleBack = useCallback((): void => {
457
- if (errorState) {
458
- setErrorState(null);
459
- setSelectedConnector(null);
460
- return;
461
- }
462
- if (selectedConnector === 'WALLET_CONNECT' && wc.handleBack()) return;
463
- setSelectedConnector(null);
464
- setQrUri(null);
465
- cancelConnect();
466
- }, [selectedConnector, errorState, wc.handleBack, cancelConnect]);
467
-
468
- const handleSwitchChainDisconnect = useCallback((): void => {
469
- disconnectAsync().catch((err: unknown) => {
470
- const normalized = err instanceof Error ? err : new Error(String(err));
471
- onLog?.(`[connect-kit] disconnect failed: ${normalized.message}`, normalized);
472
- });
473
- }, [disconnectAsync, onLog]);
474
-
475
- const handleOverlayClick = useCallback((): void => {
476
- if (chainMismatch) return;
477
- onClose();
478
- }, [chainMismatch, onClose]);
479
-
480
- const handleCloseClick = useCallback((): void => {
481
- if (chainMismatch) {
482
- handleSwitchChainDisconnect();
483
- return;
484
- }
485
- onClose();
486
- }, [chainMismatch, handleSwitchChainDisconnect, onClose]);
487
-
488
- const renderedError: ReactNode = useMemo(() => {
489
- if (!errorState || !renderConnectError) return null;
490
- const ctx: ConnectErrorContext = {
491
- connectorId: errorState.connectorId,
492
- reason: classifyError(errorState.error),
493
- error: errorState.error,
494
- retry: () => {
495
- const id = errorState.connectorId;
496
- setErrorState(null);
497
- setQrUri(null);
498
- cancelConnect();
499
- triggerConnect(id);
500
- },
501
- dismiss: () => {
502
- setErrorState(null);
503
- setSelectedConnector(null);
504
- },
505
- };
506
- return renderConnectError(ctx);
507
- }, [errorState, renderConnectError, triggerConnect, cancelConnect]);
508
-
509
- if (chainMismatch && requiredChainId != null) {
510
- return (
511
- <div className="ck-root">
512
- <div className="ck-overlay" onClick={handleOverlayClick} />
513
- <div
514
- className="ck-modal ck-modal--switch-chain"
515
- role="dialog"
516
- aria-modal="true"
517
- aria-label="Switch network"
518
- >
519
- <div className="ck-pane">
520
- <div className="ck-pane__header">
521
- <h3 className="ck-pane__title">Switch network</h3>
522
- <button
523
- type="button"
524
- className="ck-btn-close"
525
- onClick={handleCloseClick}
526
- aria-label="Cancel and disconnect"
527
- />
528
- </div>
529
- <div className="ck-pane__body">
530
- <SwitchChainView
531
- currentChainId={account.chainId}
532
- requiredChainId={requiredChainId}
533
- requiredChainName={requiredChainName}
534
- onDisconnect={handleSwitchChainDisconnect}
535
- onLog={onLog}
536
- />
537
- </div>
538
- </div>
539
- </div>
540
- </div>
541
- );
542
- }
543
-
544
- return (
545
- <div className="ck-root">
546
- <div className="ck-overlay" onClick={handleOverlayClick} />
547
- <div
548
- className={`ck-modal${(selectedConnector ?? errorState) ? ' ck-modal--has-detail' : ''}`}
549
- role="dialog"
550
- aria-modal="true"
551
- aria-label="Connect Wallet"
552
- >
553
- <SelectorPane
554
- connectors={connectors}
555
- selected={selectedConnector}
556
- recentConnector={recentConnector}
557
- onSelect={handleSelectConnector}
558
- onClose={handleCloseClick}
559
- />
560
- <DetailPane
561
- selectedConnector={selectedConnector}
562
- qrUri={qrUri}
563
- hasMetaMaskExtension={hasMetaMaskExtension}
564
- connectorLogoMap={connectorLogoMap}
565
- wc={wc}
566
- errorOverride={renderedError}
567
- onBack={handleBack}
568
- onClose={handleCloseClick}
569
- />
570
- </div>
571
- </div>
572
- );
573
- };
@@ -1,43 +0,0 @@
1
- import { type FC } from 'react';
2
- import { QRCodeSVG } from 'qrcode.react';
3
-
4
- interface QRFrameProps {
5
- qrUri: string | null;
6
- logoUrl?: string;
7
- }
8
-
9
- export const QRFrame: FC<QRFrameProps> = ({ qrUri, logoUrl }) => (
10
- <div className={`ck-qr-frame ${!qrUri ? 'ck-qr-frame--loading' : ''}`}>
11
- {qrUri ? (
12
- <QRCodeSVG
13
- value={qrUri}
14
- size={196}
15
- level="H"
16
- imageSettings={
17
- logoUrl ? { src: logoUrl, width: 50, height: 50, excavate: true } : undefined
18
- }
19
- />
20
- ) : (
21
- <div className="ck-qr-spinner" aria-label="Loading QR code" />
22
- )}
23
- </div>
24
- );
25
-
26
- interface CopyLinkButtonProps {
27
- qrUri: string | null;
28
- }
29
-
30
- export const CopyLinkButton: FC<CopyLinkButtonProps> = ({ qrUri }) => {
31
- if (!qrUri) return null;
32
- return (
33
- <button
34
- type="button"
35
- className="ck-copy-link"
36
- onClick={() => {
37
- navigator.clipboard?.writeText(qrUri).catch(() => {});
38
- }}
39
- >
40
- Copy link
41
- </button>
42
- );
43
- };
@@ -1,58 +0,0 @@
1
- import { type FC, useEffect, useMemo, useRef } from 'react';
2
- import { isMobileDevice, tryOpenDeepLink } from '../utils/platform';
3
- import { CONNECTOR_META } from '../connector-meta';
4
- import { type ConnectorId } from '../types';
5
- import { QRFrame } from '../components/QRFrame';
6
-
7
- interface CreditWalletViewProps {
8
- connectorId: Extract<ConnectorId, 'CREDIT_CONNECT' | 'CREDIT_WALLET'>;
9
- qrUri: string | null;
10
- }
11
-
12
- export const CreditWalletView: FC<CreditWalletViewProps> = ({ connectorId, qrUri }) => {
13
- const { downloadUrl, logoUrl, deepLinkBase } = CONNECTOR_META[connectorId];
14
- const isMobile = useMemo(() => isMobileDevice(), []);
15
- const hasRedirectedRef = useRef(false);
16
-
17
- useEffect(() => {
18
- if (isMobile && qrUri && deepLinkBase && !hasRedirectedRef.current) {
19
- hasRedirectedRef.current = true;
20
- tryOpenDeepLink(qrUri, deepLinkBase);
21
- }
22
- }, [isMobile, qrUri, deepLinkBase]);
23
-
24
- if (isMobile && deepLinkBase) {
25
- return (
26
- <div className="ck-view ck-view--mobile-redirect">
27
- <p>Opening Credit Wallet...</p>
28
- </div>
29
- );
30
- }
31
-
32
- return (
33
- <div className="ck-view ck-view--qr">
34
- <QRFrame qrUri={qrUri} logoUrl={logoUrl} />
35
-
36
- <p className="ck-view__caption">Open the Credit Wallet app and scan the QR</p>
37
-
38
- {downloadUrl && (
39
- <div className="ck-download-card">
40
- <div className="ck-download-card__text">
41
- <p className="ck-download-card__title">Get Credit Wallet app</p>
42
- <p className="ck-download-card__sub">
43
- Once connected, you can log in with it next time
44
- </p>
45
- </div>
46
- <a
47
- href={downloadUrl}
48
- target="_blank"
49
- rel="nofollow noopener noreferrer"
50
- className="ck-btn-primary"
51
- >
52
- Download
53
- </a>
54
- </div>
55
- )}
56
- </div>
57
- );
58
- };
@@ -1,10 +0,0 @@
1
- import { type FC } from 'react';
2
- import graphic from '../../assets/graphic.png';
3
-
4
- export const IdleView: FC = () => (
5
- <div className="ck-view ck-view--idle">
6
- <img className="ck-view__illustration" src={graphic} alt="" aria-hidden="true" />
7
- <h4 className="ck-view__title">Connect anytime, anywhere</h4>
8
- <p className="ck-view__description">Choose a wallet on the left to start connecting.</p>
9
- </div>
10
- );