@btc-vision/walletconnect 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.prettierrc.json +1 -1
  2. package/CHANGELOG.md +83 -0
  3. package/README.md +11 -11
  4. package/browser/consts.d.ts +2 -0
  5. package/browser/context/WalletConnectContext.d.ts +18 -0
  6. package/browser/hooks/WalletConnectHook.d.ts +2 -0
  7. package/browser/index.d.ts +4 -2
  8. package/browser/index.js +1 -1
  9. package/browser/index.js.LICENSE.txt +0 -2
  10. package/browser/provider/WalletConnectProvider.d.ts +9 -0
  11. package/browser/types.d.ts +11 -0
  12. package/browser/utils/accessibility/definitions.d.ts +2 -0
  13. package/browser/utils/accessibility/errorDecoder.d.ts +2 -0
  14. package/browser/utils/accessibility/patterns.d.ts +13 -0
  15. package/browser/wallets/controller.d.ts +29 -0
  16. package/browser/wallets/index.d.ts +4 -0
  17. package/browser/wallets/opwallet/controller.d.ts +26 -0
  18. package/browser/wallets/opwallet/interface.d.ts +5 -0
  19. package/browser/wallets/types.d.ts +34 -0
  20. package/browser/wallets/unisat/controller.d.ts +26 -0
  21. package/browser/wallets/unisat/interface.d.ts +5 -0
  22. package/build/consts.d.ts +2 -0
  23. package/build/consts.js +6 -0
  24. package/build/context/WalletConnectContext.d.ts +18 -0
  25. package/build/context/WalletConnectContext.js +2 -0
  26. package/build/hooks/WalletConnectHook.d.ts +2 -0
  27. package/build/hooks/WalletConnectHook.js +9 -0
  28. package/build/index.d.ts +4 -2
  29. package/build/index.js +4 -2
  30. package/build/provider/WalletConnectProvider.d.ts +9 -0
  31. package/build/provider/WalletConnectProvider.js +178 -0
  32. package/build/types.d.ts +11 -0
  33. package/build/types.js +1 -0
  34. package/build/utils/accessibility/definitions.d.ts +2 -0
  35. package/build/utils/accessibility/definitions.js +8 -0
  36. package/build/utils/accessibility/errorDecoder.d.ts +2 -0
  37. package/build/utils/accessibility/errorDecoder.js +73 -0
  38. package/build/utils/accessibility/patterns.d.ts +13 -0
  39. package/build/utils/accessibility/patterns.js +51 -0
  40. package/build/wallets/controller.d.ts +29 -0
  41. package/build/wallets/controller.js +205 -0
  42. package/build/wallets/index.d.ts +4 -0
  43. package/build/wallets/index.js +16 -0
  44. package/build/wallets/opwallet/controller.d.ts +26 -0
  45. package/build/wallets/opwallet/controller.js +132 -0
  46. package/build/wallets/opwallet/interface.d.ts +5 -0
  47. package/build/wallets/opwallet/interface.js +35 -0
  48. package/build/wallets/types.d.ts +34 -0
  49. package/build/wallets/types.js +1 -0
  50. package/build/wallets/unisat/controller.d.ts +26 -0
  51. package/build/wallets/unisat/controller.js +135 -0
  52. package/build/wallets/unisat/interface.d.ts +5 -0
  53. package/build/wallets/unisat/interface.js +285 -0
  54. package/eslint.config.js +23 -2
  55. package/package.json +10 -5
  56. package/src/README.md +24 -0
  57. package/src/consts.ts +8 -0
  58. package/src/context/WalletConnectContext.ts +21 -0
  59. package/src/hooks/WalletConnectHook.tsx +13 -0
  60. package/src/index.ts +5 -2
  61. package/src/provider/WalletConnectProvider.tsx +341 -0
  62. package/src/types.ts +13 -0
  63. package/src/utils/accessibility/definitions.ts +9 -0
  64. package/src/utils/accessibility/errorDecoder.ts +105 -0
  65. package/src/utils/accessibility/patterns.ts +86 -0
  66. package/src/utils/style.css +131 -0
  67. package/src/utils/theme.css +26 -0
  68. package/src/wallets/controller.ts +231 -0
  69. package/src/wallets/index.ts +22 -0
  70. package/src/wallets/opwallet/controller.ts +177 -0
  71. package/src/wallets/opwallet/interface.ts +42 -0
  72. package/src/wallets/types.ts +39 -0
  73. package/src/wallets/unisat/controller.ts +179 -0
  74. package/src/wallets/unisat/interface.ts +292 -0
  75. package/tsconfig.webpack.json +2 -6
  76. package/webpack.config.js +4 -0
  77. package/browser/WalletConnection.d.ts +0 -21
  78. package/browser/WalletProvider.d.ts +0 -25
  79. package/build/WalletConnection.d.ts +0 -21
  80. package/build/WalletConnection.js +0 -152
  81. package/build/WalletProvider.d.ts +0 -25
  82. package/build/WalletProvider.js +0 -178
  83. package/src/WalletConnection.ts +0 -210
  84. package/src/WalletProvider.tsx +0 -240
