@gluwa/connect-kit 0.2.0-next.1 → 0.2.0-next.10
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 +62 -0
- package/assets/fonts/Inter-Medium.ttf +0 -0
- package/assets/fonts/Inter-Medium.woff2 +0 -0
- package/assets/fonts/Inter-Regular.ttf +0 -0
- package/assets/fonts/Inter-Regular.woff2 +0 -0
- package/assets/fonts/Inter-SemiBold.ttf +0 -0
- package/assets/fonts/Inter-SemiBold.woff2 +0 -0
- package/assets/graphic.png +0 -0
- package/assets/metamask.png +0 -0
- package/assets/penguinwallet.png +0 -0
- package/assets/wc-logo.svg +3 -0
- package/assets/wc-search.png +0 -0
- package/dist/chunk-VE5LB7BN.js +405 -0
- package/dist/credit-connect.js +2 -409
- package/dist/index.css +1903 -389
- package/dist/index.d.ts +21 -10
- package/dist/index.js +1507 -922
- package/dist/package.json +7 -6
- package/package.json +8 -8
- package/src/ConnectKitProvider.tsx +97 -65
- package/src/api/asset.ts +10 -0
- package/src/assets.d.ts +5 -0
- package/src/components/actionItem/index.tsx +50 -0
- package/src/components/actionItem/style.scss +47 -0
- package/src/components/copyLink/index.tsx +16 -0
- package/src/components/copyLink/style.scss +16 -0
- package/src/components/qrArea/index.tsx +72 -0
- package/src/components/qrArea/style.scss +122 -0
- package/src/components/searchBar/asset/Search.tsx +20 -0
- package/src/components/searchBar/asset/XMarkCircle.tsx +24 -0
- package/src/components/searchBar/index.tsx +44 -0
- package/src/components/searchBar/style.scss +58 -0
- package/src/components/toast/index.tsx +41 -0
- package/src/components/toast/style.scss +108 -0
- package/src/components/toggle/index.tsx +27 -0
- package/src/components/toggle/style.scss +53 -0
- package/src/components/walletGrid/index.tsx +64 -0
- package/src/components/walletGrid/style.scss +108 -0
- package/src/components/walletItem/index.tsx +49 -0
- package/src/components/walletItem/style.scss +70 -0
- package/src/connector-meta.ts +16 -11
- package/src/core/config.ts +20 -1
- package/src/creditConnectConnector.ts +23 -25
- package/src/events/account.ts +30 -3
- package/src/hooks/useConnectBanner.ts +79 -0
- package/src/hooks/useConnectTimeout.ts +92 -0
- package/src/hooks/useMetaMaskExtension.ts +29 -0
- package/src/hooks/useWCState.ts +21 -5
- package/src/hooks/useWagmiConnect.ts +35 -9
- package/src/index.ts +5 -2
- package/src/layout/allWallets/index.tsx +52 -0
- package/src/layout/allWallets/style.scss +57 -0
- package/src/layout/connectDialog/asset/backIcon.tsx +24 -0
- package/src/layout/connectDialog/asset/checkIcon.tsx +28 -0
- package/src/layout/connectDialog/asset/closeIcon.tsx +21 -0
- package/src/layout/connectDialog/asset/copyIcon.tsx +28 -0
- package/src/layout/connectDialog/asset/linkIcon.tsx +24 -0
- package/src/layout/connectDialog/asset/spinner.tsx +21 -0
- package/src/layout/connectDialog/asset/warningIcon.tsx +21 -0
- package/src/layout/connectDialog/idle/assets/banner-placeholder.png +0 -0
- package/src/layout/connectDialog/idle/index.tsx +55 -0
- package/src/layout/connectDialog/idle/style.scss +52 -0
- package/src/layout/connectDialog/index.tsx +432 -0
- package/src/layout/connectDialog/loading/index.tsx +13 -0
- package/src/layout/connectDialog/loading/style.scss +19 -0
- package/src/layout/connectDialog/metaMask/index.tsx +61 -0
- package/src/layout/connectDialog/metaMask/style.scss +65 -0
- package/src/layout/connectDialog/qr/index.tsx +33 -0
- package/src/layout/connectDialog/style.scss +48 -0
- package/src/layout/connectDialog/timeout/index.tsx +31 -0
- package/src/layout/connectDialog/timeout/style.scss +64 -0
- package/src/layout/connectDialog/walletConnect/index.tsx +45 -0
- package/src/layout/connectDialog/walletConnect/style.scss +48 -0
- package/src/layout/connectDialog/walletQR/index.tsx +37 -0
- package/src/layout/detailPanel/index.tsx +175 -0
- package/src/layout/detailPanel/style.scss +70 -0
- package/src/layout/selectorPanel/index.tsx +100 -0
- package/src/layout/selectorPanel/style.scss +113 -0
- package/src/style/color.scss +417 -0
- package/src/style/font.scss +28 -0
- package/src/style/index.scss +5 -0
- package/src/style/mixin.scss +217 -0
- package/src/style/reset.scss +110 -0
- package/src/style/variables.scss +13 -0
- package/src/types.ts +32 -8
- package/src/utils/platform.ts +5 -3
- package/src/wallet-display-override.ts +15 -0
- package/tsconfig.json +5 -1
- package/tsup.config.ts +32 -2
- package/assets/creditwallet.png +0 -0
- package/dist/chunk-DDA6FP6U.js +0 -7
- package/src/ConnectModal.scss +0 -665
- package/src/ConnectModal.tsx +0 -573
- package/src/components/QRFrame.tsx +0 -43
- package/src/views/CreditWalletView.tsx +0 -58
- package/src/views/IdleView.tsx +0 -10
- package/src/views/MetaMaskView.tsx +0 -66
- package/src/views/SwitchChainView.tsx +0 -72
- package/src/views/WalletConnectView.tsx +0 -206
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.2.0-next.
|
|
3
|
+
"version": "0.2.0-next.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"types": "./src/credit-connect.ts",
|
|
12
12
|
"default": "./src/credit-connect.ts"
|
|
13
13
|
},
|
|
14
|
+
"./index.css": "./dist/index.css",
|
|
14
15
|
"./package.json": "./package.json"
|
|
15
16
|
},
|
|
16
17
|
"publishConfig": {
|
|
@@ -45,7 +46,11 @@
|
|
|
45
46
|
"dependencies": {
|
|
46
47
|
"qrcode.react": "^4.2.0",
|
|
47
48
|
"wagmi": "^2.15.6",
|
|
48
|
-
"@wagmi/core": "^2.16.7"
|
|
49
|
+
"@wagmi/core": "^2.16.7",
|
|
50
|
+
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
51
|
+
"@gluwa/credit-connect-storage-local": "workspace:*",
|
|
52
|
+
"@gluwa/credit-connect-e2ee-tweetnacl": "workspace:*",
|
|
53
|
+
"@gluwa/credit-connect-hub-node-ws": "workspace:*"
|
|
49
54
|
},
|
|
50
55
|
"devDependencies": {
|
|
51
56
|
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
@@ -62,15 +67,11 @@
|
|
|
62
67
|
"wagmi": "^2.15.6"
|
|
63
68
|
},
|
|
64
69
|
"peerDependencies": {
|
|
65
|
-
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
66
70
|
"@tanstack/react-query": ">=5.0.0",
|
|
67
71
|
"react": "^18.0.0 || ^19.0.0",
|
|
68
72
|
"viem": ">=2.0.0"
|
|
69
73
|
},
|
|
70
74
|
"peerDependenciesMeta": {
|
|
71
|
-
"@gluwa/credit-connect-sdk": {
|
|
72
|
-
"optional": true
|
|
73
|
-
},
|
|
74
75
|
"@tanstack/react-query": {
|
|
75
76
|
"optional": true
|
|
76
77
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.2.0-next.
|
|
3
|
+
"version": "0.2.0-next.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -25,7 +25,11 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"qrcode.react": "^4.2.0",
|
|
27
27
|
"wagmi": "^2.15.6",
|
|
28
|
-
"@wagmi/core": "^2.16.7"
|
|
28
|
+
"@wagmi/core": "^2.16.7",
|
|
29
|
+
"@gluwa/credit-connect-sdk": "0.2.0-next.5",
|
|
30
|
+
"@gluwa/credit-connect-storage-local": "0.2.0-next.5",
|
|
31
|
+
"@gluwa/credit-connect-e2ee-tweetnacl": "0.2.0-next.5",
|
|
32
|
+
"@gluwa/credit-connect-hub-node-ws": "0.1.0-next.5"
|
|
29
33
|
},
|
|
30
34
|
"devDependencies": {
|
|
31
35
|
"@tanstack/react-query": "^5.62.0",
|
|
@@ -39,18 +43,14 @@
|
|
|
39
43
|
"typescript-eslint": "^8.18.2",
|
|
40
44
|
"viem": "^2.31.7",
|
|
41
45
|
"wagmi": "^2.15.6",
|
|
42
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.
|
|
46
|
+
"@gluwa/credit-connect-sdk": "0.2.0-next.5"
|
|
43
47
|
},
|
|
44
48
|
"peerDependencies": {
|
|
45
49
|
"@tanstack/react-query": ">=5.0.0",
|
|
46
50
|
"react": "^18.0.0 || ^19.0.0",
|
|
47
|
-
"viem": ">=2.0.0"
|
|
48
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.1"
|
|
51
|
+
"viem": ">=2.0.0"
|
|
49
52
|
},
|
|
50
53
|
"peerDependenciesMeta": {
|
|
51
|
-
"@gluwa/credit-connect-sdk": {
|
|
52
|
-
"optional": true
|
|
53
|
-
},
|
|
54
54
|
"@tanstack/react-query": {
|
|
55
55
|
"optional": true
|
|
56
56
|
}
|
|
@@ -9,15 +9,21 @@ import {
|
|
|
9
9
|
type FC,
|
|
10
10
|
type ReactNode,
|
|
11
11
|
} from 'react';
|
|
12
|
-
import { WagmiProvider, useAccount, useDisconnect, useSwitchChain } from 'wagmi';
|
|
12
|
+
import { WagmiProvider, useAccount, useConfig, useDisconnect, useSwitchChain } from 'wagmi';
|
|
13
|
+
import { getAccount } from '@wagmi/core';
|
|
13
14
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
14
|
-
import { ConnectModal } from './ConnectModal';
|
|
15
|
+
// import { ConnectModal } from './ConnectModal';
|
|
16
|
+
import { ConnectDialog } from './layout/connectDialog';
|
|
15
17
|
import { getConfig, getKitConfig, initConfig } from './core/config';
|
|
18
|
+
import { resolveConnectorId } from './connector-meta';
|
|
16
19
|
import type {
|
|
17
20
|
ConnectErrorContext,
|
|
21
|
+
ConnectBannerSiteKey,
|
|
18
22
|
ConnectKitConfig,
|
|
23
|
+
ConnectKitTheme,
|
|
19
24
|
ConnectResult,
|
|
20
25
|
ConnectorId,
|
|
26
|
+
ConnectorKey,
|
|
21
27
|
Connectors,
|
|
22
28
|
} from './types';
|
|
23
29
|
|
|
@@ -25,19 +31,26 @@ const internalQueryClient = new QueryClient();
|
|
|
25
31
|
|
|
26
32
|
export interface ConnectKitProviderProps {
|
|
27
33
|
children: ReactNode;
|
|
34
|
+
siteKey: ConnectBannerSiteKey;
|
|
35
|
+
connectBannerUrl: string;
|
|
28
36
|
kitConfig?: ConnectKitConfig;
|
|
29
37
|
connectors: Connectors;
|
|
30
38
|
requiredChainId?: number;
|
|
39
|
+
theme: ConnectKitTheme;
|
|
31
40
|
onConnect?: (result: ConnectResult) => void;
|
|
32
41
|
onLog?: (message: string, error?: Error) => void;
|
|
33
42
|
renderConnectError?: (ctx: ConnectErrorContext) => ReactNode;
|
|
34
43
|
}
|
|
35
|
-
|
|
36
44
|
export interface ConnectKitContextValue {
|
|
37
45
|
isOpen: boolean;
|
|
38
46
|
open: () => void;
|
|
39
47
|
close: () => void;
|
|
40
48
|
isConnected: boolean;
|
|
49
|
+
needsChainSwitch: boolean;
|
|
50
|
+
requiredChainId: number | undefined;
|
|
51
|
+
currentChainId: number | undefined;
|
|
52
|
+
isSwitchingChain: boolean;
|
|
53
|
+
switchToRequiredChain: () => Promise<void>;
|
|
41
54
|
address: `0x${string}` | undefined;
|
|
42
55
|
connectorId: ConnectorId | null;
|
|
43
56
|
disconnect: () => Promise<void>;
|
|
@@ -45,14 +58,16 @@ export interface ConnectKitContextValue {
|
|
|
45
58
|
|
|
46
59
|
const ConnectKitContext = createContext<ConnectKitContextValue | null>(null);
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
// 외부 API Connectors (ConnectorKey 배열) → 내부 ConnectorId[] 매핑.
|
|
62
|
+
// 입력 순서 그대로 selector 표시 순서.
|
|
63
|
+
const CONNECTOR_KEY_TO_ID: Record<ConnectorKey, ConnectorId> = {
|
|
64
|
+
creditWallet: 'CREDIT_CONNECT',
|
|
65
|
+
metamask: 'METAMASK',
|
|
66
|
+
walletConnect: 'WALLET_CONNECT',
|
|
67
|
+
};
|
|
68
|
+
const resolveConnectorsFromConfig = (connectorsConfig?: Connectors): ConnectorId[] => {
|
|
69
|
+
if (!connectorsConfig) return [];
|
|
70
|
+
return connectorsConfig.map((key) => CONNECTOR_KEY_TO_ID[key]);
|
|
56
71
|
};
|
|
57
72
|
|
|
58
73
|
export const ConnectKitProvider: FC<ConnectKitProviderProps> = (props) => {
|
|
@@ -78,17 +93,22 @@ type ConnectKitProviderInnerProps = Omit<ConnectKitProviderProps, 'kitConfig'> &
|
|
|
78
93
|
|
|
79
94
|
const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
80
95
|
children,
|
|
96
|
+
siteKey,
|
|
97
|
+
connectBannerUrl,
|
|
81
98
|
connectors,
|
|
82
99
|
kitConfig,
|
|
83
100
|
requiredChainId,
|
|
101
|
+
theme,
|
|
84
102
|
onConnect,
|
|
85
103
|
onLog,
|
|
86
|
-
renderConnectError,
|
|
87
104
|
}) => {
|
|
105
|
+
// NOTE: renderConnectError 는 ConnectDialog 가 아직 error UI customization 을 받지 않으므로
|
|
106
|
+
// destructure 에서 제외. 추후 ConnectDialog 의 timeout/error content 에 wire 필요 시 복원.
|
|
88
107
|
const [isOpen, setIsOpen] = useState(false);
|
|
89
108
|
const [pendingResult, setPendingResult] = useState<ConnectResult | null>(null);
|
|
90
109
|
|
|
91
110
|
const account = useAccount();
|
|
111
|
+
const wagmiConfig = useConfig();
|
|
92
112
|
const { disconnectAsync } = useDisconnect();
|
|
93
113
|
const { switchChainAsync } = useSwitchChain();
|
|
94
114
|
|
|
@@ -97,14 +117,6 @@ const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
|
97
117
|
onConnectRef.current = onConnect;
|
|
98
118
|
}, [onConnect]);
|
|
99
119
|
|
|
100
|
-
const chainMismatch =
|
|
101
|
-
requiredChainId != null &&
|
|
102
|
-
account.status === 'connected' &&
|
|
103
|
-
account.chainId != null &&
|
|
104
|
-
account.chainId !== requiredChainId;
|
|
105
|
-
|
|
106
|
-
const [autoSwitchFailedKey, setAutoSwitchFailedKey] = useState<string | null>(null);
|
|
107
|
-
const autoSwitchInFlightRef = useRef(false);
|
|
108
120
|
const isMountedRef = useRef(true);
|
|
109
121
|
useEffect(() => {
|
|
110
122
|
isMountedRef.current = true;
|
|
@@ -113,39 +125,15 @@ const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
|
113
125
|
};
|
|
114
126
|
}, []);
|
|
115
127
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
const needsChainSwitch =
|
|
129
|
+
requiredChainId != null &&
|
|
130
|
+
account.status === 'connected' &&
|
|
131
|
+
account.chainId != null &&
|
|
132
|
+
account.chainId !== requiredChainId;
|
|
120
133
|
|
|
121
|
-
|
|
122
|
-
if (!chainMismatch || requiredChainId == null) return;
|
|
123
|
-
if (autoSwitchInFlightRef.current) return;
|
|
124
|
-
if (mismatchKey != null && mismatchKey === autoSwitchFailedKey) return;
|
|
125
|
-
|
|
126
|
-
autoSwitchInFlightRef.current = true;
|
|
127
|
-
switchChainAsync({ chainId: requiredChainId })
|
|
128
|
-
.catch((err: unknown) => {
|
|
129
|
-
if (!isMountedRef.current) return;
|
|
130
|
-
const normalized = err instanceof Error ? err : new Error(String(err));
|
|
131
|
-
onLog?.(`[connect-kit] silent switch chain failed: ${normalized.message}`, normalized);
|
|
132
|
-
if (mismatchKey != null) {
|
|
133
|
-
setAutoSwitchFailedKey(mismatchKey);
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
.finally(() => {
|
|
137
|
-
autoSwitchInFlightRef.current = false;
|
|
138
|
-
});
|
|
139
|
-
}, [chainMismatch, mismatchKey, requiredChainId, autoSwitchFailedKey, switchChainAsync, onLog]);
|
|
134
|
+
const [isSwitchingChain, setIsSwitchingChain] = useState(false);
|
|
140
135
|
|
|
141
|
-
|
|
142
|
-
if (!chainMismatch && autoSwitchFailedKey != null) {
|
|
143
|
-
setAutoSwitchFailedKey(null);
|
|
144
|
-
}
|
|
145
|
-
}, [chainMismatch, autoSwitchFailedKey]);
|
|
146
|
-
|
|
147
|
-
const autoSwitchFailedForCurrent = mismatchKey != null && mismatchKey === autoSwitchFailedKey;
|
|
148
|
-
const effectiveOpen = isOpen || (chainMismatch && autoSwitchFailedForCurrent);
|
|
136
|
+
const effectiveOpen = isOpen;
|
|
149
137
|
|
|
150
138
|
const open = useCallback((): void => {
|
|
151
139
|
setIsOpen(true);
|
|
@@ -153,29 +141,62 @@ const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
|
153
141
|
|
|
154
142
|
const close = useCallback((): void => {
|
|
155
143
|
setIsOpen(false);
|
|
156
|
-
|
|
144
|
+
const status = getAccount(wagmiConfig).status;
|
|
145
|
+
if (status === 'connecting' || status === 'reconnecting') {
|
|
146
|
+
disconnectAsync().catch(() => undefined);
|
|
147
|
+
}
|
|
148
|
+
}, [wagmiConfig, disconnectAsync]);
|
|
157
149
|
|
|
158
150
|
const disconnect = useCallback(async (): Promise<void> => {
|
|
159
151
|
await disconnectAsync();
|
|
160
152
|
}, [disconnectAsync]);
|
|
161
153
|
|
|
162
|
-
const
|
|
154
|
+
const switchToRequiredChain = useCallback(async (): Promise<void> => {
|
|
155
|
+
if (requiredChainId == null) return;
|
|
156
|
+
setIsSwitchingChain(true);
|
|
157
|
+
try {
|
|
158
|
+
await switchChainAsync({ chainId: requiredChainId });
|
|
159
|
+
} finally {
|
|
160
|
+
if (isMountedRef.current) setIsSwitchingChain(false);
|
|
161
|
+
}
|
|
162
|
+
}, [requiredChainId, switchChainAsync]);
|
|
163
|
+
|
|
164
|
+
// ConnectDialog 의 wagmi connect 성공 → pendingResult set → 아래 useEffect 가
|
|
165
|
+
// account.status === 'connected' 확인 후 외부 onConnect 호출 + modal close.
|
|
166
|
+
// wagmi state 가 비동기로 'connected' 로 전환되는 race 흡수용.
|
|
167
|
+
const handleDialogConnect = useCallback((result: ConnectResult): void => {
|
|
163
168
|
setPendingResult(result);
|
|
164
169
|
}, []);
|
|
165
170
|
|
|
166
|
-
|
|
171
|
+
const handleDialogError = useCallback(
|
|
172
|
+
(error: Error, connectorId: ConnectorId): void => {
|
|
173
|
+
onLog?.(`[connect-kit] connect failed: ${connectorId} — ${error.message}`, error);
|
|
174
|
+
},
|
|
175
|
+
[onLog],
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// 연결 성공 시 modal 자동 close — wagmi state 만 기준으로.
|
|
179
|
+
// 이전 구현은 pendingResult 가 set 된 경우만 close 했는데, `setPendingResult` 는
|
|
180
|
+
// ConnectDialog 의 onConnect (`connectAsync.then`) 안에서만 호출됨. MM deeplink 같은
|
|
181
|
+
// 시나리오 (앱 이동 → 승인 → 복귀) 에서 wagmi 가 자체적으로 'connected' 로 전이하지만
|
|
182
|
+
// connectAsync 의 promise 는 resolve 안 될 수 있음 → pendingResult set 안 됨 → modal 안 닫힘.
|
|
183
|
+
// 모든 connector (WC/CC/MM) 의 connected 가 일관된 close 트리거가 되도록 단순화.
|
|
184
|
+
useEffect((): void => {
|
|
185
|
+
if (!effectiveOpen) return;
|
|
186
|
+
if (account.status !== 'connected') return;
|
|
187
|
+
setIsOpen(false);
|
|
188
|
+
}, [effectiveOpen, account.status]);
|
|
189
|
+
|
|
190
|
+
// 외부 onConnect 콜백은 best-effort — pendingResult 가 set 된 경우만 호출.
|
|
191
|
+
useEffect((): void => {
|
|
167
192
|
if (!pendingResult) return;
|
|
168
193
|
if (account.status !== 'connected') {
|
|
169
194
|
setPendingResult(null);
|
|
170
195
|
return;
|
|
171
196
|
}
|
|
172
|
-
if (requiredChainId != null && account.chainId !== requiredChainId) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
197
|
onConnectRef.current?.(pendingResult);
|
|
176
198
|
setPendingResult(null);
|
|
177
|
-
|
|
178
|
-
}, [pendingResult, account.status, account.chainId, requiredChainId]);
|
|
199
|
+
}, [pendingResult, account.status]);
|
|
179
200
|
|
|
180
201
|
const value = useMemo<ConnectKitContextValue>(
|
|
181
202
|
() => ({
|
|
@@ -183,6 +204,11 @@ const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
|
183
204
|
open,
|
|
184
205
|
close,
|
|
185
206
|
isConnected: account.status === 'connected',
|
|
207
|
+
needsChainSwitch,
|
|
208
|
+
requiredChainId,
|
|
209
|
+
currentChainId: account.chainId,
|
|
210
|
+
isSwitchingChain,
|
|
211
|
+
switchToRequiredChain,
|
|
186
212
|
address: account.address,
|
|
187
213
|
connectorId: resolveConnectorId(account.connector?.id),
|
|
188
214
|
disconnect,
|
|
@@ -192,6 +218,11 @@ const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
|
192
218
|
open,
|
|
193
219
|
close,
|
|
194
220
|
account.status,
|
|
221
|
+
needsChainSwitch,
|
|
222
|
+
requiredChainId,
|
|
223
|
+
account.chainId,
|
|
224
|
+
isSwitchingChain,
|
|
225
|
+
switchToRequiredChain,
|
|
195
226
|
account.address,
|
|
196
227
|
account.connector?.id,
|
|
197
228
|
disconnect,
|
|
@@ -201,15 +232,16 @@ const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
|
201
232
|
return (
|
|
202
233
|
<ConnectKitContext.Provider value={value}>
|
|
203
234
|
{children}
|
|
204
|
-
<
|
|
235
|
+
<ConnectDialog
|
|
205
236
|
open={effectiveOpen}
|
|
206
|
-
|
|
237
|
+
siteKey={siteKey}
|
|
238
|
+
connectBannerUrl={connectBannerUrl}
|
|
239
|
+
theme={theme}
|
|
240
|
+
connectors={resolveConnectorsFromConfig(connectors)}
|
|
207
241
|
wcProjectId={kitConfig.wcProjectId}
|
|
208
|
-
requiredChainId={requiredChainId}
|
|
209
|
-
renderConnectError={renderConnectError}
|
|
210
|
-
onConnect={handleModalConnect}
|
|
211
242
|
onClose={close}
|
|
212
|
-
|
|
243
|
+
onConnect={handleDialogConnect}
|
|
244
|
+
onError={handleDialogError}
|
|
213
245
|
/>
|
|
214
246
|
</ConnectKitContext.Provider>
|
|
215
247
|
);
|
package/src/api/asset.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
watchAsset as wagmiWatchAsset,
|
|
3
|
+
type WatchAssetParameters,
|
|
4
|
+
type WatchAssetReturnType,
|
|
5
|
+
} from '@wagmi/core';
|
|
6
|
+
import { getConfig } from '../core/config';
|
|
7
|
+
|
|
8
|
+
export const watchAsset = (params: WatchAssetParameters): Promise<WatchAssetReturnType> => {
|
|
9
|
+
return wagmiWatchAsset(getConfig(), params);
|
|
10
|
+
};
|
package/src/assets.d.ts
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type ReactNode, type AnchorHTMLAttributes, type ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import './style.scss';
|
|
3
|
+
|
|
4
|
+
interface ActionItemContent {
|
|
5
|
+
label?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
action?: string;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type ActionItemAsAnchor = { as: 'a' } & AnchorHTMLAttributes<HTMLAnchorElement> & ActionItemContent;
|
|
12
|
+
type ActionItemAsButton = { as: 'button' } & ButtonHTMLAttributes<HTMLButtonElement> &
|
|
13
|
+
ActionItemContent;
|
|
14
|
+
|
|
15
|
+
type ActionItemProps = ActionItemAsAnchor | ActionItemAsButton;
|
|
16
|
+
|
|
17
|
+
const ActionItemBody = ({ label, description, action, children }: ActionItemContent): ReactNode => {
|
|
18
|
+
if (children) return <>{children}</>;
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<span className="ck-action-item-content">
|
|
22
|
+
<span className="ck-action-item-label">{label}</span>
|
|
23
|
+
{description && <span className="ck-action-item-desc">{description}</span>}
|
|
24
|
+
</span>
|
|
25
|
+
{action && <span className="ck-action-item-action">{action}</span>}
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const ActionItem = (props: ActionItemProps) => {
|
|
31
|
+
if (props.as === 'a') {
|
|
32
|
+
const { as: _, label, description, action, children, className, ...rest } = props;
|
|
33
|
+
return (
|
|
34
|
+
<a className={`ck-action-item${className ? ` ${className}` : ''}`} {...rest}>
|
|
35
|
+
<ActionItemBody label={label} description={description} action={action}>
|
|
36
|
+
{children}
|
|
37
|
+
</ActionItemBody>
|
|
38
|
+
</a>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { as: _, label, description, action, children, className, ...rest } = props;
|
|
43
|
+
return (
|
|
44
|
+
<button className={`ck-action-item${className ? ` ${className}` : ''}`} {...rest}>
|
|
45
|
+
<ActionItemBody label={label} description={description} action={action}>
|
|
46
|
+
{children}
|
|
47
|
+
</ActionItemBody>
|
|
48
|
+
</button>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
@use '../../style/mixin.scss' as *;
|
|
2
|
+
|
|
3
|
+
.ck-root .ck-action-item {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 16px;
|
|
7
|
+
width: 100%;
|
|
8
|
+
padding: 16px 20px;
|
|
9
|
+
border-radius: 12px;
|
|
10
|
+
background: var(--scale-gray-100);
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
margin-top: auto;
|
|
13
|
+
flex-shrink: 0;
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.ck-action-item-content {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: 2px;
|
|
21
|
+
flex: 1;
|
|
22
|
+
min-width: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.ck-action-item-label {
|
|
26
|
+
@include textToken('subtitle2-bold');
|
|
27
|
+
color: var(--scale-gray-900);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.ck-action-item-desc {
|
|
31
|
+
@include textToken('label5-regular');
|
|
32
|
+
color: var(--scale-gray-600);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ck-action-item-action {
|
|
36
|
+
display: inline-flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
padding: 0 20px;
|
|
40
|
+
height: 44px;
|
|
41
|
+
border-radius: 6px;
|
|
42
|
+
background: var(--scale-blue2-alpha-100);
|
|
43
|
+
@include textToken('label5-bold');
|
|
44
|
+
color: var(--semantic-brand-trugi-primary);
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
flex-shrink: 0;
|
|
47
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import './style.scss';
|
|
3
|
+
import { CopyIcon } from '../../layout/connectDialog/asset/copyIcon';
|
|
4
|
+
|
|
5
|
+
interface CopyLinkProps {
|
|
6
|
+
onCopy?: () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const CopyLink: FC<CopyLinkProps> = ({ onCopy }) => {
|
|
10
|
+
return (
|
|
11
|
+
<button type="button" className="ck-copy-link" onClick={onCopy}>
|
|
12
|
+
<CopyIcon className="ck-copy-link-icon" />
|
|
13
|
+
Copy link
|
|
14
|
+
</button>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@use '../../style/mixin.scss' as *;
|
|
2
|
+
|
|
3
|
+
.ck-root .ck-copy-link {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
align-self: center;
|
|
7
|
+
gap: 6px;
|
|
8
|
+
@include textToken('body3-l1-regular');
|
|
9
|
+
color: var(--scale-gray-500);
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ck-copy-link-icon {
|
|
14
|
+
flex-shrink: 0;
|
|
15
|
+
color: var(--scale-gray-500);
|
|
16
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type FC, type CSSProperties } from 'react';
|
|
2
|
+
import { QRCodeSVG } from 'qrcode.react';
|
|
3
|
+
import { CopyLink } from '../copyLink';
|
|
4
|
+
import './style.scss';
|
|
5
|
+
|
|
6
|
+
export type QrAreaStatus = 'loading' | 'ready' | 'timeout';
|
|
7
|
+
|
|
8
|
+
interface QrAreaProps {
|
|
9
|
+
uri?: string | null;
|
|
10
|
+
status: QrAreaStatus;
|
|
11
|
+
logoUrl?: string;
|
|
12
|
+
hasBg?: boolean;
|
|
13
|
+
label?: string;
|
|
14
|
+
onCopy?: () => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const BG_COLOR = '#ffffff';
|
|
18
|
+
const FG_COLOR = '#000000';
|
|
19
|
+
const FG_GRADIENT = 'url(#ck-qr-gradient)';
|
|
20
|
+
|
|
21
|
+
export const QrArea: FC<QrAreaProps> = ({ uri, status, logoUrl, hasBg = false, label, onCopy }) => {
|
|
22
|
+
const bgColor = hasBg ? BG_COLOR : 'transparent';
|
|
23
|
+
const fgColor = hasBg ? FG_COLOR : FG_GRADIENT;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className="ck-qr-area">
|
|
27
|
+
<div className="ck-qr-group">
|
|
28
|
+
<figure className={`ck-qr ck-qr-${status}`} aria-label="QR Code">
|
|
29
|
+
{status === 'loading' && (
|
|
30
|
+
<div className="ck-qr-skeleton" aria-busy="true" aria-label="Loading QR code">
|
|
31
|
+
<div className="ck-qr-skeleton-inner" />
|
|
32
|
+
</div>
|
|
33
|
+
)}
|
|
34
|
+
{status === 'ready' && uri && (
|
|
35
|
+
<div
|
|
36
|
+
className="ck-qr-frame"
|
|
37
|
+
style={{ 'background': bgColor, '--ck-qr-bg': bgColor } as CSSProperties}
|
|
38
|
+
>
|
|
39
|
+
{!hasBg && (
|
|
40
|
+
<svg width="0" height="0" style={{ position: 'absolute' }} aria-hidden="true">
|
|
41
|
+
<defs>
|
|
42
|
+
<linearGradient id="ck-qr-gradient" x1="67%" y1="11%" x2="45%" y2="99%">
|
|
43
|
+
<stop offset="0%" stopColor="#7B91FF" />
|
|
44
|
+
<stop offset="100%" stopColor="#61BCFF" />
|
|
45
|
+
</linearGradient>
|
|
46
|
+
</defs>
|
|
47
|
+
</svg>
|
|
48
|
+
)}
|
|
49
|
+
<QRCodeSVG
|
|
50
|
+
value={uri}
|
|
51
|
+
size={288}
|
|
52
|
+
bgColor={bgColor}
|
|
53
|
+
fgColor={fgColor}
|
|
54
|
+
level="M"
|
|
55
|
+
marginSize={0}
|
|
56
|
+
imageSettings={
|
|
57
|
+
logoUrl ? { src: logoUrl, width: 68, height: 68, excavate: true } : undefined
|
|
58
|
+
}
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
)}
|
|
62
|
+
</figure>
|
|
63
|
+
{(label || onCopy) && (
|
|
64
|
+
<div className="ck-qr-text">
|
|
65
|
+
{label && <p className="ck-qr-label">{label}</p>}
|
|
66
|
+
{onCopy && <CopyLink onCopy={onCopy} />}
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
};
|