@gluwa/connect-kit 0.1.0-next.3 → 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 +68 -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 -394
- package/dist/index.css +2075 -0
- package/dist/index.d.ts +58 -33
- package/dist/index.js +1748 -1503
- package/dist/package.json +16 -10
- package/package.json +14 -11
- package/src/ConnectKitProvider.tsx +133 -75
- package/src/api/account.ts +21 -0
- package/src/api/asset.ts +10 -0
- package/src/api/balance.ts +10 -0
- package/src/api/chain.ts +17 -0
- package/src/api/contract.ts +33 -0
- package/src/api/transaction.ts +12 -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 +102 -0
- package/src/creditConnectConnector.ts +198 -184
- package/src/events/account.ts +76 -0
- 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 +45 -14
- package/src/hooks/useWagmiConnect.ts +42 -11
- package/src/index.ts +38 -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 +40 -7
- package/src/utils/platform.ts +6 -7
- 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 -559
- package/src/components/QRFrame.tsx +0 -43
- package/src/views/CreditWalletView.tsx +0 -59
- package/src/views/IdleView.tsx +0 -10
- package/src/views/MetaMaskView.tsx +0 -64
- package/src/views/SwitchChainView.tsx +0 -67
- package/src/views/WalletConnectView.tsx +0 -206
package/dist/package.json
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-next.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
+
"types": "./src/index.ts",
|
|
7
8
|
"default": "./src/index.ts"
|
|
8
9
|
},
|
|
9
10
|
"./credit-connect": {
|
|
11
|
+
"types": "./src/credit-connect.ts",
|
|
10
12
|
"default": "./src/credit-connect.ts"
|
|
11
13
|
},
|
|
14
|
+
"./index.css": "./dist/index.css",
|
|
12
15
|
"./package.json": "./package.json"
|
|
13
16
|
},
|
|
14
17
|
"publishConfig": {
|
|
@@ -27,7 +30,10 @@
|
|
|
27
30
|
"./index.css": "./dist/index.css"
|
|
28
31
|
}
|
|
29
32
|
},
|
|
30
|
-
"sideEffects":
|
|
33
|
+
"sideEffects": [
|
|
34
|
+
"**/*.scss",
|
|
35
|
+
"**/*.css"
|
|
36
|
+
],
|
|
31
37
|
"scripts": {
|
|
32
38
|
"prepack": "pnpm build && cp package.json dist/ && cp README.md dist/",
|
|
33
39
|
"build": "tsup",
|
|
@@ -38,7 +44,13 @@
|
|
|
38
44
|
"author": "",
|
|
39
45
|
"license": "ISC",
|
|
40
46
|
"dependencies": {
|
|
41
|
-
"qrcode.react": "^
|
|
47
|
+
"qrcode.react": "^4.2.0",
|
|
48
|
+
"wagmi": "^2.15.6",
|
|
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:*"
|
|
42
54
|
},
|
|
43
55
|
"devDependencies": {
|
|
44
56
|
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
@@ -55,17 +67,11 @@
|
|
|
55
67
|
"wagmi": "^2.15.6"
|
|
56
68
|
},
|
|
57
69
|
"peerDependencies": {
|
|
58
|
-
"@gluwa/credit-connect-sdk": "workspace:*",
|
|
59
70
|
"@tanstack/react-query": ">=5.0.0",
|
|
60
|
-
"@wagmi/core": ">=2.0.0",
|
|
61
71
|
"react": "^18.0.0 || ^19.0.0",
|
|
62
|
-
"viem": ">=2.0.0"
|
|
63
|
-
"wagmi": ">=2.0.0"
|
|
72
|
+
"viem": ">=2.0.0"
|
|
64
73
|
},
|
|
65
74
|
"peerDependenciesMeta": {
|
|
66
|
-
"@gluwa/credit-connect-sdk": {
|
|
67
|
-
"optional": true
|
|
68
|
-
},
|
|
69
75
|
"@tanstack/react-query": {
|
|
70
76
|
"optional": true
|
|
71
77
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gluwa/connect-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-next.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -16,11 +16,20 @@
|
|
|
16
16
|
"publishConfig": {
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
|
-
"sideEffects":
|
|
19
|
+
"sideEffects": [
|
|
20
|
+
"**/*.scss",
|
|
21
|
+
"**/*.css"
|
|
22
|
+
],
|
|
20
23
|
"author": "",
|
|
21
24
|
"license": "ISC",
|
|
22
25
|
"dependencies": {
|
|
23
|
-
"qrcode.react": "^
|
|
26
|
+
"qrcode.react": "^4.2.0",
|
|
27
|
+
"wagmi": "^2.15.6",
|
|
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"
|
|
24
33
|
},
|
|
25
34
|
"devDependencies": {
|
|
26
35
|
"@tanstack/react-query": "^5.62.0",
|
|
@@ -34,20 +43,14 @@
|
|
|
34
43
|
"typescript-eslint": "^8.18.2",
|
|
35
44
|
"viem": "^2.31.7",
|
|
36
45
|
"wagmi": "^2.15.6",
|
|
37
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.
|
|
46
|
+
"@gluwa/credit-connect-sdk": "0.2.0-next.5"
|
|
38
47
|
},
|
|
39
48
|
"peerDependencies": {
|
|
40
49
|
"@tanstack/react-query": ">=5.0.0",
|
|
41
|
-
"@wagmi/core": ">=2.0.0",
|
|
42
50
|
"react": "^18.0.0 || ^19.0.0",
|
|
43
|
-
"viem": ">=2.0.0"
|
|
44
|
-
"wagmi": ">=2.0.0",
|
|
45
|
-
"@gluwa/credit-connect-sdk": "0.2.0-next.1"
|
|
51
|
+
"viem": ">=2.0.0"
|
|
46
52
|
},
|
|
47
53
|
"peerDependenciesMeta": {
|
|
48
|
-
"@gluwa/credit-connect-sdk": {
|
|
49
|
-
"optional": true
|
|
50
|
-
},
|
|
51
54
|
"@tanstack/react-query": {
|
|
52
55
|
"optional": true
|
|
53
56
|
}
|
|
@@ -9,53 +9,48 @@ import {
|
|
|
9
9
|
type FC,
|
|
10
10
|
type ReactNode,
|
|
11
11
|
} from 'react';
|
|
12
|
-
import { WagmiProvider, useAccount, useDisconnect } from 'wagmi';
|
|
13
|
-
import
|
|
12
|
+
import { WagmiProvider, useAccount, useConfig, useDisconnect, useSwitchChain } from 'wagmi';
|
|
13
|
+
import { getAccount } from '@wagmi/core';
|
|
14
14
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
15
|
-
import { ConnectModal } from './ConnectModal';
|
|
16
|
-
import
|
|
15
|
+
// import { ConnectModal } from './ConnectModal';
|
|
16
|
+
import { ConnectDialog } from './layout/connectDialog';
|
|
17
|
+
import { getConfig, getKitConfig, initConfig } from './core/config';
|
|
18
|
+
import { resolveConnectorId } from './connector-meta';
|
|
19
|
+
import type {
|
|
20
|
+
ConnectErrorContext,
|
|
21
|
+
ConnectBannerSiteKey,
|
|
22
|
+
ConnectKitConfig,
|
|
23
|
+
ConnectKitTheme,
|
|
24
|
+
ConnectResult,
|
|
25
|
+
ConnectorId,
|
|
26
|
+
ConnectorKey,
|
|
27
|
+
Connectors,
|
|
28
|
+
} from './types';
|
|
17
29
|
|
|
18
|
-
// wagmiConfig prop으로 기존 프로젝트 통합 시 내부에서 사용하는 QueryClient.
|
|
19
|
-
// 모듈 레벨에 한 번만 생성 — 연결 플로우용으로만 쓰이므로 공유해도 무방.
|
|
20
30
|
const internalQueryClient = new QueryClient();
|
|
21
31
|
|
|
22
32
|
export interface ConnectKitProviderProps {
|
|
23
33
|
children: ReactNode;
|
|
34
|
+
siteKey: ConnectBannerSiteKey;
|
|
35
|
+
connectBannerUrl: string;
|
|
36
|
+
kitConfig?: ConnectKitConfig;
|
|
24
37
|
connectors: Connectors;
|
|
25
|
-
wcProjectId?: string;
|
|
26
|
-
/**
|
|
27
|
-
* 연결돼 있는 동안 강제할 체인 ID. 다른 체인에 연결돼 있으면
|
|
28
|
-
* 자동으로 스위치 모달이 떠서 사용자에게 전환 또는 disconnect를 요구.
|
|
29
|
-
*/
|
|
30
38
|
requiredChainId?: number;
|
|
31
|
-
|
|
32
|
-
* 연결이 정상적으로 끝나고(체인 검증까지 통과) "사용 가능한 상태"가 됐을 때 한 번 호출.
|
|
33
|
-
* 재연결(reconnect)에서는 호출되지 않음 — 그쪽은 dApp의 watchAccount 책임.
|
|
34
|
-
*/
|
|
39
|
+
theme: ConnectKitTheme;
|
|
35
40
|
onConnect?: (result: ConnectResult) => void;
|
|
36
41
|
onLog?: (message: string, error?: Error) => void;
|
|
37
|
-
/**
|
|
38
|
-
* 연결 실패(거절/미설치/기타) 시 모달 안에 표시할 fallback UI를 dApp이 직접 그리고 싶을 때.
|
|
39
|
-
* 미제공 시 기본 동작은 selector로 복귀.
|
|
40
|
-
*/
|
|
41
42
|
renderConnectError?: (ctx: ConnectErrorContext) => ReactNode;
|
|
42
|
-
/**
|
|
43
|
-
* 기존 프로젝트 통합용. wagmi config를 넘기면 ConnectKitProvider 내부에서
|
|
44
|
-
* WagmiProvider를 직접 세운다.
|
|
45
|
-
*
|
|
46
|
-
* - 기존 프로젝트: 앱에 WagmiProvider가 없으므로 wagmiConfig를 넘긴다.
|
|
47
|
-
* ConnectKitProvider가 같은 config 인스턴스로 WagmiProvider를 셀프 마운트하므로
|
|
48
|
-
* 기존 wagmi 상태 store와 단일 config를 공유한다.
|
|
49
|
-
* - 신규 프로젝트: 앱이 이미 WagmiProvider를 감싸므로 이 prop은 불필요하다.
|
|
50
|
-
*/
|
|
51
|
-
wagmiConfig?: Config;
|
|
52
43
|
}
|
|
53
|
-
|
|
54
44
|
export interface ConnectKitContextValue {
|
|
55
45
|
isOpen: boolean;
|
|
56
46
|
open: () => void;
|
|
57
47
|
close: () => void;
|
|
58
48
|
isConnected: boolean;
|
|
49
|
+
needsChainSwitch: boolean;
|
|
50
|
+
requiredChainId: number | undefined;
|
|
51
|
+
currentChainId: number | undefined;
|
|
52
|
+
isSwitchingChain: boolean;
|
|
53
|
+
switchToRequiredChain: () => Promise<void>;
|
|
59
54
|
address: `0x${string}` | undefined;
|
|
60
55
|
connectorId: ConnectorId | null;
|
|
61
56
|
disconnect: () => Promise<void>;
|
|
@@ -63,58 +58,82 @@ export interface ConnectKitContextValue {
|
|
|
63
58
|
|
|
64
59
|
const ConnectKitContext = createContext<ConnectKitContextValue | null>(null);
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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]);
|
|
74
71
|
};
|
|
75
72
|
|
|
76
73
|
export const ConnectKitProvider: FC<ConnectKitProviderProps> = (props) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
74
|
+
const wagmiConfig = useMemo(
|
|
75
|
+
() => (props.kitConfig ? initConfig(props.kitConfig) : getConfig()),
|
|
76
|
+
[props.kitConfig],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const resolvedKitConfig = props.kitConfig ?? getKitConfig();
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<WagmiProvider config={wagmiConfig} reconnectOnMount={false}>
|
|
83
|
+
<QueryClientProvider client={internalQueryClient}>
|
|
84
|
+
<ConnectKitProviderInner {...props} kitConfig={resolvedKitConfig} />
|
|
85
|
+
</QueryClientProvider>
|
|
86
|
+
</WagmiProvider>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
type ConnectKitProviderInnerProps = Omit<ConnectKitProviderProps, 'kitConfig'> & {
|
|
91
|
+
kitConfig: ConnectKitConfig;
|
|
87
92
|
};
|
|
88
93
|
|
|
89
|
-
const ConnectKitProviderInner: FC<
|
|
94
|
+
const ConnectKitProviderInner: FC<ConnectKitProviderInnerProps> = ({
|
|
90
95
|
children,
|
|
96
|
+
siteKey,
|
|
97
|
+
connectBannerUrl,
|
|
91
98
|
connectors,
|
|
92
|
-
|
|
99
|
+
kitConfig,
|
|
93
100
|
requiredChainId,
|
|
101
|
+
theme,
|
|
94
102
|
onConnect,
|
|
95
103
|
onLog,
|
|
96
|
-
renderConnectError,
|
|
97
104
|
}) => {
|
|
105
|
+
// NOTE: renderConnectError 는 ConnectDialog 가 아직 error UI customization 을 받지 않으므로
|
|
106
|
+
// destructure 에서 제외. 추후 ConnectDialog 의 timeout/error content 에 wire 필요 시 복원.
|
|
98
107
|
const [isOpen, setIsOpen] = useState(false);
|
|
99
108
|
const [pendingResult, setPendingResult] = useState<ConnectResult | null>(null);
|
|
100
109
|
|
|
101
110
|
const account = useAccount();
|
|
111
|
+
const wagmiConfig = useConfig();
|
|
102
112
|
const { disconnectAsync } = useDisconnect();
|
|
113
|
+
const { switchChainAsync } = useSwitchChain();
|
|
103
114
|
|
|
104
|
-
// dApp의 onConnect는 ref로 잡아 effect 재실행 노이즈 차단
|
|
105
115
|
const onConnectRef = useRef(onConnect);
|
|
106
116
|
useEffect(() => {
|
|
107
117
|
onConnectRef.current = onConnect;
|
|
108
118
|
}, [onConnect]);
|
|
109
119
|
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
const isMountedRef = useRef(true);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
isMountedRef.current = true;
|
|
123
|
+
return () => {
|
|
124
|
+
isMountedRef.current = false;
|
|
125
|
+
};
|
|
126
|
+
}, []);
|
|
127
|
+
|
|
128
|
+
const needsChainSwitch =
|
|
112
129
|
requiredChainId != null &&
|
|
113
130
|
account.status === 'connected' &&
|
|
114
131
|
account.chainId != null &&
|
|
115
132
|
account.chainId !== requiredChainId;
|
|
116
133
|
|
|
117
|
-
const
|
|
134
|
+
const [isSwitchingChain, setIsSwitchingChain] = useState(false);
|
|
135
|
+
|
|
136
|
+
const effectiveOpen = isOpen;
|
|
118
137
|
|
|
119
138
|
const open = useCallback((): void => {
|
|
120
139
|
setIsOpen(true);
|
|
@@ -122,34 +141,62 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
122
141
|
|
|
123
142
|
const close = useCallback((): void => {
|
|
124
143
|
setIsOpen(false);
|
|
125
|
-
|
|
144
|
+
const status = getAccount(wagmiConfig).status;
|
|
145
|
+
if (status === 'connecting' || status === 'reconnecting') {
|
|
146
|
+
disconnectAsync().catch(() => undefined);
|
|
147
|
+
}
|
|
148
|
+
}, [wagmiConfig, disconnectAsync]);
|
|
126
149
|
|
|
127
150
|
const disconnect = useCallback(async (): Promise<void> => {
|
|
128
151
|
await disconnectAsync();
|
|
129
152
|
}, [disconnectAsync]);
|
|
130
153
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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 => {
|
|
134
168
|
setPendingResult(result);
|
|
135
169
|
}, []);
|
|
136
170
|
|
|
137
|
-
|
|
138
|
-
|
|
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 => {
|
|
139
192
|
if (!pendingResult) return;
|
|
140
193
|
if (account.status !== 'connected') {
|
|
141
|
-
// 연결이 끊겼거나 진행 중 — pending 폐기
|
|
142
194
|
setPendingResult(null);
|
|
143
195
|
return;
|
|
144
196
|
}
|
|
145
|
-
if (requiredChainId != null && account.chainId !== requiredChainId) {
|
|
146
|
-
// chain 아직 안 맞음 — switch 후 다시 평가
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
197
|
onConnectRef.current?.(pendingResult);
|
|
150
198
|
setPendingResult(null);
|
|
151
|
-
|
|
152
|
-
}, [pendingResult, account.status, account.chainId, requiredChainId]);
|
|
199
|
+
}, [pendingResult, account.status]);
|
|
153
200
|
|
|
154
201
|
const value = useMemo<ConnectKitContextValue>(
|
|
155
202
|
() => ({
|
|
@@ -157,6 +204,11 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
157
204
|
open,
|
|
158
205
|
close,
|
|
159
206
|
isConnected: account.status === 'connected',
|
|
207
|
+
needsChainSwitch,
|
|
208
|
+
requiredChainId,
|
|
209
|
+
currentChainId: account.chainId,
|
|
210
|
+
isSwitchingChain,
|
|
211
|
+
switchToRequiredChain,
|
|
160
212
|
address: account.address,
|
|
161
213
|
connectorId: resolveConnectorId(account.connector?.id),
|
|
162
214
|
disconnect,
|
|
@@ -166,6 +218,11 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
166
218
|
open,
|
|
167
219
|
close,
|
|
168
220
|
account.status,
|
|
221
|
+
needsChainSwitch,
|
|
222
|
+
requiredChainId,
|
|
223
|
+
account.chainId,
|
|
224
|
+
isSwitchingChain,
|
|
225
|
+
switchToRequiredChain,
|
|
169
226
|
account.address,
|
|
170
227
|
account.connector?.id,
|
|
171
228
|
disconnect,
|
|
@@ -175,15 +232,16 @@ const ConnectKitProviderInner: FC<ConnectKitProviderProps> = ({
|
|
|
175
232
|
return (
|
|
176
233
|
<ConnectKitContext.Provider value={value}>
|
|
177
234
|
{children}
|
|
178
|
-
<
|
|
235
|
+
<ConnectDialog
|
|
179
236
|
open={effectiveOpen}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
237
|
+
siteKey={siteKey}
|
|
238
|
+
connectBannerUrl={connectBannerUrl}
|
|
239
|
+
theme={theme}
|
|
240
|
+
connectors={resolveConnectorsFromConfig(connectors)}
|
|
241
|
+
wcProjectId={kitConfig.wcProjectId}
|
|
185
242
|
onClose={close}
|
|
186
|
-
|
|
243
|
+
onConnect={handleDialogConnect}
|
|
244
|
+
onError={handleDialogError}
|
|
187
245
|
/>
|
|
188
246
|
</ConnectKitContext.Provider>
|
|
189
247
|
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAccount as wagmiGetAccount,
|
|
3
|
+
signMessage as wagmiSignMessage,
|
|
4
|
+
signTypedData as wagmiSignTypedData,
|
|
5
|
+
type GetAccountReturnType,
|
|
6
|
+
type SignMessageParameters,
|
|
7
|
+
type SignTypedDataParameters,
|
|
8
|
+
} from '@wagmi/core';
|
|
9
|
+
import { getConfig } from '../core/config';
|
|
10
|
+
|
|
11
|
+
export const getAccount = (): GetAccountReturnType => {
|
|
12
|
+
return wagmiGetAccount(getConfig());
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const signMessage = (params: SignMessageParameters): Promise<`0x${string}`> => {
|
|
16
|
+
return wagmiSignMessage(getConfig(), params);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const signTypedData = (params: SignTypedDataParameters): Promise<`0x${string}`> => {
|
|
20
|
+
return wagmiSignTypedData(getConfig(), params);
|
|
21
|
+
};
|
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
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBalance as wagmiGetBalance,
|
|
3
|
+
type GetBalanceParameters,
|
|
4
|
+
type GetBalanceReturnType,
|
|
5
|
+
} from '@wagmi/core';
|
|
6
|
+
import { getConfig } from '../core/config';
|
|
7
|
+
|
|
8
|
+
export const getBalance = (params: GetBalanceParameters): Promise<GetBalanceReturnType> => {
|
|
9
|
+
return wagmiGetBalance(getConfig(), params);
|
|
10
|
+
};
|
package/src/api/chain.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
switchChain as wagmiSwitchChain,
|
|
3
|
+
getPublicClient as wagmiGetPublicClient,
|
|
4
|
+
type SwitchChainParameters,
|
|
5
|
+
type GetPublicClientParameters,
|
|
6
|
+
type GetPublicClientReturnType,
|
|
7
|
+
} from '@wagmi/core';
|
|
8
|
+
import type { Chain } from 'viem';
|
|
9
|
+
import { getConfig } from '../core/config';
|
|
10
|
+
|
|
11
|
+
export const switchChain = (params: SwitchChainParameters): Promise<Chain> => {
|
|
12
|
+
return wagmiSwitchChain(getConfig(), params);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const getPublicClient = (params?: GetPublicClientParameters): GetPublicClientReturnType => {
|
|
16
|
+
return wagmiGetPublicClient(getConfig(), params);
|
|
17
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readContract as wagmiReadContract,
|
|
3
|
+
writeContract as wagmiWriteContract,
|
|
4
|
+
type ReadContractParameters,
|
|
5
|
+
type ReadContractReturnType,
|
|
6
|
+
type WriteContractParameters,
|
|
7
|
+
type WriteContractReturnType,
|
|
8
|
+
type Config,
|
|
9
|
+
} from '@wagmi/core';
|
|
10
|
+
import type { Abi, ContractFunctionArgs, ContractFunctionName } from 'viem';
|
|
11
|
+
import { getConfig } from '../core/config';
|
|
12
|
+
|
|
13
|
+
export function readContract<
|
|
14
|
+
const abi extends Abi | readonly unknown[],
|
|
15
|
+
functionName extends ContractFunctionName<abi, 'pure' | 'view'>,
|
|
16
|
+
args extends ContractFunctionArgs<abi, 'pure' | 'view', functionName>,
|
|
17
|
+
>(
|
|
18
|
+
parameters: ReadContractParameters<abi, functionName, args, Config>,
|
|
19
|
+
): Promise<ReadContractReturnType<abi, functionName, args>> {
|
|
20
|
+
return wagmiReadContract(getConfig(), parameters as any) as Promise<
|
|
21
|
+
ReadContractReturnType<abi, functionName, args>
|
|
22
|
+
>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function writeContract<
|
|
26
|
+
const abi extends Abi | readonly unknown[],
|
|
27
|
+
functionName extends ContractFunctionName<abi, 'nonpayable' | 'payable'>,
|
|
28
|
+
args extends ContractFunctionArgs<abi, 'nonpayable' | 'payable', functionName>,
|
|
29
|
+
>(
|
|
30
|
+
parameters: WriteContractParameters<abi, functionName, args, Config>,
|
|
31
|
+
): Promise<WriteContractReturnType> {
|
|
32
|
+
return wagmiWriteContract(getConfig(), parameters as any);
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
waitForTransactionReceipt as wagmiWaitForTransactionReceipt,
|
|
3
|
+
type WaitForTransactionReceiptParameters,
|
|
4
|
+
type WaitForTransactionReceiptReturnType,
|
|
5
|
+
} from '@wagmi/core';
|
|
6
|
+
import { getConfig } from '../core/config';
|
|
7
|
+
|
|
8
|
+
export const waitForTransactionReceipt = (
|
|
9
|
+
params: WaitForTransactionReceiptParameters,
|
|
10
|
+
): Promise<WaitForTransactionReceiptReturnType> => {
|
|
11
|
+
return wagmiWaitForTransactionReceipt(getConfig(), params);
|
|
12
|
+
};
|
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
|
+
};
|