@gluwa/connect-kit 0.1.0-next.0 → 0.1.0-next.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/CHANGELOG.md +6 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +333 -298
- package/dist/package.json +3 -1
- package/package.json +3 -1
- package/src/ConnectModal.tsx +79 -173
- package/src/components/QRFrame.tsx +43 -0
- package/src/creditConnectConnector.ts +61 -13
- package/src/hooks/useWCState.ts +150 -0
- package/src/hooks/useWagmiConnect.ts +68 -45
- package/src/index.ts +9 -1
- package/src/types.ts +8 -4
- package/src/views/CreditWalletView.tsx +4 -17
- package/src/views/MetaMaskView.tsx +5 -30
- package/src/views/WalletConnectView.tsx +10 -70
- package/tsup.config.ts +12 -1
- package/dist/_esm-PE6HOEBI.js +0 -3909
- package/dist/ccip-UBX2BH3T.js +0 -15
- package/dist/chunk-6KUZ225H.js +0 -5259
- package/dist/chunk-EVEWD66F.js +0 -447
- package/dist/chunk-U2IU7TQD.js +0 -45
- package/dist/secp256k1-FYSVLDVL.js +0 -2311
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { useState, useRef, useCallback } from 'react';
|
|
2
|
+
import type { WCWallet, WCSubView } from '../types';
|
|
3
|
+
|
|
4
|
+
const fetchWCWalletList = async (projectId: string): Promise<WCWallet[]> => {
|
|
5
|
+
const all: WCWallet[] = [];
|
|
6
|
+
let page = 1;
|
|
7
|
+
const entries = 100;
|
|
8
|
+
|
|
9
|
+
while (page <= 10) {
|
|
10
|
+
const url = new URL('https://explorer-api.walletconnect.com/v3/wallets');
|
|
11
|
+
url.searchParams.set('projectId', projectId);
|
|
12
|
+
url.searchParams.set('entries', String(entries));
|
|
13
|
+
url.searchParams.set('page', String(page));
|
|
14
|
+
|
|
15
|
+
const res = await fetch(url.toString());
|
|
16
|
+
if (!res.ok) throw new Error(`Failed to fetch wallet list: ${res.status}`);
|
|
17
|
+
|
|
18
|
+
const json = (await res.json()) as {
|
|
19
|
+
listings: Record<
|
|
20
|
+
string,
|
|
21
|
+
{
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
homepage?: string;
|
|
25
|
+
image_url?: { sm?: string; md?: string };
|
|
26
|
+
mobile?: { native?: string; universal?: string };
|
|
27
|
+
desktop?: { native?: string; universal?: string };
|
|
28
|
+
app?: { ios?: string; android?: string };
|
|
29
|
+
}
|
|
30
|
+
>;
|
|
31
|
+
total: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const listings = Object.values(json.listings ?? {});
|
|
35
|
+
for (const w of listings) {
|
|
36
|
+
all.push({
|
|
37
|
+
id: w.id,
|
|
38
|
+
name: w.name,
|
|
39
|
+
imageUrl: w.image_url?.md ?? w.image_url?.sm ?? '',
|
|
40
|
+
mobileNative: w.mobile?.native ?? '',
|
|
41
|
+
mobileUniversal: w.mobile?.universal ?? '',
|
|
42
|
+
desktopNative: w.desktop?.native ?? '',
|
|
43
|
+
desktopUniversal: w.desktop?.universal ?? '',
|
|
44
|
+
appIos: w.app?.ios ?? '',
|
|
45
|
+
appAndroid: w.app?.android ?? '',
|
|
46
|
+
homepage: w.homepage ?? '',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (listings.length < entries || all.length >= json.total) break;
|
|
51
|
+
page += 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return all;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export interface WCState {
|
|
58
|
+
subView: WCSubView;
|
|
59
|
+
walletList: WCWallet[];
|
|
60
|
+
walletListLoading: boolean;
|
|
61
|
+
walletListSearch: string;
|
|
62
|
+
filterActive: boolean;
|
|
63
|
+
selectedWallet: WCWallet | null;
|
|
64
|
+
loadWalletList: (projectId: string) => Promise<void>;
|
|
65
|
+
onShowList: () => void;
|
|
66
|
+
onSelectWallet: (wallet: WCWallet) => void;
|
|
67
|
+
onSearchChange: (q: string) => void;
|
|
68
|
+
onFilterToggle: () => void;
|
|
69
|
+
// Returns true if WC handled the back navigation, false if the parent should handle it
|
|
70
|
+
handleBack: () => boolean;
|
|
71
|
+
resetView: () => void;
|
|
72
|
+
reset: () => void;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const useWCState = (): WCState => {
|
|
76
|
+
const [subView, setSubView] = useState<WCSubView>('qr');
|
|
77
|
+
const [walletList, setWalletList] = useState<WCWallet[]>([]);
|
|
78
|
+
const [walletListLoading, setWalletListLoading] = useState(false);
|
|
79
|
+
const [walletListSearch, setWalletListSearch] = useState('');
|
|
80
|
+
const [filterActive, setFilterActive] = useState(false);
|
|
81
|
+
const [selectedWallet, setSelectedWallet] = useState<WCWallet | null>(null);
|
|
82
|
+
const loadedRef = useRef(false);
|
|
83
|
+
|
|
84
|
+
const loadWalletList = useCallback(async (projectId: string): Promise<void> => {
|
|
85
|
+
if (loadedRef.current) return;
|
|
86
|
+
loadedRef.current = true;
|
|
87
|
+
setWalletListLoading(true);
|
|
88
|
+
try {
|
|
89
|
+
const list = await fetchWCWalletList(projectId);
|
|
90
|
+
setWalletList(list);
|
|
91
|
+
} catch {
|
|
92
|
+
loadedRef.current = false;
|
|
93
|
+
} finally {
|
|
94
|
+
setWalletListLoading(false);
|
|
95
|
+
}
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
const onShowList = useCallback((): void => setSubView('list'), []);
|
|
99
|
+
|
|
100
|
+
const onSelectWallet = useCallback((wallet: WCWallet): void => {
|
|
101
|
+
setSelectedWallet(wallet);
|
|
102
|
+
setSubView('wallet');
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
const onSearchChange = useCallback((q: string): void => setWalletListSearch(q), []);
|
|
106
|
+
|
|
107
|
+
const onFilterToggle = useCallback((): void => setFilterActive((prev) => !prev), []);
|
|
108
|
+
|
|
109
|
+
const handleBack = useCallback((): boolean => {
|
|
110
|
+
if (subView === 'wallet') {
|
|
111
|
+
setSelectedWallet(null);
|
|
112
|
+
setSubView('list');
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
if (subView === 'list') {
|
|
116
|
+
setSubView('qr');
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}, [subView]);
|
|
121
|
+
|
|
122
|
+
const resetView = useCallback((): void => {
|
|
123
|
+
setSubView('qr');
|
|
124
|
+
setSelectedWallet(null);
|
|
125
|
+
}, []);
|
|
126
|
+
|
|
127
|
+
const reset = useCallback((): void => {
|
|
128
|
+
setSubView('qr');
|
|
129
|
+
setWalletListSearch('');
|
|
130
|
+
setFilterActive(false);
|
|
131
|
+
setSelectedWallet(null);
|
|
132
|
+
}, []);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
subView,
|
|
136
|
+
walletList,
|
|
137
|
+
walletListLoading,
|
|
138
|
+
walletListSearch,
|
|
139
|
+
filterActive,
|
|
140
|
+
selectedWallet,
|
|
141
|
+
loadWalletList,
|
|
142
|
+
onShowList,
|
|
143
|
+
onSelectWallet,
|
|
144
|
+
onSearchChange,
|
|
145
|
+
onFilterToggle,
|
|
146
|
+
handleBack,
|
|
147
|
+
resetView,
|
|
148
|
+
reset,
|
|
149
|
+
};
|
|
150
|
+
};
|
|
@@ -1,12 +1,54 @@
|
|
|
1
1
|
import { useEffect, useRef, useCallback } from 'react';
|
|
2
|
-
import { useConnect,
|
|
2
|
+
import { useConnect, useConfig } from 'wagmi';
|
|
3
3
|
import type { ConnectorId, ConnectResult } from '../types';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
type WagmiConnectorLike = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
type?: string;
|
|
9
|
+
rdns?: string | readonly string[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const hasMetaMaskKeyword = (value: string): boolean => value.toLowerCase().includes('metamask');
|
|
13
|
+
const hasWalletConnectKeyword = (value: string): boolean =>
|
|
14
|
+
value.toLowerCase().includes('walletconnect');
|
|
15
|
+
|
|
16
|
+
const isMetaMaskConnector = (connector: WagmiConnectorLike): boolean => {
|
|
17
|
+
if (connector.id === 'injected' || connector.id === 'metaMaskSDK') return true;
|
|
18
|
+
if (hasMetaMaskKeyword(connector.id) || hasMetaMaskKeyword(connector.name)) return true;
|
|
19
|
+
|
|
20
|
+
if (connector.rdns) {
|
|
21
|
+
const rdnsList = Array.isArray(connector.rdns) ? connector.rdns : [connector.rdns];
|
|
22
|
+
if (rdnsList.some((rdns) => hasMetaMaskKeyword(rdns))) return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const isWalletConnectConnector = (connector: WagmiConnectorLike): boolean => {
|
|
29
|
+
if (connector.id === 'walletConnect') return true;
|
|
30
|
+
if (hasWalletConnectKeyword(connector.id) || hasWalletConnectKeyword(connector.name)) return true;
|
|
31
|
+
return false;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const resolveWagmiConnector = <T extends WagmiConnectorLike>(
|
|
35
|
+
connectors: readonly T[],
|
|
36
|
+
connectorId: ConnectorId,
|
|
37
|
+
): T | undefined => {
|
|
38
|
+
switch (connectorId) {
|
|
39
|
+
case 'CREDIT_CONNECT':
|
|
40
|
+
return connectors.find((connector) => connector.id === 'credit-connect');
|
|
41
|
+
|
|
42
|
+
case 'METAMASK':
|
|
43
|
+
return connectors.find(isMetaMaskConnector);
|
|
44
|
+
|
|
45
|
+
case 'CREDIT_WALLET':
|
|
46
|
+
case 'WALLET_CONNECT':
|
|
47
|
+
return connectors.find(isWalletConnectConnector);
|
|
48
|
+
|
|
49
|
+
default:
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
10
52
|
};
|
|
11
53
|
|
|
12
54
|
interface Options {
|
|
@@ -27,7 +69,6 @@ export const useWagmiConnect = ({
|
|
|
27
69
|
onQrUri,
|
|
28
70
|
}: Options): UseWagmiConnectResult => {
|
|
29
71
|
const config = useConfig();
|
|
30
|
-
const { address, status } = useAccount();
|
|
31
72
|
const pendingConnectorId = useRef<ConnectorId | null>(null);
|
|
32
73
|
|
|
33
74
|
// 콜백 참조
|
|
@@ -36,26 +77,12 @@ export const useWagmiConnect = ({
|
|
|
36
77
|
const onQrUriRef = useRef(onQrUri);
|
|
37
78
|
useEffect(() => {
|
|
38
79
|
onConnectRef.current = onConnect;
|
|
39
|
-
}, [onConnect]);
|
|
40
|
-
useEffect(() => {
|
|
41
80
|
onErrorRef.current = onError;
|
|
42
|
-
}, [onError]);
|
|
43
|
-
useEffect(() => {
|
|
44
81
|
onQrUriRef.current = onQrUri;
|
|
45
|
-
}, [onQrUri]);
|
|
82
|
+
}, [onConnect, onError, onQrUri]);
|
|
46
83
|
|
|
47
84
|
// 연결 시도
|
|
48
|
-
const {
|
|
49
|
-
mutation: {
|
|
50
|
-
onError(error) {
|
|
51
|
-
const id = pendingConnectorId.current;
|
|
52
|
-
if (id) {
|
|
53
|
-
onErrorRef.current(error as Error, id);
|
|
54
|
-
pendingConnectorId.current = null;
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
});
|
|
85
|
+
const { connectAsync, reset, isPending } = useConnect();
|
|
59
86
|
|
|
60
87
|
// QR 코드 표시
|
|
61
88
|
useEffect(() => {
|
|
@@ -80,38 +107,34 @@ export const useWagmiConnect = ({
|
|
|
80
107
|
};
|
|
81
108
|
}, [config.connectors]);
|
|
82
109
|
|
|
83
|
-
// 연결 완료
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
if (status === 'connected' && address && pendingConnectorId.current) {
|
|
86
|
-
const id = pendingConnectorId.current;
|
|
87
|
-
pendingConnectorId.current = null;
|
|
88
|
-
onConnectRef.current({ address, connectorId: id });
|
|
89
|
-
}
|
|
90
|
-
}, [status, address]);
|
|
91
|
-
|
|
92
110
|
// 연결 트리거
|
|
93
111
|
const triggerConnect = useCallback(
|
|
94
112
|
(connectorId: ConnectorId): void => {
|
|
95
|
-
const
|
|
96
|
-
if (!wagmiId) {
|
|
97
|
-
onErrorRef.current(new Error(`No wagmi connector mapped for ${connectorId}`), connectorId);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const connector = config.connectors.find((c) => c.id === wagmiId);
|
|
113
|
+
const connector = resolveWagmiConnector(config.connectors, connectorId);
|
|
102
114
|
if (!connector) {
|
|
103
|
-
onErrorRef.current(
|
|
104
|
-
new Error(`Wagmi connector '${wagmiId}' not found in config`),
|
|
105
|
-
connectorId,
|
|
106
|
-
);
|
|
115
|
+
onErrorRef.current(new Error(`No wagmi connector found for ${connectorId}`), connectorId);
|
|
107
116
|
return;
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
onQrUriRef.current(null);
|
|
111
120
|
pendingConnectorId.current = connectorId;
|
|
112
|
-
|
|
121
|
+
connectAsync({ connector })
|
|
122
|
+
.then((result) => {
|
|
123
|
+
if (pendingConnectorId.current !== connectorId) return;
|
|
124
|
+
const address = result.accounts?.[0];
|
|
125
|
+
if (!address) {
|
|
126
|
+
throw new Error('Connected but no account returned');
|
|
127
|
+
}
|
|
128
|
+
pendingConnectorId.current = null;
|
|
129
|
+
onConnectRef.current({ address, connectorId });
|
|
130
|
+
})
|
|
131
|
+
.catch((error) => {
|
|
132
|
+
if (pendingConnectorId.current !== connectorId) return;
|
|
133
|
+
pendingConnectorId.current = null;
|
|
134
|
+
onErrorRef.current(error as Error, connectorId);
|
|
135
|
+
});
|
|
113
136
|
},
|
|
114
|
-
[config.connectors,
|
|
137
|
+
[config.connectors, connectAsync],
|
|
115
138
|
);
|
|
116
139
|
|
|
117
140
|
// 연결 취소
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export { ConnectModal } from './ConnectModal';
|
|
2
2
|
export { creditConnectConnector } from './creditConnectConnector';
|
|
3
3
|
export type { CreditConnectConnectorOptions } from './creditConnectConnector';
|
|
4
|
-
export type {
|
|
4
|
+
export type {
|
|
5
|
+
ConnectModalProps,
|
|
6
|
+
Connectors,
|
|
7
|
+
ConnectResult,
|
|
8
|
+
ConnectorId,
|
|
9
|
+
CreditWalletStrategy,
|
|
10
|
+
WCSubView,
|
|
11
|
+
WCWallet,
|
|
12
|
+
} from './types';
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
export type ConnectorId = 'CREDIT_WALLET' | 'CREDIT_CONNECT' | 'METAMASK' | 'WALLET_CONNECT';
|
|
2
2
|
|
|
3
|
-
export type
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export type CreditWalletStrategy = 'walletConnect' | 'creditConnect';
|
|
4
|
+
|
|
5
|
+
export interface Connectors {
|
|
6
|
+
creditWallet?: CreditWalletStrategy | false;
|
|
7
|
+
metamask?: boolean;
|
|
8
|
+
walletConnect?: boolean;
|
|
9
|
+
}
|
|
6
10
|
|
|
7
11
|
export interface WCWallet {
|
|
8
12
|
id: string;
|
|
@@ -26,7 +30,7 @@ export interface ConnectResult {
|
|
|
26
30
|
|
|
27
31
|
export interface ConnectModalProps {
|
|
28
32
|
open: boolean;
|
|
29
|
-
connectors:
|
|
33
|
+
connectors: Connectors;
|
|
30
34
|
onConnect: (result: ConnectResult) => void;
|
|
31
35
|
onClose: () => void;
|
|
32
36
|
onLog?: (message: string, error?: Error) => void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type FC, useEffect } from 'react';
|
|
2
|
-
import { QRCodeSVG } from 'qrcode.react';
|
|
1
|
+
import { type FC, useEffect, useMemo } from 'react';
|
|
3
2
|
import { isMobileDevice, tryOpenDeepLink } from '../utils/platform';
|
|
4
3
|
import { CONNECTOR_META } from '../connector-meta';
|
|
5
4
|
import { type ConnectorId } from '../types';
|
|
5
|
+
import { QRFrame } from '../components/QRFrame';
|
|
6
6
|
|
|
7
7
|
interface CreditWalletViewProps {
|
|
8
8
|
connectorId: Extract<ConnectorId, 'CREDIT_CONNECT' | 'CREDIT_WALLET'>;
|
|
@@ -11,7 +11,7 @@ interface CreditWalletViewProps {
|
|
|
11
11
|
|
|
12
12
|
export const CreditWalletView: FC<CreditWalletViewProps> = ({ connectorId, qrUri }) => {
|
|
13
13
|
const { downloadUrl, logoUrl, deepLinkBase } = CONNECTOR_META[connectorId];
|
|
14
|
-
const isMobile = isMobileDevice();
|
|
14
|
+
const isMobile = useMemo(() => isMobileDevice(), []);
|
|
15
15
|
|
|
16
16
|
useEffect(() => {
|
|
17
17
|
if (isMobile && qrUri && deepLinkBase) {
|
|
@@ -29,20 +29,7 @@ export const CreditWalletView: FC<CreditWalletViewProps> = ({ connectorId, qrUri
|
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
31
|
<div className="ck-view ck-view--qr">
|
|
32
|
-
<
|
|
33
|
-
{qrUri ? (
|
|
34
|
-
<QRCodeSVG
|
|
35
|
-
value={qrUri}
|
|
36
|
-
size={196}
|
|
37
|
-
level="H"
|
|
38
|
-
imageSettings={
|
|
39
|
-
logoUrl ? { src: logoUrl, width: 40, height: 40, excavate: true } : undefined
|
|
40
|
-
}
|
|
41
|
-
/>
|
|
42
|
-
) : (
|
|
43
|
-
<div className="ck-qr-spinner" aria-label="Loading QR code" />
|
|
44
|
-
)}
|
|
45
|
-
</div>
|
|
32
|
+
<QRFrame qrUri={qrUri} logoUrl={logoUrl} />
|
|
46
33
|
|
|
47
34
|
<p className="ck-view__caption">Open the Credit Wallet app and scan the QR</p>
|
|
48
35
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type FC, useEffect } from 'react';
|
|
2
|
-
import { QRCodeSVG } from 'qrcode.react';
|
|
1
|
+
import { type FC, useEffect, useMemo } from 'react';
|
|
3
2
|
import { isMobileDevice, tryOpenDeepLink } from '../utils/platform';
|
|
4
3
|
import { CONNECTOR_META } from '../connector-meta';
|
|
4
|
+
import { QRFrame, CopyLinkButton } from '../components/QRFrame';
|
|
5
5
|
|
|
6
6
|
const { downloadUrl, deepLinkBase } = CONNECTOR_META.METAMASK;
|
|
7
7
|
|
|
@@ -12,7 +12,7 @@ interface MetaMaskViewProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const MetaMaskView: FC<MetaMaskViewProps> = ({ qrUri, hasExtension, logoUrl }) => {
|
|
15
|
-
const isMobile = isMobileDevice();
|
|
15
|
+
const isMobile = useMemo(() => isMobileDevice(), []);
|
|
16
16
|
|
|
17
17
|
useEffect(() => {
|
|
18
18
|
if (isMobile && qrUri && deepLinkBase) {
|
|
@@ -41,33 +41,8 @@ export const MetaMaskView: FC<MetaMaskViewProps> = ({ qrUri, hasExtension, logoU
|
|
|
41
41
|
|
|
42
42
|
return (
|
|
43
43
|
<div className="ck-view ck-view--qr">
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
<QRCodeSVG
|
|
47
|
-
value={qrUri}
|
|
48
|
-
size={196}
|
|
49
|
-
level="H"
|
|
50
|
-
imageSettings={
|
|
51
|
-
logoUrl ? { src: logoUrl, width: 40, height: 40, excavate: true } : undefined
|
|
52
|
-
}
|
|
53
|
-
/>
|
|
54
|
-
) : (
|
|
55
|
-
<div className="ck-qr-spinner" aria-label="Loading QR code" />
|
|
56
|
-
)}
|
|
57
|
-
</div>
|
|
58
|
-
|
|
59
|
-
{qrUri && (
|
|
60
|
-
<button
|
|
61
|
-
type="button"
|
|
62
|
-
className="ck-copy-link"
|
|
63
|
-
onClick={() => {
|
|
64
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
65
|
-
navigator.clipboard.writeText(qrUri);
|
|
66
|
-
}}
|
|
67
|
-
>
|
|
68
|
-
Copy link
|
|
69
|
-
</button>
|
|
70
|
-
)}
|
|
44
|
+
<QRFrame qrUri={qrUri} logoUrl={logoUrl} />
|
|
45
|
+
<CopyLinkButton qrUri={qrUri} />
|
|
71
46
|
|
|
72
47
|
{downloadUrl && (
|
|
73
48
|
<div className="ck-download-card">
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type FC, useMemo } from 'react';
|
|
2
|
-
import { QRCodeSVG } from 'qrcode.react';
|
|
3
2
|
import { isMobileDevice, tryOpenDeepLink } from '../utils/platform';
|
|
4
3
|
import { type WCWallet, type WCSubView } from '../types';
|
|
5
4
|
import deeplink from '../../assets/deeplink.png';
|
|
5
|
+
import { QRFrame, CopyLinkButton } from '../components/QRFrame';
|
|
6
|
+
import { CONNECTOR_META } from '../connector-meta';
|
|
6
7
|
|
|
7
8
|
interface WalletConnectViewProps {
|
|
8
9
|
subView: WCSubView;
|
|
@@ -30,42 +31,11 @@ export const WalletConnectView: FC<WalletConnectViewProps> = (props) => {
|
|
|
30
31
|
|
|
31
32
|
const WCQRView: FC<WalletConnectViewProps> = ({ qrUri, logoUrl, walletList, onShowList }) => (
|
|
32
33
|
<div className="ck-view ck-view--qr">
|
|
33
|
-
<
|
|
34
|
-
{qrUri ? (
|
|
35
|
-
<QRCodeSVG
|
|
36
|
-
value={qrUri}
|
|
37
|
-
size={196}
|
|
38
|
-
level="H"
|
|
39
|
-
imageSettings={
|
|
40
|
-
logoUrl
|
|
41
|
-
? {
|
|
42
|
-
src: logoUrl,
|
|
43
|
-
width: 40,
|
|
44
|
-
height: 40,
|
|
45
|
-
excavate: true,
|
|
46
|
-
}
|
|
47
|
-
: undefined
|
|
48
|
-
}
|
|
49
|
-
/>
|
|
50
|
-
) : (
|
|
51
|
-
<div className="ck-qr-spinner" aria-label="Loading QR code" />
|
|
52
|
-
)}
|
|
53
|
-
</div>
|
|
34
|
+
<QRFrame qrUri={qrUri} logoUrl={logoUrl} />
|
|
54
35
|
|
|
55
36
|
<p className="ck-view__caption">Scan this QR Code with your phone</p>
|
|
56
37
|
|
|
57
|
-
{qrUri
|
|
58
|
-
<button
|
|
59
|
-
type="button"
|
|
60
|
-
className="ck-copy-link"
|
|
61
|
-
onClick={() => {
|
|
62
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
63
|
-
navigator.clipboard.writeText(qrUri);
|
|
64
|
-
}}
|
|
65
|
-
>
|
|
66
|
-
Copy link
|
|
67
|
-
</button>
|
|
68
|
-
)}
|
|
38
|
+
<CopyLinkButton qrUri={qrUri} />
|
|
69
39
|
|
|
70
40
|
<button type="button" className="ck-all-wallets-btn" onClick={onShowList}>
|
|
71
41
|
<span className="ck-all-wallets-btn__icon" aria-hidden="true" />
|
|
@@ -77,7 +47,7 @@ const WCQRView: FC<WalletConnectViewProps> = ({ qrUri, logoUrl, walletList, onSh
|
|
|
77
47
|
</div>
|
|
78
48
|
);
|
|
79
49
|
|
|
80
|
-
const CREDIT_WALLET_NAME =
|
|
50
|
+
const CREDIT_WALLET_NAME = CONNECTOR_META.CREDIT_WALLET.label;
|
|
81
51
|
|
|
82
52
|
const WalletListView: FC<WalletConnectViewProps> = ({
|
|
83
53
|
walletList,
|
|
@@ -90,7 +60,7 @@ const WalletListView: FC<WalletConnectViewProps> = ({
|
|
|
90
60
|
onSearchChange,
|
|
91
61
|
onFilterToggle,
|
|
92
62
|
}) => {
|
|
93
|
-
const isMobile = isMobileDevice();
|
|
63
|
+
const isMobile = useMemo(() => isMobileDevice(), []);
|
|
94
64
|
|
|
95
65
|
const filtered = useMemo(() => {
|
|
96
66
|
const q = walletListSearch.trim().toLowerCase();
|
|
@@ -111,11 +81,10 @@ const WalletListView: FC<WalletConnectViewProps> = ({
|
|
|
111
81
|
}, [walletList, walletListSearch, walletListFilterActive]);
|
|
112
82
|
|
|
113
83
|
const handleClickWallet = (wallet: WCWallet): void => {
|
|
114
|
-
|
|
115
|
-
if (isMobile && uri) {
|
|
84
|
+
if (isMobile && qrUri) {
|
|
116
85
|
const target = wallet.mobileNative || wallet.mobileUniversal;
|
|
117
86
|
if (target) {
|
|
118
|
-
tryOpenDeepLink(
|
|
87
|
+
tryOpenDeepLink(qrUri, target);
|
|
119
88
|
return;
|
|
120
89
|
}
|
|
121
90
|
}
|
|
@@ -211,40 +180,11 @@ const WalletQRView: FC<{ wallet: WCWallet; qrUri: string | null }> = ({ wallet,
|
|
|
211
180
|
|
|
212
181
|
return (
|
|
213
182
|
<div className="ck-view ck-view--qr">
|
|
214
|
-
<
|
|
215
|
-
{qrUri ? (
|
|
216
|
-
<QRCodeSVG
|
|
217
|
-
value={qrUri}
|
|
218
|
-
size={196}
|
|
219
|
-
level="H"
|
|
220
|
-
{...(logoSrc && {
|
|
221
|
-
imageSettings: {
|
|
222
|
-
src: logoSrc,
|
|
223
|
-
width: 40,
|
|
224
|
-
height: 40,
|
|
225
|
-
excavate: true,
|
|
226
|
-
},
|
|
227
|
-
})}
|
|
228
|
-
/>
|
|
229
|
-
) : (
|
|
230
|
-
<div className="ck-qr-spinner" aria-label="Loading QR code" />
|
|
231
|
-
)}
|
|
232
|
-
</div>
|
|
183
|
+
<QRFrame qrUri={qrUri} logoUrl={logoSrc} />
|
|
233
184
|
|
|
234
185
|
<p className="ck-view__caption">Scan this QR Code with your phone</p>
|
|
235
186
|
|
|
236
|
-
{qrUri
|
|
237
|
-
<button
|
|
238
|
-
type="button"
|
|
239
|
-
className="ck-copy-link"
|
|
240
|
-
onClick={() => {
|
|
241
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
242
|
-
navigator.clipboard.writeText(qrUri);
|
|
243
|
-
}}
|
|
244
|
-
>
|
|
245
|
-
Copy link
|
|
246
|
-
</button>
|
|
247
|
-
)}
|
|
187
|
+
<CopyLinkButton qrUri={qrUri} />
|
|
248
188
|
|
|
249
189
|
{downloadUrl && (
|
|
250
190
|
<div className="ck-download-card">
|
package/tsup.config.ts
CHANGED
|
@@ -7,7 +7,18 @@ export default defineConfig({
|
|
|
7
7
|
dts: true,
|
|
8
8
|
clean: true,
|
|
9
9
|
target: 'es2019',
|
|
10
|
-
external: [
|
|
10
|
+
external: [
|
|
11
|
+
'react',
|
|
12
|
+
'react-native',
|
|
13
|
+
'wagmi',
|
|
14
|
+
'@wagmi/core',
|
|
15
|
+
'viem',
|
|
16
|
+
'@gluwa/credit-connect-sdk',
|
|
17
|
+
'@gluwa/credit-connect-sdk/dapp',
|
|
18
|
+
'@gluwa/credit-connect-sdk/storage',
|
|
19
|
+
'@gluwa/credit-connect-sdk/e2ee',
|
|
20
|
+
'@gluwa/credit-connect-sdk/hub',
|
|
21
|
+
],
|
|
11
22
|
banner: {
|
|
12
23
|
js: 'import React from "react";',
|
|
13
24
|
},
|