@taskon/widget-react 0.0.1-beta.6 → 0.0.1-beta.7
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/README.md +48 -43
- package/dist/EligibilityInfo.css +2 -33
- package/dist/TaskOnProvider.css +287 -0
- package/dist/ThemeProvider.css +227 -0
- package/dist/UserCenterWidget2.css +32 -290
- package/dist/WidgetShell.css +0 -227
- package/dist/chunks/{CommunityTaskList-Hde2OKHH.js → CommunityTaskList-D0uVD8wD.js} +37 -58
- package/dist/chunks/{EligibilityInfo-BV0Z2TgY.js → EligibilityInfo-Cf6hx9-a.js} +17 -209
- package/dist/chunks/{LeaderboardWidget-BNGRD5Bu.js → LeaderboardWidget-DyoiiNS6.js} +10 -9
- package/dist/chunks/{PageBuilder-C5DSHiW9.js → PageBuilder-DoAFPm6-.js} +5 -5
- package/dist/chunks/{Quest-DG9zfXJo.js → Quest-ySZlYd4u.js} +6 -11
- package/dist/chunks/TaskOnProvider-CxtFIs3n.js +2072 -0
- package/dist/chunks/{WidgetShell-D7yC894Y.js → ThemeProvider-CulHkqqY.js} +1354 -617
- package/dist/chunks/UserCenterWidget-BJsc_GSZ.js +3246 -0
- package/dist/chunks/{UserCenterWidget-D5ttw4hO.js → UserCenterWidget-STq8kpV4.js} +162 -365
- package/dist/chunks/WidgetShell-8xn-Jivw.js +659 -0
- package/dist/chunks/useIsMobile-D6Ybur-6.js +30 -0
- package/dist/chunks/useToast-BGJhd3BX.js +93 -0
- package/dist/community-task.js +1 -1
- package/dist/core.d.ts +9 -15
- package/dist/core.js +3 -3
- package/dist/index.d.ts +64 -15
- package/dist/index.js +15 -10
- package/dist/leaderboard.js +1 -1
- package/dist/page-builder.js +1 -1
- package/dist/quest.js +1 -1
- package/dist/user-center.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/TaskOnProvider-BhamHIyY.js +0 -1260
- package/dist/chunks/ThemeProvider-mXLdLSkq.js +0 -1397
- package/dist/chunks/UserCenterWidget-jDO5zTN1.js +0 -3297
- package/dist/chunks/useToast-CaRkylKe.js +0 -304
|
@@ -0,0 +1,2072 @@
|
|
|
1
|
+
import { p as preloadWidgetLocale, b as useWidgetLocale, e as createLocaleLoader, k as createContextScope, l as useComposedRefs, m as createSlot, P as Primitive, B as Branch, n as useControllableState, o as Presence, q as composeEventHandlers, r as useCallbackRef, R as Root, s as Portal, t as dispatchDiscreteCustomEvent, v as useLayoutEffect2, w as TaskOnContext, D as Dialog } from "./ThemeProvider-CulHkqqY.js";
|
|
2
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import React__default, { useState, useRef, useEffect, useMemo, useCallback, useContext } from "react";
|
|
5
|
+
import { createTaskOnClient, createUserApi, createChainApi, createCommunityTaskApi } from "@taskon/core";
|
|
6
|
+
import { W as WalletContext, b as useToastState, T as ToastContext } from "./useToast-BGJhd3BX.js";
|
|
7
|
+
import * as ReactDOM from "react-dom";
|
|
8
|
+
import { u as useIsMobile, i as isMobileViewport } from "./useIsMobile-D6Ybur-6.js";
|
|
9
|
+
import '../TaskOnProvider.css';const TOKEN_STORAGE_KEY = "taskon_user_token";
|
|
10
|
+
function isBrowser() {
|
|
11
|
+
return typeof window !== "undefined";
|
|
12
|
+
}
|
|
13
|
+
function getStoredToken() {
|
|
14
|
+
if (!isBrowser()) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return localStorage.getItem(TOKEN_STORAGE_KEY);
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function setStoredToken(token) {
|
|
24
|
+
if (!isBrowser()) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
localStorage.setItem(TOKEN_STORAGE_KEY, token);
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function removeStoredToken() {
|
|
33
|
+
if (!isBrowser()) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
localStorage.removeItem(TOKEN_STORAGE_KEY);
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function useClientInit({
|
|
42
|
+
clientId,
|
|
43
|
+
baseURL,
|
|
44
|
+
setUserInfo,
|
|
45
|
+
setUserToken
|
|
46
|
+
}) {
|
|
47
|
+
const [client, setClient] = useState(null);
|
|
48
|
+
const userApiRef = useRef(null);
|
|
49
|
+
const [isInitializing, setIsInitializing] = useState(true);
|
|
50
|
+
const [isSessionReady, setIsSessionReady] = useState(false);
|
|
51
|
+
const isInitializedRef = useRef(false);
|
|
52
|
+
const configRef = useRef({ clientId, baseURL });
|
|
53
|
+
configRef.current = { clientId, baseURL };
|
|
54
|
+
const settersRef = useRef({ setUserInfo, setUserToken });
|
|
55
|
+
settersRef.current = { setUserInfo, setUserToken };
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (isInitializedRef.current) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
isInitializedRef.current = true;
|
|
61
|
+
const init = async () => {
|
|
62
|
+
try {
|
|
63
|
+
const { clientId: clientId2, baseURL: baseURL2 } = configRef.current;
|
|
64
|
+
const { setUserInfo: setUserInfo2, setUserToken: setUserToken2 } = settersRef.current;
|
|
65
|
+
const taskOnClient = createTaskOnClient({
|
|
66
|
+
clientId: clientId2,
|
|
67
|
+
baseURL: baseURL2,
|
|
68
|
+
// Unified auth error handler - called when any API returns auth error
|
|
69
|
+
onAuthError: () => {
|
|
70
|
+
taskOnClient.setUserToken(null);
|
|
71
|
+
settersRef.current.setUserInfo(null);
|
|
72
|
+
settersRef.current.setUserToken(null);
|
|
73
|
+
removeStoredToken();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
const userApi = createUserApi(taskOnClient);
|
|
77
|
+
setClient(taskOnClient);
|
|
78
|
+
userApiRef.current = userApi;
|
|
79
|
+
const storedToken = getStoredToken();
|
|
80
|
+
if (storedToken) {
|
|
81
|
+
taskOnClient.setUserToken(storedToken);
|
|
82
|
+
setIsSessionReady(true);
|
|
83
|
+
try {
|
|
84
|
+
const info = await userApi.getInfo();
|
|
85
|
+
setUserInfo2(info);
|
|
86
|
+
setUserToken2(storedToken);
|
|
87
|
+
} catch {
|
|
88
|
+
taskOnClient.setUserToken(null);
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
setIsSessionReady(true);
|
|
92
|
+
}
|
|
93
|
+
} finally {
|
|
94
|
+
setIsInitializing(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
init();
|
|
98
|
+
}, []);
|
|
99
|
+
return {
|
|
100
|
+
client,
|
|
101
|
+
userApiRef,
|
|
102
|
+
isSessionReady,
|
|
103
|
+
isInitializing
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const registry = /* @__PURE__ */ new Map();
|
|
107
|
+
const builtInLocaleImports = {
|
|
108
|
+
CommunityTask: {
|
|
109
|
+
ko: () => import("./communitytask-ko-Bf24PQKI.js").then((module) => ({
|
|
110
|
+
default: module.default
|
|
111
|
+
})),
|
|
112
|
+
ja: () => import("./communitytask-ja-GRf9cbdx.js").then((module) => ({
|
|
113
|
+
default: module.default
|
|
114
|
+
})),
|
|
115
|
+
ru: () => import("./communitytask-ru-CZm2CPoV.js").then((module) => ({
|
|
116
|
+
default: module.default
|
|
117
|
+
})),
|
|
118
|
+
es: () => import("./communitytask-es-CBNnS4o2.js").then((module) => ({
|
|
119
|
+
default: module.default
|
|
120
|
+
}))
|
|
121
|
+
},
|
|
122
|
+
Quest: {
|
|
123
|
+
ko: () => import("./quest-ko-BMu3uRQJ.js").then((module) => ({
|
|
124
|
+
default: module.default
|
|
125
|
+
})),
|
|
126
|
+
ja: () => import("./quest-ja-Depog33y.js").then((module) => ({
|
|
127
|
+
default: module.default
|
|
128
|
+
})),
|
|
129
|
+
ru: () => import("./quest-ru-xne814Rw.js").then((module) => ({
|
|
130
|
+
default: module.default
|
|
131
|
+
})),
|
|
132
|
+
es: () => import("./quest-es-Dyyy0zaw.js").then((module) => ({
|
|
133
|
+
default: module.default
|
|
134
|
+
}))
|
|
135
|
+
},
|
|
136
|
+
TaskWidget: {
|
|
137
|
+
ko: () => import("./taskwidget-ko-EHgXFV4B.js").then((module) => ({
|
|
138
|
+
default: module.default
|
|
139
|
+
})),
|
|
140
|
+
ja: () => import("./taskwidget-ja-CqSu-yWA.js").then((module) => ({
|
|
141
|
+
default: module.default
|
|
142
|
+
})),
|
|
143
|
+
ru: () => import("./taskwidget-ru-CMbLQDK4.js").then((module) => ({
|
|
144
|
+
default: module.default
|
|
145
|
+
})),
|
|
146
|
+
es: () => import("./taskwidget-es-Do9b3Mqw.js").then((module) => ({
|
|
147
|
+
default: module.default
|
|
148
|
+
}))
|
|
149
|
+
},
|
|
150
|
+
LeaderboardWidget: {
|
|
151
|
+
ko: () => import("./leaderboardwidget-ko-CG6SWgxf.js").then((module) => ({
|
|
152
|
+
default: module.default
|
|
153
|
+
})),
|
|
154
|
+
ja: () => import("./leaderboardwidget-ja-Q6u0HxKG.js").then((module) => ({
|
|
155
|
+
default: module.default
|
|
156
|
+
})),
|
|
157
|
+
ru: () => import("./leaderboardwidget-ru-DCcHcJGz.js").then((module) => ({
|
|
158
|
+
default: module.default
|
|
159
|
+
})),
|
|
160
|
+
es: () => import("./leaderboardwidget-es-vKjrjQaz.js").then((module) => ({
|
|
161
|
+
default: module.default
|
|
162
|
+
}))
|
|
163
|
+
},
|
|
164
|
+
UserCenterWidget: {
|
|
165
|
+
ko: () => import("./usercenter-ko-Dtpkn2qb.js").then((module) => ({
|
|
166
|
+
default: module.default
|
|
167
|
+
})),
|
|
168
|
+
ja: () => import("./usercenter-ja-CKE4DJC6.js").then((module) => ({
|
|
169
|
+
default: module.default
|
|
170
|
+
})),
|
|
171
|
+
ru: () => import("./usercenter-ru-DnBGee45.js").then((module) => ({
|
|
172
|
+
default: module.default
|
|
173
|
+
})),
|
|
174
|
+
es: () => import("./usercenter-es-Dz3Wp2vV.js").then((module) => ({
|
|
175
|
+
default: module.default
|
|
176
|
+
}))
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
async function preloadBuiltInWidgetLocale(widget, locale) {
|
|
180
|
+
if (locale === "en") return;
|
|
181
|
+
const localeLoader = builtInLocaleImports[widget][locale];
|
|
182
|
+
if (!localeLoader) return;
|
|
183
|
+
await preloadWidgetLocale(widget, locale, () => localeLoader());
|
|
184
|
+
}
|
|
185
|
+
const builtInPreloaders = {
|
|
186
|
+
CommunityTask: (locale) => preloadBuiltInWidgetLocale("CommunityTask", locale),
|
|
187
|
+
Quest: (locale) => preloadBuiltInWidgetLocale("Quest", locale),
|
|
188
|
+
TaskWidget: (locale) => preloadBuiltInWidgetLocale("TaskWidget", locale),
|
|
189
|
+
LeaderboardWidget: (locale) => preloadBuiltInWidgetLocale("LeaderboardWidget", locale),
|
|
190
|
+
UserCenterWidget: (locale) => preloadBuiltInWidgetLocale("UserCenterWidget", locale)
|
|
191
|
+
};
|
|
192
|
+
async function preloadWidgets(widgets, locale) {
|
|
193
|
+
const preloadPromises = widgets.map((name) => {
|
|
194
|
+
const preloadFn = registry.get(name) ?? builtInPreloaders[name];
|
|
195
|
+
if (!preloadFn) {
|
|
196
|
+
if (process.env.NODE_ENV !== "production") {
|
|
197
|
+
console.warn(
|
|
198
|
+
`[widget-react] Widget "${name}" not found in registry. Make sure this widget has a preload loader configured.`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
return preloadFn(locale);
|
|
204
|
+
}).filter(Boolean);
|
|
205
|
+
await Promise.all(preloadPromises);
|
|
206
|
+
}
|
|
207
|
+
const loading = "Loading...";
|
|
208
|
+
const error = "Something went wrong";
|
|
209
|
+
const retry = "Retry";
|
|
210
|
+
const success = "Success";
|
|
211
|
+
const cancel = "Cancel";
|
|
212
|
+
const confirm = "Confirm";
|
|
213
|
+
const enMessages = {
|
|
214
|
+
loading,
|
|
215
|
+
error,
|
|
216
|
+
retry,
|
|
217
|
+
success,
|
|
218
|
+
cancel,
|
|
219
|
+
confirm
|
|
220
|
+
};
|
|
221
|
+
const loadMessages = createLocaleLoader(enMessages, {
|
|
222
|
+
ko: () => import("./common-ko-80ezXsMG.js").then((m) => ({ default: m.default })),
|
|
223
|
+
ja: () => import("./common-ja-DWhTaFHb.js").then((m) => ({ default: m.default }))
|
|
224
|
+
});
|
|
225
|
+
function useCommonLocale() {
|
|
226
|
+
return useWidgetLocale({
|
|
227
|
+
widgetId: "Common",
|
|
228
|
+
defaultMessages: enMessages,
|
|
229
|
+
loadMessages
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const SUPPORTED_LOCALES = ["en", "ko", "ja", "ru", "es"];
|
|
233
|
+
const DEFAULT_LOCALE = "en";
|
|
234
|
+
function detectLocale() {
|
|
235
|
+
if (typeof window === "undefined") {
|
|
236
|
+
return DEFAULT_LOCALE;
|
|
237
|
+
}
|
|
238
|
+
const browserLang = navigator.language.split("-")[0];
|
|
239
|
+
if (SUPPORTED_LOCALES.includes(browserLang)) {
|
|
240
|
+
return browserLang;
|
|
241
|
+
}
|
|
242
|
+
return DEFAULT_LOCALE;
|
|
243
|
+
}
|
|
244
|
+
function useLocaleManager({
|
|
245
|
+
configLocale,
|
|
246
|
+
preloadLocales
|
|
247
|
+
}) {
|
|
248
|
+
const [isPreloading, setIsPreloading] = useState(
|
|
249
|
+
() => preloadLocales !== void 0 && preloadLocales.length > 0
|
|
250
|
+
);
|
|
251
|
+
const preloadLocalesRef = useRef(preloadLocales);
|
|
252
|
+
preloadLocalesRef.current = preloadLocales;
|
|
253
|
+
const locale = useMemo(() => {
|
|
254
|
+
return configLocale ?? detectLocale();
|
|
255
|
+
}, [configLocale]);
|
|
256
|
+
useEffect(() => {
|
|
257
|
+
const widgets = preloadLocalesRef.current;
|
|
258
|
+
if (!widgets || widgets.length === 0) {
|
|
259
|
+
setIsPreloading(false);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (locale === "en") {
|
|
263
|
+
setIsPreloading(false);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
let isMounted = true;
|
|
267
|
+
preloadWidgets(widgets, locale).finally(() => {
|
|
268
|
+
if (isMounted) {
|
|
269
|
+
setIsPreloading(false);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
return () => {
|
|
273
|
+
isMounted = false;
|
|
274
|
+
};
|
|
275
|
+
}, [locale]);
|
|
276
|
+
return {
|
|
277
|
+
locale,
|
|
278
|
+
isPreloading
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const LOGIN_METHOD_MAP = {
|
|
282
|
+
evm_wallet: {
|
|
283
|
+
apiMethod: "loginWithEvm",
|
|
284
|
+
buildParams: (value, sign, timestamp) => ({ address: value, sign, timestamp })
|
|
285
|
+
},
|
|
286
|
+
email: {
|
|
287
|
+
apiMethod: "loginWithEmail",
|
|
288
|
+
buildParams: (value, sign, timestamp) => ({ email: value, sign, timestamp })
|
|
289
|
+
},
|
|
290
|
+
discord: {
|
|
291
|
+
apiMethod: "loginWithSns",
|
|
292
|
+
buildParams: (value, sign, timestamp) => ({ type: "Discord", token: value, sign, timestamp })
|
|
293
|
+
},
|
|
294
|
+
twitter: {
|
|
295
|
+
apiMethod: "loginWithSns",
|
|
296
|
+
buildParams: (value, sign, timestamp) => ({ type: "Twitter", token: value, sign, timestamp })
|
|
297
|
+
},
|
|
298
|
+
telegram: {
|
|
299
|
+
apiMethod: "loginWithSns",
|
|
300
|
+
buildParams: (value, sign, timestamp) => ({ type: "Telegram", token: value, sign, timestamp })
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
function useAuth({
|
|
304
|
+
client,
|
|
305
|
+
userApiRef,
|
|
306
|
+
setUserInfo,
|
|
307
|
+
setUserToken
|
|
308
|
+
}) {
|
|
309
|
+
const setToken = useCallback(
|
|
310
|
+
(token) => {
|
|
311
|
+
if (!client) {
|
|
312
|
+
throw new Error("TaskOn client not initialized");
|
|
313
|
+
}
|
|
314
|
+
client.setUserToken(token);
|
|
315
|
+
setUserToken(token);
|
|
316
|
+
setStoredToken(token);
|
|
317
|
+
},
|
|
318
|
+
[client, setUserToken]
|
|
319
|
+
);
|
|
320
|
+
const login = useCallback(
|
|
321
|
+
async (params) => {
|
|
322
|
+
const userApi = userApiRef.current;
|
|
323
|
+
if (!userApi) {
|
|
324
|
+
throw new Error("TaskOn client not initialized");
|
|
325
|
+
}
|
|
326
|
+
const { method, value, sign, timestamp } = params;
|
|
327
|
+
const methodConfig = LOGIN_METHOD_MAP[method];
|
|
328
|
+
if (!methodConfig) {
|
|
329
|
+
throw new Error(`Unsupported login method: ${method}`);
|
|
330
|
+
}
|
|
331
|
+
const apiParams = methodConfig.buildParams(value, sign, timestamp);
|
|
332
|
+
const result = await userApi[methodConfig.apiMethod](apiParams);
|
|
333
|
+
setToken(result.token);
|
|
334
|
+
try {
|
|
335
|
+
const info = await userApi.getInfo();
|
|
336
|
+
setUserInfo(info);
|
|
337
|
+
} catch {
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
[userApiRef, setToken, setUserInfo]
|
|
341
|
+
);
|
|
342
|
+
const logout = useCallback(() => {
|
|
343
|
+
if (client) {
|
|
344
|
+
client.setUserToken(null);
|
|
345
|
+
}
|
|
346
|
+
setUserInfo(null);
|
|
347
|
+
setUserToken(null);
|
|
348
|
+
removeStoredToken();
|
|
349
|
+
}, [client, setUserInfo, setUserToken]);
|
|
350
|
+
return { login, logout };
|
|
351
|
+
}
|
|
352
|
+
let ethersModule = null;
|
|
353
|
+
const interfaceCache = /* @__PURE__ */ new Map();
|
|
354
|
+
async function loadEthers() {
|
|
355
|
+
if (ethersModule) {
|
|
356
|
+
return ethersModule;
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
ethersModule = await import("ethers");
|
|
360
|
+
return ethersModule;
|
|
361
|
+
} catch {
|
|
362
|
+
throw new Error(
|
|
363
|
+
"ethers.js is required for contract invocation. Please install ethers@^6.0.0"
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function getInterface(abi) {
|
|
368
|
+
const { ethers } = await loadEthers();
|
|
369
|
+
const cacheKey = JSON.stringify(abi);
|
|
370
|
+
let iface = interfaceCache.get(cacheKey);
|
|
371
|
+
if (!iface) {
|
|
372
|
+
iface = new ethers.Interface(abi);
|
|
373
|
+
interfaceCache.set(cacheKey, iface);
|
|
374
|
+
}
|
|
375
|
+
return iface;
|
|
376
|
+
}
|
|
377
|
+
function buildEthereumAdapter(provider, initialAddress = null, initialChainId = null) {
|
|
378
|
+
let currentAddress = initialAddress;
|
|
379
|
+
let currentChainId = initialChainId;
|
|
380
|
+
const adapter = {
|
|
381
|
+
/**
|
|
382
|
+
* Connect wallet
|
|
383
|
+
*/
|
|
384
|
+
connect: async () => {
|
|
385
|
+
const accounts = await provider.request({
|
|
386
|
+
method: "eth_requestAccounts"
|
|
387
|
+
});
|
|
388
|
+
if (!accounts || accounts.length === 0) {
|
|
389
|
+
throw new Error("No accounts found");
|
|
390
|
+
}
|
|
391
|
+
const address = accounts[0];
|
|
392
|
+
if (!address) {
|
|
393
|
+
throw new Error("No accounts found");
|
|
394
|
+
}
|
|
395
|
+
currentAddress = address;
|
|
396
|
+
const chainIdHex = await provider.request({
|
|
397
|
+
method: "eth_chainId"
|
|
398
|
+
});
|
|
399
|
+
currentChainId = parseInt(chainIdHex, 16);
|
|
400
|
+
return address;
|
|
401
|
+
},
|
|
402
|
+
/**
|
|
403
|
+
* Disconnect from wallet
|
|
404
|
+
* Note: Most wallets don't support programmatic disconnect, can only clear local state
|
|
405
|
+
*/
|
|
406
|
+
disconnect: async () => {
|
|
407
|
+
currentAddress = null;
|
|
408
|
+
currentChainId = null;
|
|
409
|
+
},
|
|
410
|
+
/**
|
|
411
|
+
* Sign message (personal_sign)
|
|
412
|
+
*/
|
|
413
|
+
signMessage: async (message) => {
|
|
414
|
+
if (!currentAddress) {
|
|
415
|
+
throw new Error("Wallet not connected");
|
|
416
|
+
}
|
|
417
|
+
const signature = await provider.request({
|
|
418
|
+
method: "personal_sign",
|
|
419
|
+
params: [message, currentAddress]
|
|
420
|
+
});
|
|
421
|
+
return signature;
|
|
422
|
+
},
|
|
423
|
+
/**
|
|
424
|
+
* Get current address
|
|
425
|
+
*/
|
|
426
|
+
getAddress: () => currentAddress,
|
|
427
|
+
/**
|
|
428
|
+
* Get current chain ID
|
|
429
|
+
*/
|
|
430
|
+
getChainId: () => currentChainId,
|
|
431
|
+
/**
|
|
432
|
+
* Switch network
|
|
433
|
+
*/
|
|
434
|
+
switchNetwork: async (chainId) => {
|
|
435
|
+
const chainIdHex = `0x${chainId.toString(16)}`;
|
|
436
|
+
try {
|
|
437
|
+
await provider.request({
|
|
438
|
+
method: "wallet_switchEthereumChain",
|
|
439
|
+
params: [{ chainId: chainIdHex }]
|
|
440
|
+
});
|
|
441
|
+
currentChainId = chainId;
|
|
442
|
+
} catch (error2) {
|
|
443
|
+
const err = error2;
|
|
444
|
+
if (err.code === 4902) {
|
|
445
|
+
throw new Error("Chain not found in wallet. Please add the network manually.");
|
|
446
|
+
}
|
|
447
|
+
throw error2;
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
/**
|
|
451
|
+
* Get wallet's native token balance (for gas estimation)
|
|
452
|
+
* @returns Balance in ETH (string, formatted)
|
|
453
|
+
*/
|
|
454
|
+
getBalance: async () => {
|
|
455
|
+
if (!currentAddress) {
|
|
456
|
+
throw new Error("Wallet not connected");
|
|
457
|
+
}
|
|
458
|
+
const balanceHex = await provider.request({
|
|
459
|
+
method: "eth_getBalance",
|
|
460
|
+
params: [currentAddress, "latest"]
|
|
461
|
+
});
|
|
462
|
+
const balanceWei = BigInt(balanceHex);
|
|
463
|
+
const balanceEth = Number(balanceWei) / 1e18;
|
|
464
|
+
return balanceEth.toString();
|
|
465
|
+
},
|
|
466
|
+
/**
|
|
467
|
+
* Invoke a smart contract method
|
|
468
|
+
*
|
|
469
|
+
* 使用 ethers.js 编码合约调用,支持缓存优化:
|
|
470
|
+
* - ethers 模块只加载一次
|
|
471
|
+
* - 相同 ABI 的 Interface 实例会被缓存复用
|
|
472
|
+
*
|
|
473
|
+
* @param params - Contract invocation parameters
|
|
474
|
+
* @returns Transaction hash
|
|
475
|
+
*/
|
|
476
|
+
invokeContract: async (params) => {
|
|
477
|
+
var _a;
|
|
478
|
+
if (!currentAddress) {
|
|
479
|
+
throw new Error("Wallet not connected");
|
|
480
|
+
}
|
|
481
|
+
const { contract, abi, method, params: methodParams, chainId, value } = params;
|
|
482
|
+
if (chainId && currentChainId !== chainId) {
|
|
483
|
+
await ((_a = adapter.switchNetwork) == null ? void 0 : _a.call(adapter, chainId));
|
|
484
|
+
}
|
|
485
|
+
let encodedData;
|
|
486
|
+
try {
|
|
487
|
+
const iface = await getInterface(abi);
|
|
488
|
+
encodedData = iface.encodeFunctionData(method, methodParams);
|
|
489
|
+
} catch (error2) {
|
|
490
|
+
if (error2 instanceof Error && error2.message.includes("ethers.js is required")) {
|
|
491
|
+
throw error2;
|
|
492
|
+
}
|
|
493
|
+
throw new Error(
|
|
494
|
+
`Failed to encode contract call "${method}": ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
const txParams = {
|
|
498
|
+
from: currentAddress,
|
|
499
|
+
to: contract,
|
|
500
|
+
data: encodedData
|
|
501
|
+
};
|
|
502
|
+
if (value) {
|
|
503
|
+
txParams.value = `0x${BigInt(value).toString(16)}`;
|
|
504
|
+
}
|
|
505
|
+
const txHash = await provider.request({
|
|
506
|
+
method: "eth_sendTransaction",
|
|
507
|
+
params: [txParams]
|
|
508
|
+
});
|
|
509
|
+
return txHash;
|
|
510
|
+
},
|
|
511
|
+
/**
|
|
512
|
+
* Listen to account changes
|
|
513
|
+
*/
|
|
514
|
+
onAccountChange: (callback) => {
|
|
515
|
+
var _a;
|
|
516
|
+
const handler = (accounts) => {
|
|
517
|
+
const accountList = accounts;
|
|
518
|
+
currentAddress = accountList[0] ?? null;
|
|
519
|
+
callback(currentAddress);
|
|
520
|
+
};
|
|
521
|
+
(_a = provider.on) == null ? void 0 : _a.call(provider, "accountsChanged", handler);
|
|
522
|
+
return () => {
|
|
523
|
+
var _a2;
|
|
524
|
+
return (_a2 = provider.removeListener) == null ? void 0 : _a2.call(provider, "accountsChanged", handler);
|
|
525
|
+
};
|
|
526
|
+
},
|
|
527
|
+
/**
|
|
528
|
+
* Listen to chain changes
|
|
529
|
+
*/
|
|
530
|
+
onChainChange: (callback) => {
|
|
531
|
+
var _a;
|
|
532
|
+
const handler = (chainIdHex) => {
|
|
533
|
+
currentChainId = parseInt(chainIdHex, 16);
|
|
534
|
+
callback(currentChainId);
|
|
535
|
+
};
|
|
536
|
+
(_a = provider.on) == null ? void 0 : _a.call(provider, "chainChanged", handler);
|
|
537
|
+
return () => {
|
|
538
|
+
var _a2;
|
|
539
|
+
return (_a2 = provider.removeListener) == null ? void 0 : _a2.call(provider, "chainChanged", handler);
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
return adapter;
|
|
544
|
+
}
|
|
545
|
+
async function getProviderChainId(provider) {
|
|
546
|
+
try {
|
|
547
|
+
const chainIdHex = await provider.request({
|
|
548
|
+
method: "eth_chainId"
|
|
549
|
+
});
|
|
550
|
+
if (typeof chainIdHex !== "string") {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
return Number.parseInt(chainIdHex, 16);
|
|
554
|
+
} catch {
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function createEthereumAdapter() {
|
|
559
|
+
let selectedAdapter = null;
|
|
560
|
+
let selectingAdapterPromise = null;
|
|
561
|
+
const ensureSelectedAdapter = async () => {
|
|
562
|
+
if (selectedAdapter) {
|
|
563
|
+
return selectedAdapter;
|
|
564
|
+
}
|
|
565
|
+
if (selectingAdapterPromise) {
|
|
566
|
+
return selectingAdapterPromise;
|
|
567
|
+
}
|
|
568
|
+
selectingAdapterPromise = (async () => {
|
|
569
|
+
if (typeof window === "undefined") {
|
|
570
|
+
throw new Error(
|
|
571
|
+
"Wallet connection is only available in browser environment"
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
const { selectEvmWallet: selectEvmWallet2 } = await Promise.resolve().then(() => selectEvmWallet$1);
|
|
575
|
+
const selection = await selectEvmWallet2();
|
|
576
|
+
const chainId = await getProviderChainId(selection.provider);
|
|
577
|
+
const adapter = createEthereumAdapterFromProvider(selection.provider, {
|
|
578
|
+
address: selection.address,
|
|
579
|
+
chainId
|
|
580
|
+
});
|
|
581
|
+
selectedAdapter = adapter;
|
|
582
|
+
return adapter;
|
|
583
|
+
})();
|
|
584
|
+
try {
|
|
585
|
+
return await selectingAdapterPromise;
|
|
586
|
+
} finally {
|
|
587
|
+
selectingAdapterPromise = null;
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
return {
|
|
591
|
+
connect: async () => {
|
|
592
|
+
const adapter = await ensureSelectedAdapter();
|
|
593
|
+
const connectedAddress = adapter.getAddress();
|
|
594
|
+
if (connectedAddress) {
|
|
595
|
+
return connectedAddress;
|
|
596
|
+
}
|
|
597
|
+
return adapter.connect();
|
|
598
|
+
},
|
|
599
|
+
disconnect: async () => {
|
|
600
|
+
if (!selectedAdapter) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
await selectedAdapter.disconnect();
|
|
604
|
+
selectedAdapter = null;
|
|
605
|
+
},
|
|
606
|
+
signMessage: async (message) => {
|
|
607
|
+
const adapter = await ensureSelectedAdapter();
|
|
608
|
+
if (!adapter.getAddress()) {
|
|
609
|
+
await adapter.connect();
|
|
610
|
+
}
|
|
611
|
+
return adapter.signMessage(message);
|
|
612
|
+
},
|
|
613
|
+
getAddress: () => {
|
|
614
|
+
return (selectedAdapter == null ? void 0 : selectedAdapter.getAddress()) ?? null;
|
|
615
|
+
},
|
|
616
|
+
getChainId: () => {
|
|
617
|
+
var _a;
|
|
618
|
+
return ((_a = selectedAdapter == null ? void 0 : selectedAdapter.getChainId) == null ? void 0 : _a.call(selectedAdapter)) ?? null;
|
|
619
|
+
},
|
|
620
|
+
switchNetwork: async (chainId) => {
|
|
621
|
+
const adapter = await ensureSelectedAdapter();
|
|
622
|
+
if (!adapter.switchNetwork) {
|
|
623
|
+
throw new Error("Wallet adapter does not support network switching");
|
|
624
|
+
}
|
|
625
|
+
await adapter.switchNetwork(chainId);
|
|
626
|
+
},
|
|
627
|
+
invokeContract: async (params) => {
|
|
628
|
+
const adapter = await ensureSelectedAdapter();
|
|
629
|
+
if (!adapter.invokeContract) {
|
|
630
|
+
throw new Error("Wallet adapter does not support contract invocation");
|
|
631
|
+
}
|
|
632
|
+
if (!adapter.getAddress()) {
|
|
633
|
+
await adapter.connect();
|
|
634
|
+
}
|
|
635
|
+
return adapter.invokeContract(params);
|
|
636
|
+
},
|
|
637
|
+
getBalance: async () => {
|
|
638
|
+
const adapter = await ensureSelectedAdapter();
|
|
639
|
+
if (!adapter.getBalance) {
|
|
640
|
+
throw new Error("Wallet adapter does not support getBalance");
|
|
641
|
+
}
|
|
642
|
+
if (!adapter.getAddress()) {
|
|
643
|
+
await adapter.connect();
|
|
644
|
+
}
|
|
645
|
+
return adapter.getBalance();
|
|
646
|
+
},
|
|
647
|
+
onAccountChange: (callback) => {
|
|
648
|
+
var _a;
|
|
649
|
+
return ((_a = selectedAdapter == null ? void 0 : selectedAdapter.onAccountChange) == null ? void 0 : _a.call(selectedAdapter, callback)) ?? (() => {
|
|
650
|
+
});
|
|
651
|
+
},
|
|
652
|
+
onChainChange: (callback) => {
|
|
653
|
+
var _a;
|
|
654
|
+
return ((_a = selectedAdapter == null ? void 0 : selectedAdapter.onChainChange) == null ? void 0 : _a.call(selectedAdapter, callback)) ?? (() => {
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
function createEthereumAdapterFromProvider(provider, options = {}) {
|
|
660
|
+
return buildEthereumAdapter(
|
|
661
|
+
provider,
|
|
662
|
+
options.address ?? null,
|
|
663
|
+
options.chainId ?? null
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
function WalletProvider({
|
|
667
|
+
children,
|
|
668
|
+
config
|
|
669
|
+
}) {
|
|
670
|
+
const [state, setState] = useState({
|
|
671
|
+
adapter: (config == null ? void 0 : config.evmAdapter) ?? createEthereumAdapter(),
|
|
672
|
+
address: null,
|
|
673
|
+
chainId: null
|
|
674
|
+
});
|
|
675
|
+
useEffect(() => {
|
|
676
|
+
const nextAdapter = (config == null ? void 0 : config.evmAdapter) ?? createEthereumAdapter();
|
|
677
|
+
setState((prev) => ({
|
|
678
|
+
...prev,
|
|
679
|
+
adapter: nextAdapter,
|
|
680
|
+
address: null,
|
|
681
|
+
chainId: null
|
|
682
|
+
}));
|
|
683
|
+
}, [config == null ? void 0 : config.evmAdapter]);
|
|
684
|
+
const contextValue = useMemo(
|
|
685
|
+
() => ({
|
|
686
|
+
evmAdapter: state.adapter,
|
|
687
|
+
evmAddress: state.address,
|
|
688
|
+
evmChainId: state.chainId,
|
|
689
|
+
isEvmConnected: state.address !== null,
|
|
690
|
+
isDetecting: false,
|
|
691
|
+
// Actions - delegate to adapter
|
|
692
|
+
connectEvm: async () => {
|
|
693
|
+
if (!state.adapter) return null;
|
|
694
|
+
try {
|
|
695
|
+
const address = await state.adapter.connect();
|
|
696
|
+
setState((prev) => {
|
|
697
|
+
var _a, _b;
|
|
698
|
+
return {
|
|
699
|
+
...prev,
|
|
700
|
+
address,
|
|
701
|
+
chainId: ((_b = (_a = state.adapter) == null ? void 0 : _a.getChainId) == null ? void 0 : _b.call(_a)) ?? null
|
|
702
|
+
};
|
|
703
|
+
});
|
|
704
|
+
return address;
|
|
705
|
+
} catch {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
disconnectEvm: async () => {
|
|
710
|
+
var _a;
|
|
711
|
+
await ((_a = state.adapter) == null ? void 0 : _a.disconnect());
|
|
712
|
+
setState((prev) => ({
|
|
713
|
+
...prev,
|
|
714
|
+
address: null
|
|
715
|
+
}));
|
|
716
|
+
},
|
|
717
|
+
signEvmMessage: async (message) => {
|
|
718
|
+
if (!state.adapter) return null;
|
|
719
|
+
try {
|
|
720
|
+
return await state.adapter.signMessage(message);
|
|
721
|
+
} catch {
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}),
|
|
726
|
+
[state]
|
|
727
|
+
);
|
|
728
|
+
return /* @__PURE__ */ jsx(WalletContext.Provider, { value: contextValue, children });
|
|
729
|
+
}
|
|
730
|
+
function createCollection(name) {
|
|
731
|
+
const PROVIDER_NAME2 = name + "CollectionProvider";
|
|
732
|
+
const [createCollectionContext, createCollectionScope2] = createContextScope(PROVIDER_NAME2);
|
|
733
|
+
const [CollectionProviderImpl, useCollectionContext] = createCollectionContext(
|
|
734
|
+
PROVIDER_NAME2,
|
|
735
|
+
{ collectionRef: { current: null }, itemMap: /* @__PURE__ */ new Map() }
|
|
736
|
+
);
|
|
737
|
+
const CollectionProvider = (props) => {
|
|
738
|
+
const { scope, children } = props;
|
|
739
|
+
const ref = React__default.useRef(null);
|
|
740
|
+
const itemMap = React__default.useRef(/* @__PURE__ */ new Map()).current;
|
|
741
|
+
return /* @__PURE__ */ jsx(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
|
|
742
|
+
};
|
|
743
|
+
CollectionProvider.displayName = PROVIDER_NAME2;
|
|
744
|
+
const COLLECTION_SLOT_NAME = name + "CollectionSlot";
|
|
745
|
+
const CollectionSlotImpl = createSlot(COLLECTION_SLOT_NAME);
|
|
746
|
+
const CollectionSlot = React__default.forwardRef(
|
|
747
|
+
(props, forwardedRef) => {
|
|
748
|
+
const { scope, children } = props;
|
|
749
|
+
const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
|
|
750
|
+
const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
|
|
751
|
+
return /* @__PURE__ */ jsx(CollectionSlotImpl, { ref: composedRefs, children });
|
|
752
|
+
}
|
|
753
|
+
);
|
|
754
|
+
CollectionSlot.displayName = COLLECTION_SLOT_NAME;
|
|
755
|
+
const ITEM_SLOT_NAME = name + "CollectionItemSlot";
|
|
756
|
+
const ITEM_DATA_ATTR = "data-radix-collection-item";
|
|
757
|
+
const CollectionItemSlotImpl = createSlot(ITEM_SLOT_NAME);
|
|
758
|
+
const CollectionItemSlot = React__default.forwardRef(
|
|
759
|
+
(props, forwardedRef) => {
|
|
760
|
+
const { scope, children, ...itemData } = props;
|
|
761
|
+
const ref = React__default.useRef(null);
|
|
762
|
+
const composedRefs = useComposedRefs(forwardedRef, ref);
|
|
763
|
+
const context = useCollectionContext(ITEM_SLOT_NAME, scope);
|
|
764
|
+
React__default.useEffect(() => {
|
|
765
|
+
context.itemMap.set(ref, { ref, ...itemData });
|
|
766
|
+
return () => void context.itemMap.delete(ref);
|
|
767
|
+
});
|
|
768
|
+
return /* @__PURE__ */ jsx(CollectionItemSlotImpl, { ...{ [ITEM_DATA_ATTR]: "" }, ref: composedRefs, children });
|
|
769
|
+
}
|
|
770
|
+
);
|
|
771
|
+
CollectionItemSlot.displayName = ITEM_SLOT_NAME;
|
|
772
|
+
function useCollection2(scope) {
|
|
773
|
+
const context = useCollectionContext(name + "CollectionConsumer", scope);
|
|
774
|
+
const getItems = React__default.useCallback(() => {
|
|
775
|
+
const collectionNode = context.collectionRef.current;
|
|
776
|
+
if (!collectionNode) return [];
|
|
777
|
+
const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
|
|
778
|
+
const items = Array.from(context.itemMap.values());
|
|
779
|
+
const orderedItems = items.sort(
|
|
780
|
+
(a, b) => orderedNodes.indexOf(a.ref.current) - orderedNodes.indexOf(b.ref.current)
|
|
781
|
+
);
|
|
782
|
+
return orderedItems;
|
|
783
|
+
}, [context.collectionRef, context.itemMap]);
|
|
784
|
+
return getItems;
|
|
785
|
+
}
|
|
786
|
+
return [
|
|
787
|
+
{ Provider: CollectionProvider, Slot: CollectionSlot, ItemSlot: CollectionItemSlot },
|
|
788
|
+
useCollection2,
|
|
789
|
+
createCollectionScope2
|
|
790
|
+
];
|
|
791
|
+
}
|
|
792
|
+
var VISUALLY_HIDDEN_STYLES = Object.freeze({
|
|
793
|
+
// See: https://github.com/twbs/bootstrap/blob/main/scss/mixins/_visually-hidden.scss
|
|
794
|
+
position: "absolute",
|
|
795
|
+
border: 0,
|
|
796
|
+
width: 1,
|
|
797
|
+
height: 1,
|
|
798
|
+
padding: 0,
|
|
799
|
+
margin: -1,
|
|
800
|
+
overflow: "hidden",
|
|
801
|
+
clip: "rect(0, 0, 0, 0)",
|
|
802
|
+
whiteSpace: "nowrap",
|
|
803
|
+
wordWrap: "normal"
|
|
804
|
+
});
|
|
805
|
+
var NAME = "VisuallyHidden";
|
|
806
|
+
var VisuallyHidden = React.forwardRef(
|
|
807
|
+
(props, forwardedRef) => {
|
|
808
|
+
return /* @__PURE__ */ jsx(
|
|
809
|
+
Primitive.span,
|
|
810
|
+
{
|
|
811
|
+
...props,
|
|
812
|
+
ref: forwardedRef,
|
|
813
|
+
style: { ...VISUALLY_HIDDEN_STYLES, ...props.style }
|
|
814
|
+
}
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
);
|
|
818
|
+
VisuallyHidden.displayName = NAME;
|
|
819
|
+
var PROVIDER_NAME = "ToastProvider";
|
|
820
|
+
var [Collection, useCollection, createCollectionScope] = createCollection("Toast");
|
|
821
|
+
var [createToastContext] = createContextScope("Toast", [createCollectionScope]);
|
|
822
|
+
var [ToastProviderProvider, useToastProviderContext] = createToastContext(PROVIDER_NAME);
|
|
823
|
+
var ToastProvider$1 = (props) => {
|
|
824
|
+
const {
|
|
825
|
+
__scopeToast,
|
|
826
|
+
label = "Notification",
|
|
827
|
+
duration = 5e3,
|
|
828
|
+
swipeDirection = "right",
|
|
829
|
+
swipeThreshold = 50,
|
|
830
|
+
children
|
|
831
|
+
} = props;
|
|
832
|
+
const [viewport, setViewport] = React.useState(null);
|
|
833
|
+
const [toastCount, setToastCount] = React.useState(0);
|
|
834
|
+
const isFocusedToastEscapeKeyDownRef = React.useRef(false);
|
|
835
|
+
const isClosePausedRef = React.useRef(false);
|
|
836
|
+
if (!label.trim()) {
|
|
837
|
+
console.error(
|
|
838
|
+
`Invalid prop \`label\` supplied to \`${PROVIDER_NAME}\`. Expected non-empty \`string\`.`
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
return /* @__PURE__ */ jsx(Collection.Provider, { scope: __scopeToast, children: /* @__PURE__ */ jsx(
|
|
842
|
+
ToastProviderProvider,
|
|
843
|
+
{
|
|
844
|
+
scope: __scopeToast,
|
|
845
|
+
label,
|
|
846
|
+
duration,
|
|
847
|
+
swipeDirection,
|
|
848
|
+
swipeThreshold,
|
|
849
|
+
toastCount,
|
|
850
|
+
viewport,
|
|
851
|
+
onViewportChange: setViewport,
|
|
852
|
+
onToastAdd: React.useCallback(() => setToastCount((prevCount) => prevCount + 1), []),
|
|
853
|
+
onToastRemove: React.useCallback(() => setToastCount((prevCount) => prevCount - 1), []),
|
|
854
|
+
isFocusedToastEscapeKeyDownRef,
|
|
855
|
+
isClosePausedRef,
|
|
856
|
+
children
|
|
857
|
+
}
|
|
858
|
+
) });
|
|
859
|
+
};
|
|
860
|
+
ToastProvider$1.displayName = PROVIDER_NAME;
|
|
861
|
+
var VIEWPORT_NAME = "ToastViewport";
|
|
862
|
+
var VIEWPORT_DEFAULT_HOTKEY = ["F8"];
|
|
863
|
+
var VIEWPORT_PAUSE = "toast.viewportPause";
|
|
864
|
+
var VIEWPORT_RESUME = "toast.viewportResume";
|
|
865
|
+
var ToastViewport$1 = React.forwardRef(
|
|
866
|
+
(props, forwardedRef) => {
|
|
867
|
+
const {
|
|
868
|
+
__scopeToast,
|
|
869
|
+
hotkey = VIEWPORT_DEFAULT_HOTKEY,
|
|
870
|
+
label = "Notifications ({hotkey})",
|
|
871
|
+
...viewportProps
|
|
872
|
+
} = props;
|
|
873
|
+
const context = useToastProviderContext(VIEWPORT_NAME, __scopeToast);
|
|
874
|
+
const getItems = useCollection(__scopeToast);
|
|
875
|
+
const wrapperRef = React.useRef(null);
|
|
876
|
+
const headFocusProxyRef = React.useRef(null);
|
|
877
|
+
const tailFocusProxyRef = React.useRef(null);
|
|
878
|
+
const ref = React.useRef(null);
|
|
879
|
+
const composedRefs = useComposedRefs(forwardedRef, ref, context.onViewportChange);
|
|
880
|
+
const hotkeyLabel = hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, "");
|
|
881
|
+
const hasToasts = context.toastCount > 0;
|
|
882
|
+
React.useEffect(() => {
|
|
883
|
+
const handleKeyDown = (event) => {
|
|
884
|
+
var _a;
|
|
885
|
+
const isHotkeyPressed = hotkey.length !== 0 && hotkey.every((key) => event[key] || event.code === key);
|
|
886
|
+
if (isHotkeyPressed) (_a = ref.current) == null ? void 0 : _a.focus();
|
|
887
|
+
};
|
|
888
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
889
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
890
|
+
}, [hotkey]);
|
|
891
|
+
React.useEffect(() => {
|
|
892
|
+
const wrapper = wrapperRef.current;
|
|
893
|
+
const viewport = ref.current;
|
|
894
|
+
if (hasToasts && wrapper && viewport) {
|
|
895
|
+
const handlePause = () => {
|
|
896
|
+
if (!context.isClosePausedRef.current) {
|
|
897
|
+
const pauseEvent = new CustomEvent(VIEWPORT_PAUSE);
|
|
898
|
+
viewport.dispatchEvent(pauseEvent);
|
|
899
|
+
context.isClosePausedRef.current = true;
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
const handleResume = () => {
|
|
903
|
+
if (context.isClosePausedRef.current) {
|
|
904
|
+
const resumeEvent = new CustomEvent(VIEWPORT_RESUME);
|
|
905
|
+
viewport.dispatchEvent(resumeEvent);
|
|
906
|
+
context.isClosePausedRef.current = false;
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
const handleFocusOutResume = (event) => {
|
|
910
|
+
const isFocusMovingOutside = !wrapper.contains(event.relatedTarget);
|
|
911
|
+
if (isFocusMovingOutside) handleResume();
|
|
912
|
+
};
|
|
913
|
+
const handlePointerLeaveResume = () => {
|
|
914
|
+
const isFocusInside = wrapper.contains(document.activeElement);
|
|
915
|
+
if (!isFocusInside) handleResume();
|
|
916
|
+
};
|
|
917
|
+
wrapper.addEventListener("focusin", handlePause);
|
|
918
|
+
wrapper.addEventListener("focusout", handleFocusOutResume);
|
|
919
|
+
wrapper.addEventListener("pointermove", handlePause);
|
|
920
|
+
wrapper.addEventListener("pointerleave", handlePointerLeaveResume);
|
|
921
|
+
window.addEventListener("blur", handlePause);
|
|
922
|
+
window.addEventListener("focus", handleResume);
|
|
923
|
+
return () => {
|
|
924
|
+
wrapper.removeEventListener("focusin", handlePause);
|
|
925
|
+
wrapper.removeEventListener("focusout", handleFocusOutResume);
|
|
926
|
+
wrapper.removeEventListener("pointermove", handlePause);
|
|
927
|
+
wrapper.removeEventListener("pointerleave", handlePointerLeaveResume);
|
|
928
|
+
window.removeEventListener("blur", handlePause);
|
|
929
|
+
window.removeEventListener("focus", handleResume);
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
}, [hasToasts, context.isClosePausedRef]);
|
|
933
|
+
const getSortedTabbableCandidates = React.useCallback(
|
|
934
|
+
({ tabbingDirection }) => {
|
|
935
|
+
const toastItems = getItems();
|
|
936
|
+
const tabbableCandidates = toastItems.map((toastItem) => {
|
|
937
|
+
const toastNode = toastItem.ref.current;
|
|
938
|
+
const toastTabbableCandidates = [toastNode, ...getTabbableCandidates(toastNode)];
|
|
939
|
+
return tabbingDirection === "forwards" ? toastTabbableCandidates : toastTabbableCandidates.reverse();
|
|
940
|
+
});
|
|
941
|
+
return (tabbingDirection === "forwards" ? tabbableCandidates.reverse() : tabbableCandidates).flat();
|
|
942
|
+
},
|
|
943
|
+
[getItems]
|
|
944
|
+
);
|
|
945
|
+
React.useEffect(() => {
|
|
946
|
+
const viewport = ref.current;
|
|
947
|
+
if (viewport) {
|
|
948
|
+
const handleKeyDown = (event) => {
|
|
949
|
+
var _a, _b, _c;
|
|
950
|
+
const isMetaKey = event.altKey || event.ctrlKey || event.metaKey;
|
|
951
|
+
const isTabKey = event.key === "Tab" && !isMetaKey;
|
|
952
|
+
if (isTabKey) {
|
|
953
|
+
const focusedElement = document.activeElement;
|
|
954
|
+
const isTabbingBackwards = event.shiftKey;
|
|
955
|
+
const targetIsViewport = event.target === viewport;
|
|
956
|
+
if (targetIsViewport && isTabbingBackwards) {
|
|
957
|
+
(_a = headFocusProxyRef.current) == null ? void 0 : _a.focus();
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
const tabbingDirection = isTabbingBackwards ? "backwards" : "forwards";
|
|
961
|
+
const sortedCandidates = getSortedTabbableCandidates({ tabbingDirection });
|
|
962
|
+
const index = sortedCandidates.findIndex((candidate) => candidate === focusedElement);
|
|
963
|
+
if (focusFirst(sortedCandidates.slice(index + 1))) {
|
|
964
|
+
event.preventDefault();
|
|
965
|
+
} else {
|
|
966
|
+
isTabbingBackwards ? (_b = headFocusProxyRef.current) == null ? void 0 : _b.focus() : (_c = tailFocusProxyRef.current) == null ? void 0 : _c.focus();
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
viewport.addEventListener("keydown", handleKeyDown);
|
|
971
|
+
return () => viewport.removeEventListener("keydown", handleKeyDown);
|
|
972
|
+
}
|
|
973
|
+
}, [getItems, getSortedTabbableCandidates]);
|
|
974
|
+
return /* @__PURE__ */ jsxs(
|
|
975
|
+
Branch,
|
|
976
|
+
{
|
|
977
|
+
ref: wrapperRef,
|
|
978
|
+
role: "region",
|
|
979
|
+
"aria-label": label.replace("{hotkey}", hotkeyLabel),
|
|
980
|
+
tabIndex: -1,
|
|
981
|
+
style: { pointerEvents: hasToasts ? void 0 : "none" },
|
|
982
|
+
children: [
|
|
983
|
+
hasToasts && /* @__PURE__ */ jsx(
|
|
984
|
+
FocusProxy,
|
|
985
|
+
{
|
|
986
|
+
ref: headFocusProxyRef,
|
|
987
|
+
onFocusFromOutsideViewport: () => {
|
|
988
|
+
const tabbableCandidates = getSortedTabbableCandidates({
|
|
989
|
+
tabbingDirection: "forwards"
|
|
990
|
+
});
|
|
991
|
+
focusFirst(tabbableCandidates);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
),
|
|
995
|
+
/* @__PURE__ */ jsx(Collection.Slot, { scope: __scopeToast, children: /* @__PURE__ */ jsx(Primitive.ol, { tabIndex: -1, ...viewportProps, ref: composedRefs }) }),
|
|
996
|
+
hasToasts && /* @__PURE__ */ jsx(
|
|
997
|
+
FocusProxy,
|
|
998
|
+
{
|
|
999
|
+
ref: tailFocusProxyRef,
|
|
1000
|
+
onFocusFromOutsideViewport: () => {
|
|
1001
|
+
const tabbableCandidates = getSortedTabbableCandidates({
|
|
1002
|
+
tabbingDirection: "backwards"
|
|
1003
|
+
});
|
|
1004
|
+
focusFirst(tabbableCandidates);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
)
|
|
1008
|
+
]
|
|
1009
|
+
}
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
ToastViewport$1.displayName = VIEWPORT_NAME;
|
|
1014
|
+
var FOCUS_PROXY_NAME = "ToastFocusProxy";
|
|
1015
|
+
var FocusProxy = React.forwardRef(
|
|
1016
|
+
(props, forwardedRef) => {
|
|
1017
|
+
const { __scopeToast, onFocusFromOutsideViewport, ...proxyProps } = props;
|
|
1018
|
+
const context = useToastProviderContext(FOCUS_PROXY_NAME, __scopeToast);
|
|
1019
|
+
return /* @__PURE__ */ jsx(
|
|
1020
|
+
VisuallyHidden,
|
|
1021
|
+
{
|
|
1022
|
+
tabIndex: 0,
|
|
1023
|
+
...proxyProps,
|
|
1024
|
+
ref: forwardedRef,
|
|
1025
|
+
style: { position: "fixed" },
|
|
1026
|
+
onFocus: (event) => {
|
|
1027
|
+
var _a;
|
|
1028
|
+
const prevFocusedElement = event.relatedTarget;
|
|
1029
|
+
const isFocusFromOutsideViewport = !((_a = context.viewport) == null ? void 0 : _a.contains(prevFocusedElement));
|
|
1030
|
+
if (isFocusFromOutsideViewport) onFocusFromOutsideViewport();
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
);
|
|
1036
|
+
FocusProxy.displayName = FOCUS_PROXY_NAME;
|
|
1037
|
+
var TOAST_NAME = "Toast";
|
|
1038
|
+
var TOAST_SWIPE_START = "toast.swipeStart";
|
|
1039
|
+
var TOAST_SWIPE_MOVE = "toast.swipeMove";
|
|
1040
|
+
var TOAST_SWIPE_CANCEL = "toast.swipeCancel";
|
|
1041
|
+
var TOAST_SWIPE_END = "toast.swipeEnd";
|
|
1042
|
+
var Toast = React.forwardRef(
|
|
1043
|
+
(props, forwardedRef) => {
|
|
1044
|
+
const { forceMount, open: openProp, defaultOpen, onOpenChange, ...toastProps } = props;
|
|
1045
|
+
const [open, setOpen] = useControllableState({
|
|
1046
|
+
prop: openProp,
|
|
1047
|
+
defaultProp: defaultOpen ?? true,
|
|
1048
|
+
onChange: onOpenChange,
|
|
1049
|
+
caller: TOAST_NAME
|
|
1050
|
+
});
|
|
1051
|
+
return /* @__PURE__ */ jsx(Presence, { present: forceMount || open, children: /* @__PURE__ */ jsx(
|
|
1052
|
+
ToastImpl,
|
|
1053
|
+
{
|
|
1054
|
+
open,
|
|
1055
|
+
...toastProps,
|
|
1056
|
+
ref: forwardedRef,
|
|
1057
|
+
onClose: () => setOpen(false),
|
|
1058
|
+
onPause: useCallbackRef(props.onPause),
|
|
1059
|
+
onResume: useCallbackRef(props.onResume),
|
|
1060
|
+
onSwipeStart: composeEventHandlers(props.onSwipeStart, (event) => {
|
|
1061
|
+
event.currentTarget.setAttribute("data-swipe", "start");
|
|
1062
|
+
}),
|
|
1063
|
+
onSwipeMove: composeEventHandlers(props.onSwipeMove, (event) => {
|
|
1064
|
+
const { x, y } = event.detail.delta;
|
|
1065
|
+
event.currentTarget.setAttribute("data-swipe", "move");
|
|
1066
|
+
event.currentTarget.style.setProperty("--radix-toast-swipe-move-x", `${x}px`);
|
|
1067
|
+
event.currentTarget.style.setProperty("--radix-toast-swipe-move-y", `${y}px`);
|
|
1068
|
+
}),
|
|
1069
|
+
onSwipeCancel: composeEventHandlers(props.onSwipeCancel, (event) => {
|
|
1070
|
+
event.currentTarget.setAttribute("data-swipe", "cancel");
|
|
1071
|
+
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-x");
|
|
1072
|
+
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-y");
|
|
1073
|
+
event.currentTarget.style.removeProperty("--radix-toast-swipe-end-x");
|
|
1074
|
+
event.currentTarget.style.removeProperty("--radix-toast-swipe-end-y");
|
|
1075
|
+
}),
|
|
1076
|
+
onSwipeEnd: composeEventHandlers(props.onSwipeEnd, (event) => {
|
|
1077
|
+
const { x, y } = event.detail.delta;
|
|
1078
|
+
event.currentTarget.setAttribute("data-swipe", "end");
|
|
1079
|
+
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-x");
|
|
1080
|
+
event.currentTarget.style.removeProperty("--radix-toast-swipe-move-y");
|
|
1081
|
+
event.currentTarget.style.setProperty("--radix-toast-swipe-end-x", `${x}px`);
|
|
1082
|
+
event.currentTarget.style.setProperty("--radix-toast-swipe-end-y", `${y}px`);
|
|
1083
|
+
setOpen(false);
|
|
1084
|
+
})
|
|
1085
|
+
}
|
|
1086
|
+
) });
|
|
1087
|
+
}
|
|
1088
|
+
);
|
|
1089
|
+
Toast.displayName = TOAST_NAME;
|
|
1090
|
+
var [ToastInteractiveProvider, useToastInteractiveContext] = createToastContext(TOAST_NAME, {
|
|
1091
|
+
onClose() {
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1094
|
+
var ToastImpl = React.forwardRef(
|
|
1095
|
+
(props, forwardedRef) => {
|
|
1096
|
+
const {
|
|
1097
|
+
__scopeToast,
|
|
1098
|
+
type = "foreground",
|
|
1099
|
+
duration: durationProp,
|
|
1100
|
+
open,
|
|
1101
|
+
onClose,
|
|
1102
|
+
onEscapeKeyDown,
|
|
1103
|
+
onPause,
|
|
1104
|
+
onResume,
|
|
1105
|
+
onSwipeStart,
|
|
1106
|
+
onSwipeMove,
|
|
1107
|
+
onSwipeCancel,
|
|
1108
|
+
onSwipeEnd,
|
|
1109
|
+
...toastProps
|
|
1110
|
+
} = props;
|
|
1111
|
+
const context = useToastProviderContext(TOAST_NAME, __scopeToast);
|
|
1112
|
+
const [node, setNode] = React.useState(null);
|
|
1113
|
+
const composedRefs = useComposedRefs(forwardedRef, (node2) => setNode(node2));
|
|
1114
|
+
const pointerStartRef = React.useRef(null);
|
|
1115
|
+
const swipeDeltaRef = React.useRef(null);
|
|
1116
|
+
const duration = durationProp || context.duration;
|
|
1117
|
+
const closeTimerStartTimeRef = React.useRef(0);
|
|
1118
|
+
const closeTimerRemainingTimeRef = React.useRef(duration);
|
|
1119
|
+
const closeTimerRef = React.useRef(0);
|
|
1120
|
+
const { onToastAdd, onToastRemove } = context;
|
|
1121
|
+
const handleClose = useCallbackRef(() => {
|
|
1122
|
+
var _a;
|
|
1123
|
+
const isFocusInToast = node == null ? void 0 : node.contains(document.activeElement);
|
|
1124
|
+
if (isFocusInToast) (_a = context.viewport) == null ? void 0 : _a.focus();
|
|
1125
|
+
onClose();
|
|
1126
|
+
});
|
|
1127
|
+
const startTimer = React.useCallback(
|
|
1128
|
+
(duration2) => {
|
|
1129
|
+
if (!duration2 || duration2 === Infinity) return;
|
|
1130
|
+
window.clearTimeout(closeTimerRef.current);
|
|
1131
|
+
closeTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
|
|
1132
|
+
closeTimerRef.current = window.setTimeout(handleClose, duration2);
|
|
1133
|
+
},
|
|
1134
|
+
[handleClose]
|
|
1135
|
+
);
|
|
1136
|
+
React.useEffect(() => {
|
|
1137
|
+
const viewport = context.viewport;
|
|
1138
|
+
if (viewport) {
|
|
1139
|
+
const handleResume = () => {
|
|
1140
|
+
startTimer(closeTimerRemainingTimeRef.current);
|
|
1141
|
+
onResume == null ? void 0 : onResume();
|
|
1142
|
+
};
|
|
1143
|
+
const handlePause = () => {
|
|
1144
|
+
const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - closeTimerStartTimeRef.current;
|
|
1145
|
+
closeTimerRemainingTimeRef.current = closeTimerRemainingTimeRef.current - elapsedTime;
|
|
1146
|
+
window.clearTimeout(closeTimerRef.current);
|
|
1147
|
+
onPause == null ? void 0 : onPause();
|
|
1148
|
+
};
|
|
1149
|
+
viewport.addEventListener(VIEWPORT_PAUSE, handlePause);
|
|
1150
|
+
viewport.addEventListener(VIEWPORT_RESUME, handleResume);
|
|
1151
|
+
return () => {
|
|
1152
|
+
viewport.removeEventListener(VIEWPORT_PAUSE, handlePause);
|
|
1153
|
+
viewport.removeEventListener(VIEWPORT_RESUME, handleResume);
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
}, [context.viewport, duration, onPause, onResume, startTimer]);
|
|
1157
|
+
React.useEffect(() => {
|
|
1158
|
+
if (open && !context.isClosePausedRef.current) startTimer(duration);
|
|
1159
|
+
}, [open, duration, context.isClosePausedRef, startTimer]);
|
|
1160
|
+
React.useEffect(() => {
|
|
1161
|
+
onToastAdd();
|
|
1162
|
+
return () => onToastRemove();
|
|
1163
|
+
}, [onToastAdd, onToastRemove]);
|
|
1164
|
+
const announceTextContent = React.useMemo(() => {
|
|
1165
|
+
return node ? getAnnounceTextContent(node) : null;
|
|
1166
|
+
}, [node]);
|
|
1167
|
+
if (!context.viewport) return null;
|
|
1168
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1169
|
+
announceTextContent && /* @__PURE__ */ jsx(
|
|
1170
|
+
ToastAnnounce,
|
|
1171
|
+
{
|
|
1172
|
+
__scopeToast,
|
|
1173
|
+
role: "status",
|
|
1174
|
+
"aria-live": type === "foreground" ? "assertive" : "polite",
|
|
1175
|
+
children: announceTextContent
|
|
1176
|
+
}
|
|
1177
|
+
),
|
|
1178
|
+
/* @__PURE__ */ jsx(ToastInteractiveProvider, { scope: __scopeToast, onClose: handleClose, children: ReactDOM.createPortal(
|
|
1179
|
+
/* @__PURE__ */ jsx(Collection.ItemSlot, { scope: __scopeToast, children: /* @__PURE__ */ jsx(
|
|
1180
|
+
Root,
|
|
1181
|
+
{
|
|
1182
|
+
asChild: true,
|
|
1183
|
+
onEscapeKeyDown: composeEventHandlers(onEscapeKeyDown, () => {
|
|
1184
|
+
if (!context.isFocusedToastEscapeKeyDownRef.current) handleClose();
|
|
1185
|
+
context.isFocusedToastEscapeKeyDownRef.current = false;
|
|
1186
|
+
}),
|
|
1187
|
+
children: /* @__PURE__ */ jsx(
|
|
1188
|
+
Primitive.li,
|
|
1189
|
+
{
|
|
1190
|
+
tabIndex: 0,
|
|
1191
|
+
"data-state": open ? "open" : "closed",
|
|
1192
|
+
"data-swipe-direction": context.swipeDirection,
|
|
1193
|
+
...toastProps,
|
|
1194
|
+
ref: composedRefs,
|
|
1195
|
+
style: { userSelect: "none", touchAction: "none", ...props.style },
|
|
1196
|
+
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
|
1197
|
+
if (event.key !== "Escape") return;
|
|
1198
|
+
onEscapeKeyDown == null ? void 0 : onEscapeKeyDown(event.nativeEvent);
|
|
1199
|
+
if (!event.nativeEvent.defaultPrevented) {
|
|
1200
|
+
context.isFocusedToastEscapeKeyDownRef.current = true;
|
|
1201
|
+
handleClose();
|
|
1202
|
+
}
|
|
1203
|
+
}),
|
|
1204
|
+
onPointerDown: composeEventHandlers(props.onPointerDown, (event) => {
|
|
1205
|
+
if (event.button !== 0) return;
|
|
1206
|
+
pointerStartRef.current = { x: event.clientX, y: event.clientY };
|
|
1207
|
+
}),
|
|
1208
|
+
onPointerMove: composeEventHandlers(props.onPointerMove, (event) => {
|
|
1209
|
+
if (!pointerStartRef.current) return;
|
|
1210
|
+
const x = event.clientX - pointerStartRef.current.x;
|
|
1211
|
+
const y = event.clientY - pointerStartRef.current.y;
|
|
1212
|
+
const hasSwipeMoveStarted = Boolean(swipeDeltaRef.current);
|
|
1213
|
+
const isHorizontalSwipe = ["left", "right"].includes(context.swipeDirection);
|
|
1214
|
+
const clamp = ["left", "up"].includes(context.swipeDirection) ? Math.min : Math.max;
|
|
1215
|
+
const clampedX = isHorizontalSwipe ? clamp(0, x) : 0;
|
|
1216
|
+
const clampedY = !isHorizontalSwipe ? clamp(0, y) : 0;
|
|
1217
|
+
const moveStartBuffer = event.pointerType === "touch" ? 10 : 2;
|
|
1218
|
+
const delta = { x: clampedX, y: clampedY };
|
|
1219
|
+
const eventDetail = { originalEvent: event, delta };
|
|
1220
|
+
if (hasSwipeMoveStarted) {
|
|
1221
|
+
swipeDeltaRef.current = delta;
|
|
1222
|
+
handleAndDispatchCustomEvent(TOAST_SWIPE_MOVE, onSwipeMove, eventDetail, {
|
|
1223
|
+
discrete: false
|
|
1224
|
+
});
|
|
1225
|
+
} else if (isDeltaInDirection(delta, context.swipeDirection, moveStartBuffer)) {
|
|
1226
|
+
swipeDeltaRef.current = delta;
|
|
1227
|
+
handleAndDispatchCustomEvent(TOAST_SWIPE_START, onSwipeStart, eventDetail, {
|
|
1228
|
+
discrete: false
|
|
1229
|
+
});
|
|
1230
|
+
event.target.setPointerCapture(event.pointerId);
|
|
1231
|
+
} else if (Math.abs(x) > moveStartBuffer || Math.abs(y) > moveStartBuffer) {
|
|
1232
|
+
pointerStartRef.current = null;
|
|
1233
|
+
}
|
|
1234
|
+
}),
|
|
1235
|
+
onPointerUp: composeEventHandlers(props.onPointerUp, (event) => {
|
|
1236
|
+
const delta = swipeDeltaRef.current;
|
|
1237
|
+
const target = event.target;
|
|
1238
|
+
if (target.hasPointerCapture(event.pointerId)) {
|
|
1239
|
+
target.releasePointerCapture(event.pointerId);
|
|
1240
|
+
}
|
|
1241
|
+
swipeDeltaRef.current = null;
|
|
1242
|
+
pointerStartRef.current = null;
|
|
1243
|
+
if (delta) {
|
|
1244
|
+
const toast = event.currentTarget;
|
|
1245
|
+
const eventDetail = { originalEvent: event, delta };
|
|
1246
|
+
if (isDeltaInDirection(delta, context.swipeDirection, context.swipeThreshold)) {
|
|
1247
|
+
handleAndDispatchCustomEvent(TOAST_SWIPE_END, onSwipeEnd, eventDetail, {
|
|
1248
|
+
discrete: true
|
|
1249
|
+
});
|
|
1250
|
+
} else {
|
|
1251
|
+
handleAndDispatchCustomEvent(
|
|
1252
|
+
TOAST_SWIPE_CANCEL,
|
|
1253
|
+
onSwipeCancel,
|
|
1254
|
+
eventDetail,
|
|
1255
|
+
{
|
|
1256
|
+
discrete: true
|
|
1257
|
+
}
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
toast.addEventListener("click", (event2) => event2.preventDefault(), {
|
|
1261
|
+
once: true
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
})
|
|
1265
|
+
}
|
|
1266
|
+
)
|
|
1267
|
+
}
|
|
1268
|
+
) }),
|
|
1269
|
+
context.viewport
|
|
1270
|
+
) })
|
|
1271
|
+
] });
|
|
1272
|
+
}
|
|
1273
|
+
);
|
|
1274
|
+
var ToastAnnounce = (props) => {
|
|
1275
|
+
const { __scopeToast, children, ...announceProps } = props;
|
|
1276
|
+
const context = useToastProviderContext(TOAST_NAME, __scopeToast);
|
|
1277
|
+
const [renderAnnounceText, setRenderAnnounceText] = React.useState(false);
|
|
1278
|
+
const [isAnnounced, setIsAnnounced] = React.useState(false);
|
|
1279
|
+
useNextFrame(() => setRenderAnnounceText(true));
|
|
1280
|
+
React.useEffect(() => {
|
|
1281
|
+
const timer = window.setTimeout(() => setIsAnnounced(true), 1e3);
|
|
1282
|
+
return () => window.clearTimeout(timer);
|
|
1283
|
+
}, []);
|
|
1284
|
+
return isAnnounced ? null : /* @__PURE__ */ jsx(Portal, { asChild: true, children: /* @__PURE__ */ jsx(VisuallyHidden, { ...announceProps, children: renderAnnounceText && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1285
|
+
context.label,
|
|
1286
|
+
" ",
|
|
1287
|
+
children
|
|
1288
|
+
] }) }) });
|
|
1289
|
+
};
|
|
1290
|
+
var TITLE_NAME = "ToastTitle";
|
|
1291
|
+
var ToastTitle = React.forwardRef(
|
|
1292
|
+
(props, forwardedRef) => {
|
|
1293
|
+
const { __scopeToast, ...titleProps } = props;
|
|
1294
|
+
return /* @__PURE__ */ jsx(Primitive.div, { ...titleProps, ref: forwardedRef });
|
|
1295
|
+
}
|
|
1296
|
+
);
|
|
1297
|
+
ToastTitle.displayName = TITLE_NAME;
|
|
1298
|
+
var DESCRIPTION_NAME = "ToastDescription";
|
|
1299
|
+
var ToastDescription = React.forwardRef(
|
|
1300
|
+
(props, forwardedRef) => {
|
|
1301
|
+
const { __scopeToast, ...descriptionProps } = props;
|
|
1302
|
+
return /* @__PURE__ */ jsx(Primitive.div, { ...descriptionProps, ref: forwardedRef });
|
|
1303
|
+
}
|
|
1304
|
+
);
|
|
1305
|
+
ToastDescription.displayName = DESCRIPTION_NAME;
|
|
1306
|
+
var ACTION_NAME = "ToastAction";
|
|
1307
|
+
var ToastAction = React.forwardRef(
|
|
1308
|
+
(props, forwardedRef) => {
|
|
1309
|
+
const { altText, ...actionProps } = props;
|
|
1310
|
+
if (!altText.trim()) {
|
|
1311
|
+
console.error(
|
|
1312
|
+
`Invalid prop \`altText\` supplied to \`${ACTION_NAME}\`. Expected non-empty \`string\`.`
|
|
1313
|
+
);
|
|
1314
|
+
return null;
|
|
1315
|
+
}
|
|
1316
|
+
return /* @__PURE__ */ jsx(ToastAnnounceExclude, { altText, asChild: true, children: /* @__PURE__ */ jsx(ToastClose, { ...actionProps, ref: forwardedRef }) });
|
|
1317
|
+
}
|
|
1318
|
+
);
|
|
1319
|
+
ToastAction.displayName = ACTION_NAME;
|
|
1320
|
+
var CLOSE_NAME = "ToastClose";
|
|
1321
|
+
var ToastClose = React.forwardRef(
|
|
1322
|
+
(props, forwardedRef) => {
|
|
1323
|
+
const { __scopeToast, ...closeProps } = props;
|
|
1324
|
+
const interactiveContext = useToastInteractiveContext(CLOSE_NAME, __scopeToast);
|
|
1325
|
+
return /* @__PURE__ */ jsx(ToastAnnounceExclude, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1326
|
+
Primitive.button,
|
|
1327
|
+
{
|
|
1328
|
+
type: "button",
|
|
1329
|
+
...closeProps,
|
|
1330
|
+
ref: forwardedRef,
|
|
1331
|
+
onClick: composeEventHandlers(props.onClick, interactiveContext.onClose)
|
|
1332
|
+
}
|
|
1333
|
+
) });
|
|
1334
|
+
}
|
|
1335
|
+
);
|
|
1336
|
+
ToastClose.displayName = CLOSE_NAME;
|
|
1337
|
+
var ToastAnnounceExclude = React.forwardRef((props, forwardedRef) => {
|
|
1338
|
+
const { __scopeToast, altText, ...announceExcludeProps } = props;
|
|
1339
|
+
return /* @__PURE__ */ jsx(
|
|
1340
|
+
Primitive.div,
|
|
1341
|
+
{
|
|
1342
|
+
"data-radix-toast-announce-exclude": "",
|
|
1343
|
+
"data-radix-toast-announce-alt": altText || void 0,
|
|
1344
|
+
...announceExcludeProps,
|
|
1345
|
+
ref: forwardedRef
|
|
1346
|
+
}
|
|
1347
|
+
);
|
|
1348
|
+
});
|
|
1349
|
+
function getAnnounceTextContent(container) {
|
|
1350
|
+
const textContent = [];
|
|
1351
|
+
const childNodes = Array.from(container.childNodes);
|
|
1352
|
+
childNodes.forEach((node) => {
|
|
1353
|
+
if (node.nodeType === node.TEXT_NODE && node.textContent) textContent.push(node.textContent);
|
|
1354
|
+
if (isHTMLElement(node)) {
|
|
1355
|
+
const isHidden = node.ariaHidden || node.hidden || node.style.display === "none";
|
|
1356
|
+
const isExcluded = node.dataset.radixToastAnnounceExclude === "";
|
|
1357
|
+
if (!isHidden) {
|
|
1358
|
+
if (isExcluded) {
|
|
1359
|
+
const altText = node.dataset.radixToastAnnounceAlt;
|
|
1360
|
+
if (altText) textContent.push(altText);
|
|
1361
|
+
} else {
|
|
1362
|
+
textContent.push(...getAnnounceTextContent(node));
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
});
|
|
1367
|
+
return textContent;
|
|
1368
|
+
}
|
|
1369
|
+
function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
|
|
1370
|
+
const currentTarget = detail.originalEvent.currentTarget;
|
|
1371
|
+
const event = new CustomEvent(name, { bubbles: true, cancelable: true, detail });
|
|
1372
|
+
if (handler) currentTarget.addEventListener(name, handler, { once: true });
|
|
1373
|
+
if (discrete) {
|
|
1374
|
+
dispatchDiscreteCustomEvent(currentTarget, event);
|
|
1375
|
+
} else {
|
|
1376
|
+
currentTarget.dispatchEvent(event);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
var isDeltaInDirection = (delta, direction, threshold = 0) => {
|
|
1380
|
+
const deltaX = Math.abs(delta.x);
|
|
1381
|
+
const deltaY = Math.abs(delta.y);
|
|
1382
|
+
const isDeltaX = deltaX > deltaY;
|
|
1383
|
+
if (direction === "left" || direction === "right") {
|
|
1384
|
+
return isDeltaX && deltaX > threshold;
|
|
1385
|
+
} else {
|
|
1386
|
+
return !isDeltaX && deltaY > threshold;
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
function useNextFrame(callback = () => {
|
|
1390
|
+
}) {
|
|
1391
|
+
const fn = useCallbackRef(callback);
|
|
1392
|
+
useLayoutEffect2(() => {
|
|
1393
|
+
let raf1 = 0;
|
|
1394
|
+
let raf2 = 0;
|
|
1395
|
+
raf1 = window.requestAnimationFrame(() => raf2 = window.requestAnimationFrame(fn));
|
|
1396
|
+
return () => {
|
|
1397
|
+
window.cancelAnimationFrame(raf1);
|
|
1398
|
+
window.cancelAnimationFrame(raf2);
|
|
1399
|
+
};
|
|
1400
|
+
}, [fn]);
|
|
1401
|
+
}
|
|
1402
|
+
function isHTMLElement(node) {
|
|
1403
|
+
return node.nodeType === node.ELEMENT_NODE;
|
|
1404
|
+
}
|
|
1405
|
+
function getTabbableCandidates(container) {
|
|
1406
|
+
const nodes = [];
|
|
1407
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
|
|
1408
|
+
acceptNode: (node) => {
|
|
1409
|
+
const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
|
|
1410
|
+
if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
|
|
1411
|
+
return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1414
|
+
while (walker.nextNode()) nodes.push(walker.currentNode);
|
|
1415
|
+
return nodes;
|
|
1416
|
+
}
|
|
1417
|
+
function focusFirst(candidates) {
|
|
1418
|
+
const previouslyFocusedElement = document.activeElement;
|
|
1419
|
+
return candidates.some((candidate) => {
|
|
1420
|
+
if (candidate === previouslyFocusedElement) return true;
|
|
1421
|
+
candidate.focus();
|
|
1422
|
+
return document.activeElement !== previouslyFocusedElement;
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
var Provider = ToastProvider$1;
|
|
1426
|
+
var Viewport = ToastViewport$1;
|
|
1427
|
+
var Root2 = Toast;
|
|
1428
|
+
var Description = ToastDescription;
|
|
1429
|
+
function getToastIcon(type) {
|
|
1430
|
+
switch (type) {
|
|
1431
|
+
case "success":
|
|
1432
|
+
return "✓";
|
|
1433
|
+
case "error":
|
|
1434
|
+
return "✕";
|
|
1435
|
+
case "warning":
|
|
1436
|
+
return "⚠";
|
|
1437
|
+
case "info":
|
|
1438
|
+
default:
|
|
1439
|
+
return "ℹ";
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
function ToastItem({ toast, onOpenChange }) {
|
|
1443
|
+
return /* @__PURE__ */ jsxs(
|
|
1444
|
+
Root2,
|
|
1445
|
+
{
|
|
1446
|
+
className: `taskon-toast taskon-toast--${toast.type}`,
|
|
1447
|
+
duration: toast.duration ?? 3e3,
|
|
1448
|
+
onOpenChange,
|
|
1449
|
+
children: [
|
|
1450
|
+
/* @__PURE__ */ jsx("div", { className: "taskon-toast-icon", children: getToastIcon(toast.type) }),
|
|
1451
|
+
/* @__PURE__ */ jsx(Description, { className: "taskon-toast-message", children: toast.message })
|
|
1452
|
+
]
|
|
1453
|
+
}
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
1456
|
+
function ToastViewport({
|
|
1457
|
+
toasts,
|
|
1458
|
+
onRemove
|
|
1459
|
+
}) {
|
|
1460
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1461
|
+
toasts.map((toast) => /* @__PURE__ */ jsx(
|
|
1462
|
+
ToastItem,
|
|
1463
|
+
{
|
|
1464
|
+
toast,
|
|
1465
|
+
onOpenChange: (open) => {
|
|
1466
|
+
if (!open) {
|
|
1467
|
+
onRemove(toast.id);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
},
|
|
1471
|
+
toast.id
|
|
1472
|
+
)),
|
|
1473
|
+
/* @__PURE__ */ jsx(Viewport, { className: "taskon-toast-viewport" })
|
|
1474
|
+
] });
|
|
1475
|
+
}
|
|
1476
|
+
const ToastProvider = Provider;
|
|
1477
|
+
const MetaMaskIcon = new URL("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%3e%3crect%20width='24'%20height='24'%20rx='8'%20fill='white'/%3e%3crect%20width='24'%20height='24'%20fill='url(%23pattern0)'/%3e%3cdefs%3e%3cpattern%20id='pattern0'%20patternContentUnits='objectBoundingBox'%20width='1'%20height='1'%3e%3cuse%20xlink:href='%23image0_1936_8376'%20transform='scale(0.00227273)'/%3e%3c/pattern%3e%3cimage%20id='image0_1936_8376'%20width='440'%20height='440'%20xlink:href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAbgAAAG4CAYAAAA3yvKzAAAMbGlDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnluSkJDQAghICb0JIjWAlBBaAOndRkgCCSXGhKBiL4sKrl1EsaKrIgqWFRALiF1ZFHtfLKgo66IuNlTehAR03Ve+d/LNvX/OnPlPuXPLAUDzA1ciyUO1AMgXF0jjw4IYqWnpDNIzgMCfPvx5c3kyCSs2NgpAGTz/Xd7dgLZQrjopuP45/19Fhy+Q8QBAxkGcyZfx8iFuBgDfwJNICwAgKvSWUwokCjwHYl0pDBDi1QqcrcS7FDhTiY8O2CTGsyG+DIAalcuVZgOgcQ/qGYW8bMij8RliFzFfJAZAcwTE/jwhlw+xIvYR+fmTFLgcYjtoL4EYxgOYmd9xZv+NP3OIn8vNHsLKvAZELVgkk+Rxp/2fpfnfkp8nH/RhAwdVKA2PV+QPa3grd1KkAlMh7hZnRscoag3xBxFfWXcAUIpQHp6ktEeNeTI2rB+84gB14XODIyE2hjhUnBcdpdJnZolCORDD3YJOFRVwEiE2gHiRQBaSoLLZIp0Ur/KF1mVJ2SyV/hxXOuBX4euBPDeJpeJ/IxRwVPyYRpEwMQViCsRWhaLkaIg1IHaW5SZEqmxGFwnZ0YM2Unm8In4riOMF4rAgJT9WmCUNjVfZl+TLBvPFtghFnGgVPlAgTAxX1gc7xeMOxA9zwS4LxKykQR6BLDVqMBe+IDhEmTv2XCBOSlDxfJAUBMUr1+IUSV6syh63EOSFKfQWELvLChNUa/HkArg5lfx4lqQgNlEZJ16Uw42IVcaDLwdRgA2CAQPI4cgEk0AOELV113fDf8qZUMAFUpANBMBJpRlckTIwI4bHBFAE/oBIAGRD64IGZgWgEOq/DGmVRyeQNTBbOLAiFzyFOB9Egjz4Xz6wSjzkLRk8gRrRP7xz4eDBePPgUMz/e/2g9puGBTVRKo180CNDc9CSGEIMJoYTQ4n2uBHuj/viUfAYCIcrzsS9B/P4Zk94SmgnPCJcJ3QQbk8UzZP+EOUY0AH5Q1W1yPy+FrgN5PTAg3A/yA6ZcX3cCDjh7tAPCw+Anj2glq2KW1EVxg/cf8vgu6uhsiO7kFHyMHIg2e7HlRoOGh5DLIpaf18fZayZQ/VmD8386J/9XfX58Bz5oyW2CDuIncVOYOexo1g9YGBNWAPWih1T4KHd9WRgdw16ix+IJxfyiP7hj6vyqaikzKXapcvls3KuQDC1QHHjsSdJpklF2cICBgu+HQQMjpjnPILh6uLqBoDiXaN8fL2NG3iHIPqt33TzfwfAr6m/v//IN11EEwD7veDtf/ibzo4JgLY6AOcO8+TSQqUOVxwI8CmhCe80Q2AKLIEdzMcVeAJfEAhCQASIAYkgDUyAVRbCfS4FU8AMMBcUg1KwHKwB68FmsA3sAnvBAVAPjoIT4Ay4CC6D6+Au3D2d4CXoAe9AH4IgJISG0BFDxAyxRhwRV4SJ+CMhSBQSj6QhGUg2IkbkyAxkPlKKrETWI1uRKmQ/chg5gZxH2pHbyEOkC3mDfEIxlIrqoiaoDToSZaIsNBJNRMej2ehktAhdgC5Fy9FKdA9ah55AL6LX0Q70JdqLAUwd08fMMSeMibGxGCwdy8Kk2CysBCvDKrEarBFe56tYB9aNfcSJOB1n4E5wB4fjSTgPn4zPwpfg6/FdeB1+Cr+KP8R78K8EGsGY4EjwIXAIqYRswhRCMaGMsINwiHAa3kudhHdEIlGfaEv0gvdiGjGHOJ24hLiRWEtsJrYTHxN7SSSSIcmR5EeKIXFJBaRi0jrSHlIT6Qqpk/RBTV3NTM1VLVQtXU2sNk+tTG232nG1K2rP1PrIWmRrsg85hswnTyMvI28nN5IvkTvJfRRtii3Fj5JIyaHMpZRTaiinKfcob9XV1S3UvdXj1EXqc9TL1fepn1N/qP6RqkN1oLKp46hy6lLqTmoz9Tb1LY1Gs6EF0tJpBbSltCraSdoD2gcNuoazBkeDrzFbo0KjTuOKxitNsqa1JktzgmaRZpnmQc1Lmt1aZC0bLbYWV2uWVoXWYa2bWr3adO1R2jHa+dpLtHdrn9d+rkPSsdEJ0eHrLNDZpnNS5zEdo1vS2XQefT59O/00vVOXqGury9HN0S3V3avbptujp6PnrpesN1WvQu+YXoc+pm+jz9HP01+mf0D/hv6nYSbDWMMEwxYPqxl2Zdh7g+EGgQYCgxKDWoPrBp8MGYYhhrmGKwzrDe8b4UYORnFGU4w2GZ026h6uO9x3OG94yfADw+8Yo8YOxvHG0423Gbca95qYmoSZSEzWmZw06TbVNw00zTFdbXrctMuMbuZvJjJbbdZk9oKhx2Ax8hjljFOMHnNj83BzuflW8zbzPgtbiySLeRa1FvctKZZMyyzL1ZYtlj1WZlZjrGZYVVvdsSZbM62F1mutz1q/t7G1SbFZaFNv89zWwJZjW2RbbXvPjmYXYDfZrtLumj3Rnmmfa7/R/rID6uDhIHSocLjkiDp6OoocNzq2jyCM8B4hHlE54qYT1YnlVOhU7fTQWd85ynmec73zq5FWI9NHrhh5duRXFw+XPJftLndH6YyKGDVvVOOoN64OrjzXCtdrbjS3ULfZbg1ur90d3QXum9xvedA9xngs9Gjx+OLp5Sn1rPHs8rLyyvDa4HWTqcuMZS5hnvMmeAd5z/Y+6v3Rx9OnwOeAz5++Tr65vrt9n4+2HS0YvX30Yz8LP67fVr8Of4Z/hv8W/44A8wBuQGXAo0DLQH7gjsBnLHtWDmsP61WQS5A06FDQe7YPeya7ORgLDgsuCW4L0QlJClkf8iDUIjQ7tDq0J8wjbHpYczghPDJ8RfhNjgmHx6ni9ER4RcyMOBVJjUyIXB/5KMohShrVOAYdEzFm1Zh70dbR4uj6GBDDiVkVcz/WNnZy7JE4YlxsXEXc0/hR8TPizybQEyYm7E54lxiUuCzxbpJdkjypJVkzeVxyVfL7lOCUlSkdqSNTZ6ZeTDNKE6U1pJPSk9N3pPeODRm7ZmznOI9xxeNujLcdP3X8+QlGE/ImHJuoOZE78WAGISMlY3fGZ24Mt5Lbm8nJ3JDZw2Pz1vJe8gP5q/ldAj/BSsGzLL+slVnPs/2yV2V3CQOEZcJuEVu0XvQ6Jzxnc8773Jjcnbn9eSl5tflq+Rn5h8U64lzxqUmmk6ZOapc4SoolHZN9Jq+Z3CONlO6QIbLxsoYCXfhR3yq3k/8kf1joX1hR+GFK8pSDU7Wniqe2TnOYtnjas6LQol+m49N501tmmM+YO+PhTNbMrbOQWZmzWmZbzl4wu3NO2Jxdcylzc+f+Ns9l3sp5f81Pmd+4wGTBnAWPfwr7qbpYo1hafHOh78LNi/BFokVti90Wr1v8tYRfcqHUpbSs9PMS3pILP4/6ufzn/qVZS9uWeS7btJy4XLz8xoqAFbtWaq8sWvl41ZhVdasZq0tW/7Vm4przZe5lm9dS1srXdpRHlTess1q3fN3n9cL11yuCKmo3GG9YvOH9Rv7GK5sCN9VsNtlcuvnTFtGWW1vDttZV2lSWbSNuK9z2dHvy9rO/MH+p2mG0o3THl53inR274nedqvKqqtptvHtZNVotr+7aM27P5b3BextqnGq21urXlu4D++T7XuzP2H/jQOSBloPMgzW/Wv+64RD9UEkdUjetrqdeWN/RkNbQfjjicEujb+OhI85Hdh41P1pxTO/YsuOU4wuO9zcVNfU2S5q7T2SfeNwyseXuydST107FnWo7HXn63JnQMyfPss42nfM7d/S8z/nDF5gX6i96Xqxr9Wg99JvHb4faPNvqLnldarjsfbmxfXT78SsBV05cDb565hrn2sXr0dfbbyTduHVz3M2OW/xbz2/n3X59p/BO39059wj3Su5r3S97YPyg8nf732s7PDuOPQx+2Poo4dHdx7zHL5/InnzuXPCU9rTsmdmzqueuz492hXZdfjH2RedLycu+7uI/tP/Y8Mru1a9/Bv7Z2pPa0/la+rr/zZK3hm93/uX+V0tvbO+Dd/nv+t6XfDD8sOsj8+PZTymfnvVN+Uz6XP7F/kvj18iv9/rz+/slXCl34FMAgwPNygLgzU4AaGkA0GHfRhmr7AUHBFH2rwMI/Ces7BcHxBOAGvj9HtcNv25uArBvO2y/IL8m7FVjaQAkegPUzW1oqESW5eaq5KLCPoXwoL//LezZSKsA+LK8v7+vsr//yzYYLOwdm8XKHlQhRNgzbIn+kpmfCf6NKPvT73L88QwUEbiDH8//AlB8kNc164p8AAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAG4oAMABAAAAAEAAAG4AAAAAAH7VFcAAEAASURBVHgB7L0HnBzHdSZe3TOzEbsLgNgFsABIgAQBZgWKpEQCTGKQqESKQZKDJNuyrL/P9sm2CMr++fzH+SSKAChZ54vSna1gi0qWxCCREqlAIVDMIikxIRCBCJuAxeYwM133vZ7p3dnZnpmeme6erppX5GJmOlS9+qrqvXqvXr0SghMjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAgwAowAI8AIMAKMACPACDACjAAjwAhEHQEj6gT6Td89t3ZdOzJl3P2WlYn//Oauw/cam4XldxmcHyPACDACUUDgxc3nNgy8fvIPXhpI/8WipsR7P/jt1/dFga6waIiHVVBUytl7wvjw6LS8oGds+ntp2X388B3Glwwpv75i69FXo0Ij08EIMAKMQDUIHPz08guFND6y79CJP/z5a1brdFqK/obJDyDPO6vJV7V360qD2yyEOb6x6xgaqcswhMSncekqU7x5RUwAiOelNL4Ss6xvdH/+6IBqDcn0MgKMQH0jsP/21ctMkfoAeNnH0kKet+uAJX7TkwYoEsmQwhRPbt3e97Z6QqmuBNztV3RuNCxje24DEwDd7YZ45/qY1RIz0AtECh3hXsi+r6x87fDDxncF9RBOjAAjwAhEDoE9f762saFp4r2mIf4AvOs6InBkSpgP7U4Z/aPSnsXnEA0xF1+9ZefRQznXtP5aVwLujo1L/wlN/gm0aCK3VdE5RENMiOvXxcVpHQSJkcSsJ4GJzwA0vXtIs1u57chzue/wd0aAEWAEaoXAwTtOPdeUqd+Xwvg4aFgErpWCgIvvO2GJn+61RMoirY0MUznJwGRdGp/auqP3izlXtf46FwCNq7o5xzzpWk2YLKG+GWSufNupJpS4mZTCt7g0xG488S/xWOpfln+up3/mLn9hBBgB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Rqgqv49VlnCuOBiixLFo0IPFiNWIIbNba86Gv0jh5tiiZsYyEOAILgMUfuV8AhdjzSnEmnPqAhRDbNs+0jq+rn7NA+86v1SZQxIYSoAjuKE8eOQSAovXPvB6RTR+HUZzLzk0y7KQ5McVserrKdwcWsLMVk4CHMHlRMQTnE7gSEvzdVGf6XdSPiG4e269u/H/nJQn5oUESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEiiDw/21fUQrhhQi0AAAAAElFTkSuQmCC'/%3e%3c/defs%3e%3c/svg%3e", import.meta.url).href;
|
|
1478
|
+
const WalletConnectIcon = new URL("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='24'%20height='24'%20rx='8'%20fill='%23216DFF'/%3e%3cpath%20d='M7.82421%2018.1965C7.54878%2018.1956%207.36404%2018.0185%207.18434%2017.8404C5.61069%2016.2668%204.03201%2014.6965%202.46507%2013.1145C1.83528%2012.4771%201.84871%2012.289%202.48355%2011.6256C3.5584%2010.5046%203.57687%2010.4836%204.71722%2011.5626C5.61741%2012.4141%206.47561%2013.3135%207.32457%2014.2179C7.6739%2014.589%207.91154%2014.5722%208.27682%2014.2229C9.29286%2013.2589%2010.2813%2012.2662%2011.2411%2011.2461C11.8986%2010.5407%2012.1035%2010.5491%2012.803%2011.2385C13.7653%2012.1874%2014.6428%2013.2236%2015.6563%2014.1263C16.1148%2014.5344%2016.3684%2014.6041%2016.8126%2014.1288C17.801%2013.0741%2018.8565%2012.0833%2019.8667%2011.047C20.2488%2010.6557%2020.5679%2010.6389%2020.9727%2011.0168C22.3632%2012.3134%2022.333%2012.4158%2020.9374%2013.7258C19.6005%2014.9812%2018.3435%2016.3264%2017.0553%2017.6355C16.3214%2018.3821%2016.2156%2018.3426%2015.4422%2017.68C14.3573%2016.7496%2013.4731%2015.6244%2012.4696%2014.6167C12.1371%2014.2825%2011.9162%2014.2556%2011.5803%2014.61C10.5684%2015.6739%209.61535%2016.8%208.50187%2017.7607C8.29446%2017.9395%208.11812%2018.1621%207.82421%2018.1973'%20fill='white'/%3e%3cpath%20d='M11.9418%205C14.3342%205.17298%2016.515%205.89179%2018.2373%207.88026C18.6697%208.37906%2018.6823%208.79725%2018.2675%209.27421C18.2028%209.34811%2018.1407%209.42452%2018.0743%209.49758C17.0474%2010.643%2017.0474%2010.643%2015.954%209.58659C13.6666%207.37559%2010.3027%207.39826%208.03205%209.64033C7.87586%209.79484%207.72051%209.95019%207.5702%2010.1106C7.18225%2010.5262%206.86483%2010.5178%206.45084%2010.0711C5.0485%208.5596%205.02247%208.5638%206.51634%207.17237C8.07908%205.71713%209.95167%205.17214%2011.9418%205Z'%20fill='white'/%3e%3c/svg%3e", import.meta.url).href;
|
|
1479
|
+
const BitgetIcon = new URL("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cg%20clip-path='url(%23clip0_2600_5842)'%3e%3cpath%20d='M16%200H8C3.58172%200%200%203.58172%200%208V16C0%2020.4183%203.58172%2024%208%2024H16C20.4183%2024%2024%2020.4183%2024%2016V8C24%203.58172%2020.4183%200%2016%200Z'%20fill='white'/%3e%3cmask%20id='mask0_2600_5842'%20style='mask-type:alpha'%20maskUnits='userSpaceOnUse'%20x='0'%20y='0'%20width='24'%20height='24'%3e%3cpath%20d='M16%200H8C3.58172%200%200%203.58172%200%208V16C0%2020.4183%203.58172%2024%208%2024H16C20.4183%2024%2024%2020.4183%2024%2016V8C24%203.58172%2020.4183%200%2016%200Z'%20fill='white'/%3e%3c/mask%3e%3cg%20mask='url(%23mask0_2600_5842)'%3e%3cg%20filter='url(%23filter0_f_2600_5842)'%3e%3cpath%20d='M26.0859%20-6.75C26.0859%204.56321%2016.9148%2013.7344%205.60156%2013.7344C-5.71165%2013.7344%20-14.8828%204.56321%20-14.8828%20-6.75C-14.8828%20-18.0632%20-5.71165%20-27.2344%205.60156%20-27.2344C16.9148%20-27.2344%2026.0859%20-18.0632%2026.0859%20-6.75Z'%20fill='%2333FFF3'/%3e%3c/g%3e%3cg%20filter='url(%23filter1_f_2600_5842)'%3e%3cpath%20d='M9.5625%2022.957C9.5625%2027.4423%205.92657%2031.0781%201.44141%2031.0781C-3.04376%2031.0781%20-6.67969%2027.4423%20-6.67969%2022.957C-6.67969%2018.4719%20-3.04376%2014.8359%201.44141%2014.8359C5.92657%2014.8359%209.5625%2018.4719%209.5625%2022.957Z'%20fill='url(%23paint0_linear_2600_5842)'%20fill-opacity='0.87'/%3e%3c/g%3e%3cg%20filter='url(%23filter2_f_2600_5842)'%3e%3cpath%20d='M49.5%2042.2578C49.5%2053.5711%2040.3289%2062.7422%2029.0156%2062.7422C17.7024%2062.7422%208.53125%2053.5711%208.53125%2042.2578C8.53125%2030.9445%2017.7024%2021.7734%2029.0156%2021.7734C40.3289%2021.7734%2049.5%2030.9445%2049.5%2042.2578Z'%20fill='%2333FFF3'/%3e%3c/g%3e%3cg%20filter='url(%23filter3_f_2600_5842)'%3e%3cpath%20d='M26.0391%20-1.66406C26.0391%201.92147%2023.1324%204.82812%2019.5469%204.82812C15.9613%204.82812%2013.0547%201.92147%2013.0547%20-1.66406C13.0547%20-5.2496%2015.9613%20-8.15625%2019.5469%20-8.15625C23.1324%20-8.15625%2026.0391%20-5.2496%2026.0391%20-1.66406Z'%20fill='%2353C0FB'/%3e%3c/g%3e%3c/g%3e%3cpath%20fill-rule='evenodd'%20clip-rule='evenodd'%20d='M14.1111%203.63526C14.1335%203.61077%2014.1559%203.58628%2014.1786%203.56211L14.1789%203.56139C14.175%203.55316%2014.1707%203.54493%2014.1664%203.53668L14.1664%203.53664C14.1549%203.53544%2014.1434%203.53387%2014.1319%203.53228C14.1088%203.52909%2014.0856%203.52588%2014.0626%203.52588C13.6357%203.5256%2013.2085%203.52196%2012.781%203.51833C11.8354%203.51027%2010.889%203.50221%209.94501%203.53054C9.8897%203.53197%209.82326%203.56389%209.78301%203.60336C9.56315%203.81772%209.34682%204.03562%209.1304%204.25361C9.07987%204.3045%209.02934%204.3554%208.97876%204.40626C8.79524%204.59078%208.61182%204.77547%208.42837%204.96018C8.13468%205.25594%207.84091%205.55175%207.54663%205.84699C7.36675%206.02713%207.18642%206.2068%207.00609%206.3865C6.79569%206.59614%206.5853%206.80579%206.37562%207.01617C6.16108%207.23182%205.94716%207.4481%205.73325%207.6644C5.55501%207.84461%205.37676%208.02485%205.19815%208.20471C5.07098%208.33277%204.94317%208.46015%204.81537%208.58751C4.63886%208.76341%204.46237%208.93931%204.28758%209.11699C4.07528%209.33261%204.01495%209.68202%204.1755%209.93531C4.28216%2010.1044%204.42867%2010.2506%204.5719%2010.3936L4.58357%2010.4053C4.96429%2010.7855%205.3478%2011.1632%205.73133%2011.5408C5.91733%2011.724%206.10335%2011.9072%206.28905%2012.0907C6.47772%2012.2771%206.66613%2012.4639%206.85459%2012.6506C7.00523%2012.7999%207.15588%2012.9492%207.30668%2013.0984C7.38648%2013.1774%207.46624%2013.2565%207.546%2013.3356C7.888%2013.6746%208.22993%2014.0136%208.57537%2014.349C8.61705%2014.3896%208.69031%2014.4179%208.74888%2014.4179C10.0646%2014.4222%2011.3804%2014.4218%2012.6962%2014.4208C12.7156%2014.4205%2012.735%2014.4121%2012.7544%2014.4036C12.7637%2014.3996%2012.773%2014.3956%2012.7824%2014.3924C12.7779%2014.3843%2012.774%2014.3758%2012.7701%2014.3672C12.7622%2014.3496%2012.7542%2014.332%2012.7414%2014.3192C12.629%2014.2059%2012.516%2014.0929%2012.403%2013.98C12.2901%2013.8671%2012.1771%2013.7542%2012.0647%2013.6408C11.8397%2013.4143%2011.6151%2013.1873%2011.3905%2012.9604C11.1659%2012.7333%2010.9413%2012.5063%2010.7162%2012.2797C10.1131%2011.6724%209.50931%2011.0661%208.90512%2010.4598C8.65907%2010.213%208.41194%209.96688%208.16482%209.72114C8.0653%209.62211%208.0646%209.61494%208.15619%209.52311C8.2033%209.47591%208.25004%209.42835%208.29677%209.38078C8.36303%209.31335%208.42931%209.24589%208.49672%209.17943C8.67972%208.99886%208.86305%208.81849%209.04637%208.63814C9.33983%208.34941%209.63334%208.06066%209.92561%207.77097C10.1823%207.51658%2010.438%207.26123%2010.6937%207.00593C10.9067%206.79316%2011.1198%206.58042%2011.3333%206.36826C11.454%206.2484%2011.5756%206.12941%2011.6972%206.01042C11.8249%205.88538%2011.9526%205.76034%2012.0794%205.63425C12.1843%205.5299%2012.2883%205.42455%2012.3923%205.31917C12.5419%205.16765%2012.6915%205.01613%2012.8438%204.8676C13.0639%204.65282%2013.2862%204.43996%2013.5085%204.2271C13.6612%204.08085%2013.8139%203.9346%2013.9659%203.78777C14.0162%203.73902%2014.0636%203.68715%2014.1111%203.63526ZM9.80814%2020.4998C9.80802%2020.4999%209.80793%2020.5%209.80781%2020.5001V20.4998C9.80793%2020.4998%209.80802%2020.4998%209.80814%2020.4998ZM9.80814%2020.4998C10.3735%2020.4998%2010.9515%2020.5036%2011.5319%2020.5074C12.3677%2020.5129%2013.2084%2020.5184%2014.023%2020.5127C14.0809%2020.5123%2014.1531%2020.4951%2014.1933%2020.4582C14.3316%2020.3316%2014.4637%2020.198%2014.5957%2020.0645C14.619%2020.041%2014.6423%2020.0174%2014.6657%2019.9939C14.9028%2019.7551%2015.1397%2019.516%2015.3766%2019.277C15.7318%2018.9185%2016.087%2018.56%2016.443%2018.2023C16.9423%2017.7007%2017.4421%2017.1996%2017.942%2016.6984C18.2275%2016.412%2018.5131%2016.1257%2018.7986%2015.8393C18.882%2015.7557%2018.9656%2015.6724%2019.0493%2015.5892C19.2722%2015.3672%2019.4952%2015.1452%2019.7128%2014.918C19.9028%2014.7196%2019.9495%2014.4814%2019.8719%2014.2138C19.8247%2014.0512%2019.713%2013.9407%2019.6013%2013.8302C19.589%2013.8181%2019.5767%2013.8059%2019.5645%2013.7937C19.3393%2013.5683%2019.1125%2013.3448%2018.8857%2013.1211C18.7261%2012.9638%2018.5665%2012.8065%2018.4075%2012.6485C18.1675%2012.41%2017.9281%2012.1708%2017.6887%2011.9317C17.4893%2011.7324%2017.2898%2011.533%2017.0899%2011.3341C16.9052%2011.1503%2016.7203%2010.9669%2016.5354%2010.7834C16.1823%2010.4331%2015.8293%2010.0828%2015.4778%209.73082C15.4027%209.65584%2015.3266%209.6196%2015.2181%209.62033C14.6488%209.62375%2014.0793%209.62354%2013.51%209.62331C13.3676%209.62324%2013.2253%209.62319%2013.083%209.62319C12.9198%209.6231%2012.7566%209.62286%2012.5934%209.62265C12.1855%209.62209%2011.7775%209.62155%2011.3696%209.62284C11.338%209.62307%2011.3064%209.63404%2011.275%209.64499C11.2601%209.65019%2011.2452%209.65539%2011.2302%209.65943C11.2378%209.67161%2011.2448%209.68443%2011.2518%209.69723C11.2669%209.7251%2011.2821%209.75294%2011.3035%209.77457C11.4959%209.96906%2011.6894%2010.1626%2011.8828%2010.3562C11.9869%2010.4604%2012.0911%2010.5646%2012.1951%2010.6689C12.6498%2011.1253%2013.1042%2011.5818%2013.5586%2012.0384C13.7104%2012.191%2013.8622%2012.3435%2014.0141%2012.4961L14.0177%2012.4997C14.6286%2013.1131%2015.2398%2013.7267%2015.8507%2014.3404C15.9362%2014.4261%2015.9365%2014.4279%2015.8503%2014.514C15.5288%2014.8342%2015.2069%2015.154%2014.8849%2015.4738C14.8043%2015.5539%2014.7236%2015.6339%2014.643%2015.7141L14.6391%2015.7179C13.8821%2016.4693%2013.1255%2017.2203%2012.3689%2017.972C12.2165%2018.1233%2012.0645%2018.2751%2011.9126%2018.4268C11.6509%2018.6881%2011.3892%2018.9493%2011.1254%2019.2083C10.8876%2019.4419%2010.6473%2019.6732%2010.4071%2019.9045C10.2688%2020.0376%2010.1306%2020.1707%209.9928%2020.3042C9.95322%2020.3428%209.91574%2020.3835%209.87362%2020.4292C9.85316%2020.4514%209.83158%2020.4748%209.80814%2020.4998Z'%20fill='black'/%3e%3c/g%3e%3cdefs%3e%3cfilter%20id='filter0_f_2600_5842'%20x='-28.9453'%20y='-41.2969'%20width='69.0938'%20height='69.0938'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='BackgroundImageFix'%20result='shape'/%3e%3cfeGaussianBlur%20stdDeviation='7.03125'%20result='effect1_foregroundBlur_2600_5842'/%3e%3c/filter%3e%3cfilter%20id='filter1_f_2600_5842'%20x='-16.0547'%20y='5.46094'%20width='34.9922'%20height='34.9922'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='BackgroundImageFix'%20result='shape'/%3e%3cfeGaussianBlur%20stdDeviation='4.6875'%20result='effect1_foregroundBlur_2600_5842'/%3e%3c/filter%3e%3cfilter%20id='filter2_f_2600_5842'%20x='-0.84375'%20y='12.3984'%20width='59.7188'%20height='59.7188'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='BackgroundImageFix'%20result='shape'/%3e%3cfeGaussianBlur%20stdDeviation='4.6875'%20result='effect1_foregroundBlur_2600_5842'/%3e%3c/filter%3e%3cfilter%20id='filter3_f_2600_5842'%20x='6.02344'%20y='-15.1875'%20width='27.0469'%20height='27.0469'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeFlood%20flood-opacity='0'%20result='BackgroundImageFix'/%3e%3cfeBlend%20mode='normal'%20in='SourceGraphic'%20in2='BackgroundImageFix'%20result='shape'/%3e%3cfeGaussianBlur%20stdDeviation='3.51562'%20result='effect1_foregroundBlur_2600_5842'/%3e%3c/filter%3e%3clinearGradient%20id='paint0_linear_2600_5842'%20x1='1.01953'%20y1='21.7852'%20x2='8.66016'%20y2='18.457'%20gradientUnits='userSpaceOnUse'%3e%3cstop%20offset='0.442707'%20stop-color='%239D95FE'/%3e%3cstop%20offset='1'%20stop-color='%23E395FE'/%3e%3c/linearGradient%3e%3cclipPath%20id='clip0_2600_5842'%3e%3crect%20width='24'%20height='24'%20fill='white'/%3e%3c/clipPath%3e%3c/defs%3e%3c/svg%3e", import.meta.url).href;
|
|
1480
|
+
const OkxIcon = new URL("data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='24'%20height='24'%20rx='8'%20fill='white'/%3e%3cpath%20d='M5%205H9.66667V9.66667H5V5ZM14.3333%205H19V9.66667H14.3333V5ZM5%2014.3333H9.66667V19H5V14.3333ZM14.3333%2014.3333H19V19H14.3333V14.3333ZM9.66667%209.66667H14.3333V14.3333H9.66667V9.66667Z'%20fill='%23010101'/%3e%3c/svg%3e", import.meta.url).href;
|
|
1481
|
+
const EVM_WALLETS = [
|
|
1482
|
+
{
|
|
1483
|
+
id: "metamask",
|
|
1484
|
+
name: "MetaMask",
|
|
1485
|
+
icon: MetaMaskIcon,
|
|
1486
|
+
downloadUrl: "https://metamask.io/download/",
|
|
1487
|
+
checkInstalled: () => typeof window !== "undefined" && Boolean(window.ethereum)
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
id: "walletconnect",
|
|
1491
|
+
name: "WalletConnect",
|
|
1492
|
+
icon: WalletConnectIcon,
|
|
1493
|
+
downloadUrl: "https://walletconnect.com/",
|
|
1494
|
+
checkInstalled: () => false
|
|
1495
|
+
// WalletConnect 不需要安装
|
|
1496
|
+
},
|
|
1497
|
+
{
|
|
1498
|
+
id: "bitget",
|
|
1499
|
+
name: "Bitget Wallet",
|
|
1500
|
+
icon: BitgetIcon,
|
|
1501
|
+
downloadUrl: "https://web3.bitget.com/",
|
|
1502
|
+
checkInstalled: () => {
|
|
1503
|
+
var _a;
|
|
1504
|
+
return typeof window !== "undefined" && Boolean((_a = window.bitkeep) == null ? void 0 : _a.ethereum);
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
id: "okx",
|
|
1509
|
+
name: "OKX Wallet",
|
|
1510
|
+
icon: OkxIcon,
|
|
1511
|
+
downloadUrl: "https://www.okx.com/web3",
|
|
1512
|
+
checkInstalled: () => typeof window !== "undefined" && Boolean(window.okxwallet)
|
|
1513
|
+
}
|
|
1514
|
+
];
|
|
1515
|
+
const DEFAULT_WALLET_CONNECT_PROJECT_ID = "c6e5e73fe203ffc84514a1ad09fe570a";
|
|
1516
|
+
function getWalletProvider(walletId) {
|
|
1517
|
+
var _a;
|
|
1518
|
+
if (typeof window === "undefined") return null;
|
|
1519
|
+
switch (walletId) {
|
|
1520
|
+
case "metamask":
|
|
1521
|
+
return window.ethereum;
|
|
1522
|
+
case "bitget":
|
|
1523
|
+
return (_a = window.bitkeep) == null ? void 0 : _a.ethereum;
|
|
1524
|
+
case "okx":
|
|
1525
|
+
return window.okxwallet;
|
|
1526
|
+
default:
|
|
1527
|
+
return null;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
async function checkWalletConnectAvailable() {
|
|
1531
|
+
try {
|
|
1532
|
+
await import("@walletconnect/ethereum-provider");
|
|
1533
|
+
return true;
|
|
1534
|
+
} catch {
|
|
1535
|
+
return false;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
function ConnectLoading({ walletName }) {
|
|
1539
|
+
return /* @__PURE__ */ jsxs("div", { className: "taskon-bind-wallet-loading-overlay", children: [
|
|
1540
|
+
/* @__PURE__ */ jsx("svg", { className: "taskon-bind-wallet-loading-spinner", viewBox: "0 0 50 50", children: /* @__PURE__ */ jsx(
|
|
1541
|
+
"circle",
|
|
1542
|
+
{
|
|
1543
|
+
cx: "25",
|
|
1544
|
+
cy: "25",
|
|
1545
|
+
r: "20",
|
|
1546
|
+
fill: "none",
|
|
1547
|
+
stroke: "currentColor",
|
|
1548
|
+
strokeWidth: "4",
|
|
1549
|
+
strokeLinecap: "round",
|
|
1550
|
+
strokeDasharray: "80 60"
|
|
1551
|
+
}
|
|
1552
|
+
) }),
|
|
1553
|
+
/* @__PURE__ */ jsxs("p", { className: "taskon-bind-wallet-loading-text", children: [
|
|
1554
|
+
"Please confirm wallet connection in ",
|
|
1555
|
+
walletName
|
|
1556
|
+
] })
|
|
1557
|
+
] });
|
|
1558
|
+
}
|
|
1559
|
+
function WalletItem({
|
|
1560
|
+
wallet,
|
|
1561
|
+
isInstalled,
|
|
1562
|
+
isConnecting,
|
|
1563
|
+
isDisabled,
|
|
1564
|
+
disabledReason,
|
|
1565
|
+
onClick
|
|
1566
|
+
}) {
|
|
1567
|
+
return /* @__PURE__ */ jsxs(
|
|
1568
|
+
"button",
|
|
1569
|
+
{
|
|
1570
|
+
type: "button",
|
|
1571
|
+
className: `taskon-bind-wallet-item ${isConnecting ? "taskon-bind-wallet-item--connecting" : ""} ${isDisabled ? "taskon-bind-wallet-item--disabled" : ""}`,
|
|
1572
|
+
onClick,
|
|
1573
|
+
disabled: isConnecting || isDisabled,
|
|
1574
|
+
title: disabledReason,
|
|
1575
|
+
children: [
|
|
1576
|
+
/* @__PURE__ */ jsx(
|
|
1577
|
+
"img",
|
|
1578
|
+
{
|
|
1579
|
+
className: "taskon-bind-wallet-item-icon",
|
|
1580
|
+
src: wallet.icon,
|
|
1581
|
+
alt: wallet.name
|
|
1582
|
+
}
|
|
1583
|
+
),
|
|
1584
|
+
/* @__PURE__ */ jsx("span", { className: "taskon-bind-wallet-item-name", children: wallet.name }),
|
|
1585
|
+
isConnecting ? /* @__PURE__ */ jsx("span", { className: "taskon-bind-wallet-item-connecting", children: /* @__PURE__ */ jsx("svg", { className: "taskon-bind-wallet-spinner", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeDasharray: "31.4 31.4" }) }) }) : isDisabled ? /* @__PURE__ */ jsx("span", { className: "taskon-bind-wallet-item-unavailable", children: "N/A" }) : isInstalled ? /* @__PURE__ */ jsx("span", { className: "taskon-bind-wallet-item-installed", children: "INSTALLED" }) : null
|
|
1586
|
+
]
|
|
1587
|
+
}
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
function WalletPickerDialog({
|
|
1591
|
+
open,
|
|
1592
|
+
onOpenChange,
|
|
1593
|
+
onSelect,
|
|
1594
|
+
onError
|
|
1595
|
+
}) {
|
|
1596
|
+
var _a, _b;
|
|
1597
|
+
const isMobile = useIsMobile();
|
|
1598
|
+
const context = useContext(TaskOnContext);
|
|
1599
|
+
const configuredProjectId = (_b = (_a = context == null ? void 0 : context.config) == null ? void 0 : _a.walletConnectProjectId) == null ? void 0 : _b.trim();
|
|
1600
|
+
const walletConnectProjectId = configuredProjectId || DEFAULT_WALLET_CONNECT_PROJECT_ID;
|
|
1601
|
+
const [connectingWalletId, setConnectingWalletId] = useState(null);
|
|
1602
|
+
const [connectingWalletName, setConnectingWalletName] = useState("");
|
|
1603
|
+
const [wcAvailable, setWcAvailable] = useState(null);
|
|
1604
|
+
React__default.useEffect(() => {
|
|
1605
|
+
checkWalletConnectAvailable().then(setWcAvailable);
|
|
1606
|
+
}, []);
|
|
1607
|
+
const isWalletConnectEnabled = useMemo(() => {
|
|
1608
|
+
return wcAvailable === true;
|
|
1609
|
+
}, [wcAvailable]);
|
|
1610
|
+
const wcDisabledReason = useMemo(() => {
|
|
1611
|
+
if (wcAvailable === false) {
|
|
1612
|
+
return "WalletConnect SDK not installed. Please install @walletconnect/ethereum-provider";
|
|
1613
|
+
}
|
|
1614
|
+
return void 0;
|
|
1615
|
+
}, [wcAvailable]);
|
|
1616
|
+
const walletsWithStatus = useMemo(() => {
|
|
1617
|
+
const walletList = isMobile ? EVM_WALLETS.filter((w) => w.id === "walletconnect") : EVM_WALLETS;
|
|
1618
|
+
return walletList.map((wallet) => ({
|
|
1619
|
+
wallet,
|
|
1620
|
+
isInstalled: wallet.id === "walletconnect" ? isWalletConnectEnabled : wallet.checkInstalled(),
|
|
1621
|
+
isDisabled: wallet.id === "walletconnect" && !isWalletConnectEnabled,
|
|
1622
|
+
disabledReason: wallet.id === "walletconnect" ? wcDisabledReason : void 0
|
|
1623
|
+
}));
|
|
1624
|
+
}, [isMobile, isWalletConnectEnabled, wcDisabledReason]);
|
|
1625
|
+
const connectWalletConnect = useCallback(async () => {
|
|
1626
|
+
var _a2, _b2, _c;
|
|
1627
|
+
setConnectingWalletId("walletconnect");
|
|
1628
|
+
setConnectingWalletName("WalletConnect");
|
|
1629
|
+
try {
|
|
1630
|
+
const { EthereumProvider } = await import("@walletconnect/ethereum-provider");
|
|
1631
|
+
const provider = await EthereumProvider.init({
|
|
1632
|
+
projectId: walletConnectProjectId,
|
|
1633
|
+
chains: [1],
|
|
1634
|
+
optionalChains: [56, 137, 42161, 10, 8453],
|
|
1635
|
+
showQrModal: true,
|
|
1636
|
+
qrModalOptions: {
|
|
1637
|
+
themeMode: "dark"
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
await provider.connect();
|
|
1641
|
+
const accounts = provider.accounts;
|
|
1642
|
+
const address = accounts[0];
|
|
1643
|
+
if (!address) {
|
|
1644
|
+
onError == null ? void 0 : onError("No account found");
|
|
1645
|
+
setConnectingWalletId(null);
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
await (onSelect == null ? void 0 : onSelect({
|
|
1649
|
+
walletId: "walletconnect",
|
|
1650
|
+
walletName: "WalletConnect",
|
|
1651
|
+
address,
|
|
1652
|
+
provider
|
|
1653
|
+
}));
|
|
1654
|
+
} catch (e) {
|
|
1655
|
+
const error2 = e;
|
|
1656
|
+
if (((_a2 = error2.message) == null ? void 0 : _a2.includes("rejected")) || ((_b2 = error2.message) == null ? void 0 : _b2.includes("denied")) || ((_c = error2.message) == null ? void 0 : _c.includes("User closed"))) {
|
|
1657
|
+
onError == null ? void 0 : onError("User rejected the connection");
|
|
1658
|
+
} else {
|
|
1659
|
+
onError == null ? void 0 : onError(error2.message || "Failed to connect WalletConnect");
|
|
1660
|
+
}
|
|
1661
|
+
} finally {
|
|
1662
|
+
setConnectingWalletId(null);
|
|
1663
|
+
}
|
|
1664
|
+
}, [walletConnectProjectId, onSelect, onError]);
|
|
1665
|
+
const connectWallet = useCallback(async (wallet) => {
|
|
1666
|
+
var _a2, _b2;
|
|
1667
|
+
const provider = getWalletProvider(wallet.id);
|
|
1668
|
+
if (!provider) {
|
|
1669
|
+
onError == null ? void 0 : onError(`${wallet.name} provider not found`);
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
setConnectingWalletId(wallet.id);
|
|
1673
|
+
setConnectingWalletName(wallet.name);
|
|
1674
|
+
try {
|
|
1675
|
+
const accounts = await provider.request({
|
|
1676
|
+
method: "eth_requestAccounts"
|
|
1677
|
+
});
|
|
1678
|
+
const address = accounts[0];
|
|
1679
|
+
if (!address) {
|
|
1680
|
+
onError == null ? void 0 : onError("No account found");
|
|
1681
|
+
setConnectingWalletId(null);
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
await (onSelect == null ? void 0 : onSelect({
|
|
1685
|
+
walletId: wallet.id,
|
|
1686
|
+
walletName: wallet.name,
|
|
1687
|
+
address,
|
|
1688
|
+
provider
|
|
1689
|
+
}));
|
|
1690
|
+
} catch (e) {
|
|
1691
|
+
const error2 = e;
|
|
1692
|
+
if (((_a2 = error2.message) == null ? void 0 : _a2.includes("rejected")) || ((_b2 = error2.message) == null ? void 0 : _b2.includes("denied"))) {
|
|
1693
|
+
onError == null ? void 0 : onError("User rejected the connection");
|
|
1694
|
+
} else {
|
|
1695
|
+
onError == null ? void 0 : onError(error2.message || "Failed to connect wallet");
|
|
1696
|
+
}
|
|
1697
|
+
} finally {
|
|
1698
|
+
setConnectingWalletId(null);
|
|
1699
|
+
}
|
|
1700
|
+
}, [onSelect, onError]);
|
|
1701
|
+
const handleWalletClick = useCallback(
|
|
1702
|
+
(wallet, isInstalled, isDisabled) => {
|
|
1703
|
+
if (isDisabled) return;
|
|
1704
|
+
if (wallet.id === "walletconnect") {
|
|
1705
|
+
connectWalletConnect();
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
if (isInstalled) {
|
|
1709
|
+
connectWallet(wallet);
|
|
1710
|
+
} else {
|
|
1711
|
+
window.open(wallet.downloadUrl, "_blank", "noopener,noreferrer");
|
|
1712
|
+
}
|
|
1713
|
+
},
|
|
1714
|
+
[connectWallet, connectWalletConnect]
|
|
1715
|
+
);
|
|
1716
|
+
return /* @__PURE__ */ jsx(
|
|
1717
|
+
Dialog,
|
|
1718
|
+
{
|
|
1719
|
+
open,
|
|
1720
|
+
onOpenChange,
|
|
1721
|
+
title: "Connect Wallet",
|
|
1722
|
+
overlayClassName: "taskon-wallet-picker-overlay",
|
|
1723
|
+
contentClassName: "taskon-wallet-picker-content",
|
|
1724
|
+
showCloseButton: true,
|
|
1725
|
+
maxWidth: 510,
|
|
1726
|
+
children: /* @__PURE__ */ jsxs("div", { className: "taskon-bind-wallet-dialog", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx("h2", { className: "taskon-bind-wallet-dialog-title", children: "Please select a wallet" }),
|
|
1728
|
+
/* @__PURE__ */ jsx("div", { className: "taskon-bind-wallet-dialog-chain-label", children: "EVM Chain" }),
|
|
1729
|
+
/* @__PURE__ */ jsx("div", { className: "taskon-bind-wallet-dialog-grid", children: walletsWithStatus.map(({ wallet, isInstalled, isDisabled, disabledReason }) => /* @__PURE__ */ jsx(
|
|
1730
|
+
WalletItem,
|
|
1731
|
+
{
|
|
1732
|
+
wallet,
|
|
1733
|
+
isInstalled,
|
|
1734
|
+
isConnecting: connectingWalletId === wallet.id,
|
|
1735
|
+
isDisabled,
|
|
1736
|
+
disabledReason,
|
|
1737
|
+
onClick: () => handleWalletClick(wallet, isInstalled, isDisabled)
|
|
1738
|
+
},
|
|
1739
|
+
wallet.id
|
|
1740
|
+
)) }),
|
|
1741
|
+
connectingWalletId && /* @__PURE__ */ jsx(ConnectLoading, { walletName: connectingWalletName })
|
|
1742
|
+
] })
|
|
1743
|
+
}
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
class EvmWalletSelectionCanceledError extends Error {
|
|
1747
|
+
constructor(message = "Wallet selection was canceled by user") {
|
|
1748
|
+
super(message);
|
|
1749
|
+
this.name = "EvmWalletSelectionCanceledError";
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
class EvmWalletSelectionInProgressError extends Error {
|
|
1753
|
+
constructor(message = "Another wallet selection is already in progress") {
|
|
1754
|
+
super(message);
|
|
1755
|
+
this.name = "EvmWalletSelectionInProgressError";
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
function getInjectedEthereumProvider() {
|
|
1759
|
+
if (typeof window === "undefined") {
|
|
1760
|
+
return null;
|
|
1761
|
+
}
|
|
1762
|
+
const provider = window.ethereum;
|
|
1763
|
+
if (!provider || typeof provider.request !== "function") {
|
|
1764
|
+
return null;
|
|
1765
|
+
}
|
|
1766
|
+
return provider;
|
|
1767
|
+
}
|
|
1768
|
+
function isUserRejectedError(error2) {
|
|
1769
|
+
if (typeof error2 === "object" && error2 !== null) {
|
|
1770
|
+
const code = error2.code;
|
|
1771
|
+
if (code === 4001) {
|
|
1772
|
+
return true;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
1776
|
+
const normalizedMessage = message.toLowerCase();
|
|
1777
|
+
return normalizedMessage.includes("rejected") || normalizedMessage.includes("denied") || normalizedMessage.includes("user closed");
|
|
1778
|
+
}
|
|
1779
|
+
function getInjectedWalletName(provider) {
|
|
1780
|
+
if (provider.isBitKeep || provider.isBitgetWallet) {
|
|
1781
|
+
return "Bitget Wallet";
|
|
1782
|
+
}
|
|
1783
|
+
if (provider.isOkxWallet) {
|
|
1784
|
+
return "OKX Wallet";
|
|
1785
|
+
}
|
|
1786
|
+
if (provider.isMetaMask) {
|
|
1787
|
+
return "MetaMask";
|
|
1788
|
+
}
|
|
1789
|
+
return "Injected Wallet";
|
|
1790
|
+
}
|
|
1791
|
+
async function trySelectInjectedWalletForMobileDapp() {
|
|
1792
|
+
if (typeof window === "undefined") {
|
|
1793
|
+
return null;
|
|
1794
|
+
}
|
|
1795
|
+
if (!isMobileViewport(window.innerWidth)) {
|
|
1796
|
+
return null;
|
|
1797
|
+
}
|
|
1798
|
+
const provider = getInjectedEthereumProvider();
|
|
1799
|
+
if (!provider) {
|
|
1800
|
+
return null;
|
|
1801
|
+
}
|
|
1802
|
+
const accounts = await provider.request({
|
|
1803
|
+
method: "eth_requestAccounts"
|
|
1804
|
+
});
|
|
1805
|
+
const address = accounts[0];
|
|
1806
|
+
if (!address) {
|
|
1807
|
+
throw new Error("No account found");
|
|
1808
|
+
}
|
|
1809
|
+
return {
|
|
1810
|
+
walletId: "injected",
|
|
1811
|
+
walletName: getInjectedWalletName(provider),
|
|
1812
|
+
address,
|
|
1813
|
+
provider
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
let requestIdCounter = 0;
|
|
1817
|
+
let activeRequest = null;
|
|
1818
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1819
|
+
let hostMountCount = 0;
|
|
1820
|
+
function notifyListeners() {
|
|
1821
|
+
listeners.forEach((listener) => {
|
|
1822
|
+
listener();
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
function getActiveRequestId() {
|
|
1826
|
+
return (activeRequest == null ? void 0 : activeRequest.id) ?? null;
|
|
1827
|
+
}
|
|
1828
|
+
function clearActiveRequest() {
|
|
1829
|
+
activeRequest = null;
|
|
1830
|
+
notifyListeners();
|
|
1831
|
+
}
|
|
1832
|
+
function settleSelectionResult(result) {
|
|
1833
|
+
if (!activeRequest) return;
|
|
1834
|
+
const current = activeRequest;
|
|
1835
|
+
clearActiveRequest();
|
|
1836
|
+
current.resolve(result);
|
|
1837
|
+
}
|
|
1838
|
+
function settleSelectionError(error2) {
|
|
1839
|
+
if (!activeRequest) return;
|
|
1840
|
+
const current = activeRequest;
|
|
1841
|
+
clearActiveRequest();
|
|
1842
|
+
current.reject(error2);
|
|
1843
|
+
}
|
|
1844
|
+
function subscribeSelectionState(listener) {
|
|
1845
|
+
listeners.add(listener);
|
|
1846
|
+
return () => {
|
|
1847
|
+
listeners.delete(listener);
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
async function selectEvmWallet(options = {}) {
|
|
1851
|
+
var _a;
|
|
1852
|
+
if (typeof window === "undefined") {
|
|
1853
|
+
return Promise.reject(
|
|
1854
|
+
new Error("selectEvmWallet can only be used in browser environment")
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
if (hostMountCount === 0) {
|
|
1858
|
+
return Promise.reject(
|
|
1859
|
+
new Error(
|
|
1860
|
+
"WalletPickerDialogHost is not mounted. Render TaskOnProvider or WalletPickerDialogHost first."
|
|
1861
|
+
)
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
if (activeRequest) {
|
|
1865
|
+
return Promise.reject(new EvmWalletSelectionInProgressError());
|
|
1866
|
+
}
|
|
1867
|
+
if ((_a = options.signal) == null ? void 0 : _a.aborted) {
|
|
1868
|
+
return Promise.reject(new EvmWalletSelectionCanceledError());
|
|
1869
|
+
}
|
|
1870
|
+
try {
|
|
1871
|
+
const injectedSelection = await trySelectInjectedWalletForMobileDapp();
|
|
1872
|
+
if (injectedSelection) {
|
|
1873
|
+
return injectedSelection;
|
|
1874
|
+
}
|
|
1875
|
+
} catch (error2) {
|
|
1876
|
+
if (isUserRejectedError(error2)) {
|
|
1877
|
+
throw new EvmWalletSelectionCanceledError("Wallet connection was rejected by user");
|
|
1878
|
+
}
|
|
1879
|
+
throw error2;
|
|
1880
|
+
}
|
|
1881
|
+
return new Promise((resolve, reject) => {
|
|
1882
|
+
var _a2;
|
|
1883
|
+
const requestId = ++requestIdCounter;
|
|
1884
|
+
const cleanupAbortListener = () => {
|
|
1885
|
+
var _a3;
|
|
1886
|
+
(_a3 = options.signal) == null ? void 0 : _a3.removeEventListener("abort", handleAbort);
|
|
1887
|
+
};
|
|
1888
|
+
const handleAbort = () => {
|
|
1889
|
+
if ((activeRequest == null ? void 0 : activeRequest.id) !== requestId) return;
|
|
1890
|
+
cleanupAbortListener();
|
|
1891
|
+
settleSelectionError(new EvmWalletSelectionCanceledError());
|
|
1892
|
+
};
|
|
1893
|
+
activeRequest = {
|
|
1894
|
+
id: requestId,
|
|
1895
|
+
resolve: (result) => {
|
|
1896
|
+
cleanupAbortListener();
|
|
1897
|
+
resolve(result);
|
|
1898
|
+
},
|
|
1899
|
+
reject: (error2) => {
|
|
1900
|
+
cleanupAbortListener();
|
|
1901
|
+
reject(error2);
|
|
1902
|
+
}
|
|
1903
|
+
};
|
|
1904
|
+
(_a2 = options.signal) == null ? void 0 : _a2.addEventListener("abort", handleAbort, { once: true });
|
|
1905
|
+
notifyListeners();
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
function WalletPickerDialogHost() {
|
|
1909
|
+
const [activeRequestId, setActiveRequestId] = useState(
|
|
1910
|
+
getActiveRequestId()
|
|
1911
|
+
);
|
|
1912
|
+
useEffect(() => {
|
|
1913
|
+
hostMountCount += 1;
|
|
1914
|
+
return subscribeSelectionState(() => {
|
|
1915
|
+
setActiveRequestId(getActiveRequestId());
|
|
1916
|
+
});
|
|
1917
|
+
}, []);
|
|
1918
|
+
useEffect(() => {
|
|
1919
|
+
return () => {
|
|
1920
|
+
hostMountCount = Math.max(0, hostMountCount - 1);
|
|
1921
|
+
if (hostMountCount === 0 && activeRequest) {
|
|
1922
|
+
settleSelectionError(
|
|
1923
|
+
new Error("Wallet selector host was unmounted during selection")
|
|
1924
|
+
);
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1927
|
+
}, []);
|
|
1928
|
+
const open = activeRequestId !== null;
|
|
1929
|
+
const handleOpenChange = useCallback((nextOpen) => {
|
|
1930
|
+
if (nextOpen) return;
|
|
1931
|
+
settleSelectionError(new EvmWalletSelectionCanceledError());
|
|
1932
|
+
}, []);
|
|
1933
|
+
const handleSelect = useCallback(
|
|
1934
|
+
async (selection) => {
|
|
1935
|
+
const { walletId, walletName, address, provider } = selection;
|
|
1936
|
+
if (!provider || typeof provider.request !== "function") {
|
|
1937
|
+
settleSelectionError(new Error("Invalid wallet provider"));
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
settleSelectionResult({
|
|
1941
|
+
walletId,
|
|
1942
|
+
walletName,
|
|
1943
|
+
address,
|
|
1944
|
+
provider
|
|
1945
|
+
});
|
|
1946
|
+
},
|
|
1947
|
+
[]
|
|
1948
|
+
);
|
|
1949
|
+
const handleError = useCallback((error2) => {
|
|
1950
|
+
settleSelectionError(new Error(error2 || "Failed to connect wallet"));
|
|
1951
|
+
}, []);
|
|
1952
|
+
return /* @__PURE__ */ jsx(
|
|
1953
|
+
WalletPickerDialog,
|
|
1954
|
+
{
|
|
1955
|
+
open,
|
|
1956
|
+
onOpenChange: handleOpenChange,
|
|
1957
|
+
onSelect: handleSelect,
|
|
1958
|
+
onError: handleError
|
|
1959
|
+
}
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
const selectEvmWallet$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1963
|
+
__proto__: null,
|
|
1964
|
+
EvmWalletSelectionCanceledError,
|
|
1965
|
+
EvmWalletSelectionInProgressError,
|
|
1966
|
+
WalletPickerDialogHost,
|
|
1967
|
+
selectEvmWallet
|
|
1968
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1969
|
+
function TaskOnProvider({
|
|
1970
|
+
config,
|
|
1971
|
+
children,
|
|
1972
|
+
preloadLocales
|
|
1973
|
+
}) {
|
|
1974
|
+
const [userInfo, setUserInfo] = useState(null);
|
|
1975
|
+
const [userToken, setUserToken] = useState(null);
|
|
1976
|
+
const [chains, setChains] = useState([]);
|
|
1977
|
+
const [communityInfo, setCommunityInfo] = useState(null);
|
|
1978
|
+
const toastState = useToastState();
|
|
1979
|
+
const { locale } = useLocaleManager({
|
|
1980
|
+
configLocale: config.locale,
|
|
1981
|
+
preloadLocales
|
|
1982
|
+
});
|
|
1983
|
+
const { client, userApiRef, isInitializing, isSessionReady } = useClientInit({
|
|
1984
|
+
clientId: config.clientId,
|
|
1985
|
+
baseURL: config.baseURL,
|
|
1986
|
+
setUserInfo,
|
|
1987
|
+
setUserToken
|
|
1988
|
+
});
|
|
1989
|
+
const { login, logout } = useAuth({
|
|
1990
|
+
client,
|
|
1991
|
+
userApiRef,
|
|
1992
|
+
setUserInfo,
|
|
1993
|
+
setUserToken
|
|
1994
|
+
});
|
|
1995
|
+
const requestLogin = useCallback(() => {
|
|
1996
|
+
var _a;
|
|
1997
|
+
(_a = config.onRequestLogin) == null ? void 0 : _a.call(config);
|
|
1998
|
+
}, [config]);
|
|
1999
|
+
const refreshUserInfo = useCallback(async () => {
|
|
2000
|
+
const userApi = userApiRef.current;
|
|
2001
|
+
if (!userApi) return;
|
|
2002
|
+
try {
|
|
2003
|
+
const info = await userApi.getInfo();
|
|
2004
|
+
setUserInfo(info);
|
|
2005
|
+
} catch {
|
|
2006
|
+
}
|
|
2007
|
+
}, [userApiRef]);
|
|
2008
|
+
useEffect(() => {
|
|
2009
|
+
if (!client) return;
|
|
2010
|
+
const loadChains = async () => {
|
|
2011
|
+
try {
|
|
2012
|
+
const chainApi = createChainApi(client);
|
|
2013
|
+
const chainList = await chainApi.getChainInfo();
|
|
2014
|
+
setChains(chainList);
|
|
2015
|
+
} catch {
|
|
2016
|
+
}
|
|
2017
|
+
};
|
|
2018
|
+
loadChains();
|
|
2019
|
+
}, [client]);
|
|
2020
|
+
useEffect(() => {
|
|
2021
|
+
if (!client) return;
|
|
2022
|
+
const loadCommunityInfo = async () => {
|
|
2023
|
+
try {
|
|
2024
|
+
const communityTaskApi = createCommunityTaskApi(client);
|
|
2025
|
+
const info = await communityTaskApi.getCommunityInfo();
|
|
2026
|
+
setCommunityInfo(info);
|
|
2027
|
+
} catch {
|
|
2028
|
+
}
|
|
2029
|
+
};
|
|
2030
|
+
loadCommunityInfo();
|
|
2031
|
+
}, [client]);
|
|
2032
|
+
const contextValue = useMemo(
|
|
2033
|
+
() => ({
|
|
2034
|
+
config,
|
|
2035
|
+
client,
|
|
2036
|
+
isInitializing,
|
|
2037
|
+
isSessionReady,
|
|
2038
|
+
locale,
|
|
2039
|
+
userId: (userInfo == null ? void 0 : userInfo.id) ?? null,
|
|
2040
|
+
userInfo,
|
|
2041
|
+
userToken,
|
|
2042
|
+
isLoggedIn: userInfo !== null && userToken !== null,
|
|
2043
|
+
login,
|
|
2044
|
+
logout,
|
|
2045
|
+
requestLogin,
|
|
2046
|
+
refreshUserInfo,
|
|
2047
|
+
chains,
|
|
2048
|
+
communityInfo
|
|
2049
|
+
}),
|
|
2050
|
+
[config, client, isInitializing, isSessionReady, locale, userInfo, userToken, login, logout, requestLogin, refreshUserInfo, chains, communityInfo]
|
|
2051
|
+
);
|
|
2052
|
+
return /* @__PURE__ */ jsx(TaskOnContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(ToastContext.Provider, { value: toastState, children: /* @__PURE__ */ jsxs(ToastProvider, { children: [
|
|
2053
|
+
/* @__PURE__ */ jsx(WalletProvider, { config: config.walletConfig, children }),
|
|
2054
|
+
/* @__PURE__ */ jsx(WalletPickerDialogHost, {}),
|
|
2055
|
+
/* @__PURE__ */ jsx(
|
|
2056
|
+
ToastViewport,
|
|
2057
|
+
{
|
|
2058
|
+
toasts: toastState.toasts,
|
|
2059
|
+
onRemove: toastState.removeToast
|
|
2060
|
+
}
|
|
2061
|
+
)
|
|
2062
|
+
] }) }) });
|
|
2063
|
+
}
|
|
2064
|
+
export {
|
|
2065
|
+
EvmWalletSelectionCanceledError as E,
|
|
2066
|
+
TaskOnProvider as T,
|
|
2067
|
+
WalletPickerDialog as W,
|
|
2068
|
+
WalletPickerDialogHost as a,
|
|
2069
|
+
EvmWalletSelectionInProgressError as b,
|
|
2070
|
+
selectEvmWallet as s,
|
|
2071
|
+
useCommonLocale as u
|
|
2072
|
+
};
|