@@ -0,0 +1,341 @@
1
+ import { Address, Unisat, UnisatSigner } from '@btc-vision/transaction';
2
+ import React, { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { DefaultWalletConnectNetwork } from '../consts';
4
+ import { WalletConnectContext } from '../context/WalletConnectContext';
5
+ import type { WalletConnectNetwork, WalletInformation } from '../types.ts';
6
+ import '../utils/style.css';
7
+ import '../utils/theme.css';
8
+ import { SupportedWallets, WalletController } from '../wallets';
9
+ import type {
10
+ ControllerConnectAccounts,
11
+ ControllerErrorResponse,
12
+ ControllerResponse,
13
+ WalletConnectWallet,
14
+ } from '../wallets/types.ts';
15
+
16
+ const AUTO_RECONNECT_RETRIES = 5;
17
+
18
+ interface WalletConnectProviderProps {
19
+ theme?: 'light' | 'dark' | 'moto';
20
+ children: ReactNode;
21
+ }
22
+
23
+ const WalletConnectProvider: React.FC<WalletConnectProviderProps> = ({ theme, children }) => {
24
+ const [connectError, setConnectError] = useState<string | undefined>(undefined);
25
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null);
26
+
27
+ const [network, setNetwork] = useState<WalletConnectNetwork>(DefaultWalletConnectNetwork);
28
+
29
+ const [supportedWallets] = useState<WalletConnectWallet[]>(WalletController.getWallets);
30
+ const [selectedWallet, setSelectedWallet] = useState<SupportedWallets | null>(
31
+ () => (localStorage.getItem('WC_SelectedWallet') as SupportedWallets) || null,
32
+ );
33
+ const [connecting, setConnecting] = useState<boolean>(false);
34
+ const [modalOpen, setModalOpen] = useState<boolean>(false);
35
+
36
+ const [walletAddress, setWalletAddress] = useState<string | null>(null);
37
+ const [publicKey, setPublicKey] = useState<string | null>(null);
38
+ const [walletType, setWalletType] = useState<SupportedWallets | null>(null);
39
+ const [provider, setProvider] = useState<Unisat | null>(null);
40
+ const [signer, setSigner] = useState<UnisatSigner | null>(null);
41
+
42
+ const clearConnectError = useCallback(() => {
43
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
44
+ timeoutRef.current = setTimeout(() => setConnectError(undefined), 5000);
45
+ }, []);
46
+
47
+ useEffect(() => {
48
+ if (connectError) {
49
+ clearConnectError();
50
+ }
51
+ }, [connectError, clearConnectError]);
52
+
53
+ const openConnectModal = () => {
54
+ setConnectError(undefined);
55
+ setModalOpen(true);
56
+ };
57
+
58
+ const closeConnectModal = () => {
59
+ setModalOpen(false);
60
+ setConnectError(undefined);
61
+ };
62
+
63
+ const disconnect = useCallback(async () => {
64
+ console.log('DISCONNECTING FROM WALLET');
65
+ localStorage.removeItem('WC_SelectedWallet');
66
+ setSelectedWallet(null);
67
+ setPublicKey(null);
68
+ setWalletAddress(null);
69
+ setConnecting(false);
70
+ WalletController.removeDisconnectHook();
71
+ WalletController.removeChainChangedHook();
72
+ WalletController.removeAccountsChangedHook();
73
+ await WalletController.disconnect();
74
+ setNetwork(DefaultWalletConnectNetwork); // Triggers allWallets update after disconnecting
75
+ }, []);
76
+
77
+ const connectToWallet = useCallback(
78
+ async (wallet: SupportedWallets) => {
79
+ setConnecting(true);
80
+ try {
81
+ const response: ControllerResponse<
82
+ ControllerConnectAccounts | ControllerErrorResponse
83
+ > = await WalletController.connect(wallet);
84
+
85
+ if (response.code === 200 && Array.isArray(response.data)) {
86
+ if (!response.data || response.data.length === 0) {
87
+ return;
88
+ }
89
+ setWalletAddress(response.data[0]);
90
+ const publicKey = await WalletController.getPublicKey();
91
+ setPublicKey(publicKey);
92
+ const network = await WalletController.getNetwork();
93
+ setNetwork(network);
94
+
95
+ WalletController.setAccountsChangedHook(accountsChanged);
96
+ WalletController.setChainChangedHook(chainChanged);
97
+ WalletController.setDisconnectHook(disconnect);
98
+
99
+ closeConnectModal();
100
+ setSelectedWallet(wallet);
101
+ localStorage.setItem('WC_SelectedWallet', wallet);
102
+ } else if (response.data && 'message' in response.data) {
103
+ setConnectError(response.data.message);
104
+ } else {
105
+ setConnectError('Unknown error');
106
+ }
107
+ } catch (err: unknown) {
108
+ setConnectError((err as Error).message || 'Unexpected error');
109
+ } finally {
110
+ setConnecting(false);
111
+ }
112
+ },
113
+ // eslint-disable-next-line
114
+ [disconnect],
115
+ );
116
+
117
+ const attemptReconnect = useCallback(async () => {
118
+ console.warn('Trying to reconnect...', selectedWallet, connecting);
119
+ if (!selectedWallet || connecting) return;
120
+
121
+ // Ensure we can connect without launching modal popup windows!
122
+ const canAutoConnect = await WalletController.canAutoConnect(selectedWallet);
123
+ console.log('CanAutoConnect', canAutoConnect);
124
+ if (!canAutoConnect) return;
125
+
126
+ let attempts = 0;
127
+
128
+ const reconnect = async () => {
129
+ attempts++;
130
+
131
+ const walletAvailable = WalletController.isWalletInstalled(selectedWallet);
132
+ if (walletAvailable) {
133
+ console.log(`Attempting to reconnect to ${selectedWallet} (Attempt ${attempts})`);
134
+ await connectToWallet(selectedWallet);
135
+ return;
136
+ }
137
+
138
+ if (attempts < AUTO_RECONNECT_RETRIES) {
139
+ setTimeout(reconnect, 1000 * attempts);
140
+ }
141
+ };
142
+
143
+ await reconnect();
144
+ // eslint-disable-next-line
145
+ }, [selectedWallet, connectToWallet]);
146
+
147
+ useEffect(() => {
148
+ void attemptReconnect();
149
+ }, [attemptReconnect]);
150
+
151
+ const accountsChanged = useCallback(
152
+ async (accounts: string[]) => {
153
+ console.log('Accounts', accounts);
154
+ if (selectedWallet) {
155
+ const account = accounts.length > 0 ? accounts[0] : null;
156
+ setWalletAddress(account);
157
+ const publicKey = account ? await WalletController.getPublicKey() : null;
158
+ setPublicKey(publicKey);
159
+ }
160
+ },
161
+ [selectedWallet, setWalletAddress, setPublicKey],
162
+ );
163
+
164
+ const chainChanged = useCallback(
165
+ (network: WalletConnectNetwork): void => {
166
+ if (selectedWallet) {
167
+ setNetwork(network);
168
+ }
169
+ },
170
+ [selectedWallet, setNetwork],
171
+ );
172
+
173
+ const allWallets = useMemo(() => {
174
+ //console.log("Refreshing all wallets");
175
+ return supportedWallets.map((wallet): WalletInformation => {
176
+ //console.log(" --> ", wallet.name, wallet.controller.isInstalled(), wallet.controller.isConnected());
177
+ return {
178
+ name: wallet.name,
179
+ icon: wallet.icon,
180
+ isInstalled: wallet.controller.isInstalled(),
181
+ isConnected: wallet.controller.isConnected(),
182
+ };
183
+ });
184
+ // eslint-disable-next-line
185
+ }, [supportedWallets, network]);
186
+
187
+ const availableWallets = useMemo(() => {
188
+ return supportedWallets.filter((wallet) => wallet.controller.isInstalled());
189
+ //return supportedWallets
190
+ // eslint-disable-next-line
191
+ }, [supportedWallets, network]);
192
+
193
+ useEffect(() => {
194
+ const walletType = walletAddress ? WalletController.getWalletType() : null;
195
+ setWalletType(walletType);
196
+ const provider = walletAddress ? WalletController.getProvider() : null;
197
+ setProvider(provider);
198
+ }, [walletAddress]);
199
+
200
+ useEffect(() => {
201
+ const updateSigner = async () => {
202
+ const signer = publicKey ? await WalletController.getSigner() : null;
203
+ setSigner(signer);
204
+ };
205
+ void updateSigner();
206
+ }, [network, publicKey]);
207
+
208
+ const currentTheme = useMemo(() => {
209
+ const currentTheme = theme || 'light';
210
+ return `wallet-connect-${currentTheme}-theme`;
211
+ }, [theme]);
212
+
213
+ const address = useMemo(() => {
214
+ return publicKey ? Address.fromString(publicKey) : null;
215
+ }, [publicKey]);
216
+
217
+ return (
218
+ <WalletConnectContext.Provider
219
+ value={{
220
+ walletAddress,
221
+ publicKey,
222
+ address,
223
+ connecting,
224
+ connectToWallet,
225
+ disconnect,
226
+ openConnectModal,
227
+ network,
228
+ allWallets,
229
+ provider,
230
+ signer,
231
+ walletType,
232
+ }}>
233
+ {children}
234
+ {modalOpen && (
235
+ <div className={`wallet-connect-modal-backdrop ${currentTheme}`}>
236
+ <div
237
+ className="wallet-connect-modal"
238
+ role="dialog"
239
+ aria-modal="true"
240
+ aria-labelledby="wallet-connect-modal-title">
241
+ <div className="wallet-connect-header">
242
+ <span>Connect Wallet</span>
243
+ <button
244
+ className="close"
245
+ onClick={() => closeConnectModal()}>
246
+ <span className="close-icon">
247
+ <svg
248
+ width="30px"
249
+ height="30px"
250
+ viewBox="0 0 24 24"
251
+ xmlns="http://www.w3.org/2000/svg">
252
+ <path
253
+ className="close-x-path"
254
+ d="M16 8L8 16M8.00001 8L16 16"
255
+ stroke="#fff"
256
+ strokeWidth="1.5"
257
+ strokeLinecap="round"
258
+ strokeLinejoin="round"
259
+ />
260
+ </svg>
261
+ </span>
262
+ </button>
263
+ </div>
264
+ {connectError && (
265
+ <div className="wallet-connect-error">
266
+ <p className="error-message">{connectError}</p>
267
+ </div>
268
+ )}
269
+ {availableWallets.length > 0 ? (
270
+ <div className="wallet-list">
271
+ {availableWallets.map((wallet) => (
272
+ <button
273
+ key={wallet.name}
274
+ onClick={() => connectToWallet(wallet.name)}
275
+ disabled={connecting || !wallet.controller.isInstalled()}
276
+ className={`wallet-button ${
277
+ wallet.controller.isInstalled()
278
+ ? 'wallet-installed'
279
+ : 'wallet-not-installed'
280
+ }`}>
281
+ {wallet.icon ? (
282
+ <div
283
+ className="wallet-icon"
284
+ title={wallet.name}>
285
+ <img
286
+ src={wallet.icon}
287
+ alt={wallet.name}
288
+ />
289
+ </div>
290
+ ) : (
291
+ <div className="wallet-name">{wallet.name}</div>
292
+ )}
293
+
294
+ {wallet.controller.isConnected() ? (
295
+ <div className="wallet-connected">(Connected)</div>
296
+ ) : (
297
+ <></>
298
+ )}
299
+ {wallet.controller.isInstalled() ? (
300
+ <></>
301
+ ) : (
302
+ <div className="wallet-not-installed">
303
+ (Not Installed)
304
+ </div>
305
+ )}
306
+ </button>
307
+ ))}
308
+ </div>
309
+ ) : (
310
+ <div>
311
+ <p>No wallets available</p>
312
+ <p>Supporting the following wallets</p>
313
+ <div className="wallet-list">
314
+ {supportedWallets.map((wallet) => (
315
+ <a
316
+ href={`https://chromewebstore.google.com/search/${wallet.name}`}>
317
+ {wallet.icon ? (
318
+ <div
319
+ className="wallet-icon"
320
+ title={wallet.name}>
321
+ <img
322
+ src={wallet.icon}
323
+ alt={wallet.name}
324
+ />
325
+ </div>
326
+ ) : (
327
+ <div className="wallet-name">{wallet.name}</div>
328
+ )}
329
+ </a>
330
+ ))}
331
+ </div>
332
+ </div>
333
+ )}
334
+ </div>
335
+ </div>
336
+ )}
337
+ </WalletConnectContext.Provider>
338
+ );
339
+ };
340
+
341
+ export default WalletConnectProvider;
package/src/types.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { Network } from '@btc-vision/bitcoin';
2
+ import { UnisatChainType } from '@btc-vision/transaction';
3
+
4
+ export interface WalletConnectNetwork extends Network {
5
+ chainType: UnisatChainType;
6
+ }
7
+
8
+ export interface WalletInformation {
9
+ name: string;
10
+ icon: string;
11
+ isInstalled: boolean;
12
+ isConnected: boolean;
13
+ }
@@ -0,0 +1,9 @@
1
+ export const genericErrors: Record<string, string> = {
2
+ UserRejected: 'Wallet Dialog was closed by the user',
3
+ UnknownError: 'Unknown error occurred',
4
+ IndexingInProgress: 'Node is still indexing. Please try again shortly',
5
+ };
6
+
7
+ export const errorDefinitions: Record<string, string> = {
8
+ ...genericErrors,
9
+ };
@@ -0,0 +1,105 @@
1
+ import type { ErrorTranslations } from './patterns';
2
+ import { patternMap, patternRegExp } from './patterns';
3
+
4
+ // Sample: Error in calling function: Spender can not be dead at ~lib/@btc-vision/btc-runtime/runtime/contracts/DeployableOP_20.ts:291:50
5
+ // matches[2] == null
6
+ // matches[3] == 'Spender can not be dead'
7
+ // Sample: Error in calling function: NATIVE_SWAP: LOCKED at ~lib/@btc-vision/btc-runtime/runtime/contracts/DeployableOP_20.ts:291:50
8
+ // matches[2] == 'NATIVE_SWAP'
9
+ // matches[3] == 'LOCKED'
10
+ const RE_EXTRACT_ERROR = new RegExp(
11
+ '^(.*?):\\s*(?:([^:]+):)?\\s*(.*?)\\s+at\\s(\\S+\\s\\()?\\S+\\d+:\\d+\\)?',
12
+ 'm',
13
+ );
14
+
15
+ const _translation = (err: ErrorTranslations, locale: string | null) => {
16
+ // Using a switch here to be sure we are safe as to not try to use
17
+ // a function or other attributes. For exemple if someone create
18
+ // a 'get' locale, we should not try to call err['get']...
19
+ switch (locale) {
20
+ case 'en':
21
+ return err['en'] || '';
22
+ case 'en-us':
23
+ return err['en-US'] || '';
24
+ case 'fr':
25
+ return err['fr'] || '';
26
+ case 'fr-ca':
27
+ return err['fr-CA'] || '';
28
+ default:
29
+ return '';
30
+ }
31
+ };
32
+
33
+ const _errors = (err: string | ErrorTranslations, locales: string[]) => {
34
+ if (typeof err === 'string') {
35
+ return err;
36
+ } else {
37
+ for (const locale of locales) {
38
+ const translation = _translation(err, locale);
39
+ if (translation) return translation;
40
+ }
41
+ return err['en']; // Return default locale
42
+ }
43
+ };
44
+
45
+ const _normalizeLocales = (locales: string[]) => {
46
+ const _locales = locales.map((l) => l.toLowerCase().trim());
47
+ // Add fallback locales if needed
48
+ for (const locale of _locales) {
49
+ const language = locale.split('-')[0];
50
+ if (!_locales.includes(language)) {
51
+ _locales.push(language);
52
+ }
53
+ }
54
+ return _locales;
55
+ };
56
+
57
+ // When translation will be enabled, will need to feed locale
58
+ // with the locale from the user's browser
59
+ export const _e = (err: string | Error, locales: string[] = ['en']): string => {
60
+ const [, , error] = _match_e(err.toString(), locales);
61
+ return error;
62
+ };
63
+ // This is mostly for debugging as it return the full matched information.
64
+ // returns [orig, pattern, translation] where
65
+ // - orig is the original key in the patterns definition
66
+ // - pattern is the transformed (lowercase, regex, etc.) key
67
+ // - translation is the resulting translation for the current key
68
+ export const _match_e = (err: string, locales: string[] = ['en']): string[] => {
69
+ const normalizedLocales = _normalizeLocales(locales);
70
+ const matches = RE_EXTRACT_ERROR.exec(err);
71
+ const packageName = matches ? matches[2] : '';
72
+ let msg = matches ? matches[3] : err;
73
+
74
+ const lookup = `${packageName}: ${msg}`.trim();
75
+ const lookupLower = lookup.toLowerCase();
76
+
77
+ // First checks with regex as these messages may be catched by includes later
78
+ for (const [orig, pattern, translation] of patternRegExp) {
79
+ const placeHolders = pattern.exec(lookup);
80
+ if (placeHolders) {
81
+ msg = _errors(translation, normalizedLocales) || msg;
82
+ for (let i = 0; i < placeHolders.length; i++) {
83
+ const regex = new RegExp(`\\$${i}`, 'g');
84
+ msg = msg.replace(regex, placeHolders[i] ?? '');
85
+ }
86
+ return [orig, pattern.source, msg];
87
+ }
88
+ }
89
+
90
+ // Next checks fast patterns that are matched as lower case strings
91
+ for (const [orig, pattern, translation] of patternMap) {
92
+ if (lookupLower == pattern) {
93
+ return [orig, pattern, _errors(translation, normalizedLocales) || msg];
94
+ }
95
+ }
96
+
97
+ // Finally checks fast patterns that are matched as lower case includes
98
+ for (const [orig, pattern, translation] of patternMap) {
99
+ if (lookupLower.includes(pattern)) {
100
+ return [orig, pattern, _errors(translation, normalizedLocales) || msg];
101
+ }
102
+ }
103
+
104
+ return ['', '', msg];
105
+ };
@@ -0,0 +1,86 @@
1
+ import { errorDefinitions } from './definitions';
2
+
3
+ export type ErrorTranslations = {
4
+ en: ErrorMessage; // Default language, required
5
+ 'en-US'?: ErrorMessage;
6
+ fr?: ErrorMessage;
7
+ 'fr-CA'?: ErrorMessage;
8
+ };
9
+
10
+ type ErrorMessage = (typeof errorDefinitions)[keyof typeof errorDefinitions];
11
+ type ErrorMessages = ErrorMessage | ErrorTranslations;
12
+
13
+ const rawPatternGeneric: Record<string, ErrorMessages> = {
14
+ 'User rejected the request.': errorDefinitions.UserRejected,
15
+ "TypeError: Cannot read properties of undefined (reading 'addresses')":
16
+ errorDefinitions.UserRejected,
17
+ };
18
+
19
+ const rawPatternUnitTest: Record<string, ErrorMessages> = {
20
+ //'TEST_CASE: not there': ''
21
+ 'TEST_CASE: empty': '',
22
+ 'TEST_CASE: simple': 'simple',
23
+ 'TEST_CASE: regex1 ${value}': 'regex1',
24
+ 'TEST_CASE: regex2 ${value}': 'regex2 $1',
25
+
26
+ //'Test case not there': ''
27
+ 'Test case empty': '',
28
+ 'Test case simple': 'simple',
29
+ 'Test case regex1 ${value}': 'regex1',
30
+ 'Test case regex2 ${value.get()}': 'regex2 $1',
31
+
32
+ // Multi-language
33
+ 'TEST_MULTI: multi1': {
34
+ en: 'Test English',
35
+ 'en-US': 'Test American English',
36
+ fr: 'Test French',
37
+ 'fr-CA': 'Test Canadian French',
38
+ },
39
+
40
+ 'TEST_MULTI: multi2 ${value}': {
41
+ en: 'Test English: $1',
42
+ 'en-US': 'Test American English: $1',
43
+ fr: 'Test French: $1',
44
+ 'fr-CA': 'Test Canadian French: $1',
45
+ },
46
+ };
47
+
48
+ // Patterns may be
49
+ // - simple string (if key don't contain a closing parenthesis '(' ).
50
+ // - regex expression (if key contains at least one '(' for regex group matching).
51
+ // The group matching don't need to be used in translation
52
+ // Group matching start at $0 (full match) and $1 (first group), $2...
53
+ //
54
+ // Simple key
55
+ // 'Test': 'This is a translated test',
56
+ // Regex key
57
+ // 'Test for (\\w+)': 'This is a test for some function',
58
+ // 'Test function (\\w+)': 'This is a testing sample for function $1',
59
+ const rawPatternMap: Record<string, ErrorMessage> = {
60
+ 'NATIVE_SWAP: Liquidity value is too low in satoshis.':
61
+ errorDefinitions.NativeSwapLiquidityValueTooLow,
62
+ 'Unknown Error': errorDefinitions.UnknownError,
63
+ 'Invalid Address': errorDefinitions.IndexingInProgress,
64
+ 'Error Indexing at Block': errorDefinitions.IndexingInProgress,
65
+ 'Valid Reservation for this Address': errorDefinitions.NoValidReservation,
66
+
67
+ ...rawPatternGeneric,
68
+ ...rawPatternUnitTest,
69
+ };
70
+
71
+ export const patternMap: Array<[string, string, ErrorMessages]> = Object.entries(rawPatternMap)
72
+ .filter(([key, value]) => !!value && !key.includes('${'))
73
+ .sort((a, b) => b[0].length - a[0].length)
74
+ .map(([key, value]) => [key, key.toLowerCase(), value]);
75
+
76
+ export const escapeKey = (key: string): string => {
77
+ return key
78
+ .replace(/\(/g, '\\(')
79
+ .replace(/\)/g, '\\)')
80
+ .replace(/\./g, '\\.')
81
+ .replace(/\$\{.*?}/g, '(.+)');
82
+ };
83
+ export const patternRegExp: Array<[string, RegExp, ErrorMessages]> = Object.entries(rawPatternMap)
84
+ .filter(([key, value]) => !!value && key.includes('${'))
85
+ .sort((a, b) => b[0].length - a[0].length)
86
+ .map(([key, value]) => [key, new RegExp(escapeKey(key), 'i'), value]);
@@ -0,0 +1,131 @@
1
+ .wallet-connect-modal-backdrop {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ background-color: rgba(10, 11, 13, 0.5);
8
+ backdrop-filter: blur(10px);
9
+ z-index: 9999;
10
+ display: flex;
11
+ justify-content: center;
12
+ align-items: center;
13
+ }
14
+
15
+ .wallet-connect-modal {
16
+ background-color: var(--background-color);
17
+ border: 1px solid var(--border-color);
18
+ color: var(--primaryColor);
19
+ border-radius: 8px;
20
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
21
+ width: 400px;
22
+ max-width: 90%;
23
+ z-index: 10000;
24
+ }
25
+
26
+ .wallet-connect-header {
27
+ padding: 16px;
28
+ border-bottom: 1px solid var(--border-color);
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: space-between;
32
+ font-size: 14px;
33
+ font-weight: bold;
34
+ user-select: none;
35
+ }
36
+
37
+ .wallet-connect-header > button.close {
38
+ width: 30px;
39
+ height: 30px;
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ color: var(--primaryColor);
44
+ fill: var(--primaryColor);
45
+ background-color: var(--background-color);
46
+ cursor: pointer;
47
+ }
48
+ .wallet-connect-header > button.close:hover {
49
+ border: 1px solid rgba(254, 121, 1, 0.3);
50
+ background-color: rgba(254, 121, 1, 0.1);
51
+ }
52
+ .wallet-connect-header > button.close svg {
53
+ display: flex;
54
+ }
55
+
56
+ .wallet-connect-header > button.close .close-x-path {
57
+ stroke: var(--primaryColor);
58
+ transition: stroke 0.2s ease;
59
+ }
60
+
61
+ .wallet-connect-header > button.close:hover .close-x-path {
62
+ }
63
+
64
+ .wallet-list {
65
+ max-height: 400px;
66
+ overflow-y: auto;
67
+ padding: 16px;
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 10px;
71
+ }
72
+
73
+ .wallet-list > button {
74
+ display: flex;
75
+ align-items: center;
76
+ gap: 12px;
77
+ height: 64px;
78
+ justify-content: space-between;
79
+ padding: 12px;
80
+ color: #fff;
81
+ width: 100%;
82
+ text-align: left;
83
+ cursor: pointer;
84
+ border-radius: 10px;
85
+ border: 1px solid var(--border-color);
86
+ background-color: var(--button-background-color);
87
+ }
88
+ .wallet-list > button:disabled {
89
+ opacity: 0.3;
90
+ cursor: not-allowed;
91
+ }
92
+
93
+ .wallet-list > button:hover {
94
+ border: 1px solid rgba(254, 121, 1, 0.3);
95
+ background-color: rgba(254, 121, 1, 0.1);
96
+ }
97
+ .wallet-icon {
98
+ display: flex;
99
+ }
100
+ .wallet-icon img {
101
+ max-height: 32px;
102
+ filter: var(--icon-filter);
103
+ }
104
+ .wallet-name {
105
+ font-size: x-large;
106
+ text-align: left;
107
+ }
108
+ .wallet-connected {
109
+ padding: 10px;
110
+ font-size: medium;
111
+ color: green;
112
+ }
113
+ div.wallet-not-installed {
114
+ padding: 10px;
115
+ font-size: medium;
116
+ }
117
+
118
+ .wallet-connect-error {
119
+ padding: 16px 16px 0;
120
+ }
121
+
122
+ .wallet-connect-error > p {
123
+ color: #ff4d4d;
124
+ text-align: center;
125
+ background-color: rgba(255, 77, 77, 0.1);
126
+ font-size: 14px;
127
+ font-weight: bolder;
128
+ padding: 20px 10px;
129
+ border-radius: 10px;
130
+ border: 1px solid #ff4d4d;
131
+ }