@rash2x/bridge-widget 0.1.18 → 0.1.20

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 CHANGED
@@ -194,38 +194,49 @@ function App() {
194
194
 
195
195
  ## Styling
196
196
 
197
- The widget uses Tailwind CSS. Make sure your project has Tailwind configured, or the styles will not work correctly.
198
-
199
- ### Tailwind Configuration
200
-
201
- ```js
202
- // tailwind.config.js
203
- module.exports = {
204
- content: [
205
- './src/**/*.{js,ts,jsx,tsx}',
206
- './node_modules/@evaa/bridge-widget/**/*.{js,mjs}',
207
- ],
208
- // ... rest of your config
209
- };
197
+ The widget comes with pre-compiled Tailwind CSS styles. **You don't need to have Tailwind installed** in your project for the widget to work.
198
+
199
+ ### Basic Usage
200
+
201
+ Simply import the styles and you're good to go:
202
+
203
+ ```tsx
204
+ import '@evaa/bridge-widget/styles.css';
210
205
  ```
211
206
 
212
- ### Custom Theme
207
+ All Tailwind utility classes used by the widget are already included in the compiled CSS. The widget has its own Tailwind configuration that ensures all necessary classes are bundled during the library build process.
208
+
209
+ ### Theme Customization
213
210
 
214
- You can customize the theme by overriding CSS variables:
211
+ Customize the widget's appearance by overriding CSS variables in your own stylesheet:
215
212
 
216
213
  ```css
217
214
  :root {
218
- --primary: #your-color;
219
- --background: #your-color;
220
- /* ... other variables */
215
+ --primary: #0095f9; /* Primary brand color */
216
+ --background: #ffffff; /* Background color */
217
+ --foreground: #171717; /* Text color */
218
+ --card: #f2f2f2; /* Card background */
219
+ --border: #00000029; /* Border color */
220
+ --radius: 0.625rem; /* Border radius */
221
+ /* ... see dist/styles.css for all available variables */
221
222
  }
222
223
 
223
224
  [data-theme="dark"] {
224
- --primary: #your-dark-color;
225
- /* ... other variables */
225
+ --primary: #5200ff;
226
+ --background: #000000;
227
+ --foreground: #ffffff;
228
+ /* ... dark theme overrides */
226
229
  }
227
230
  ```
228
231
 
232
+ **Complete list of customizable CSS variables:**
233
+ - Color tokens: `--background`, `--foreground`, `--primary`, `--secondary`, `--muted`, `--accent`, `--destructive`, `--border`, `--input`, `--ring`
234
+ - Semantic colors: `--link`, `--filter`, `--swap`, `--settings-button`, `--modal-x`, `--input-icon`, `--balance-icon`, and many more
235
+ - Border radius: `--radius` (affects all rounded corners)
236
+ - See the `dist/styles.css` file for the complete list
237
+
238
+ **Note:** The widget will work perfectly fine without Tailwind in your consuming project. All necessary styles are pre-compiled and included in `styles.css`.
239
+
229
240
  ## Advanced Usage
230
241
 
231
242
  ### Using Stores Directly
@@ -0,0 +1,81 @@
1
+ /* fonts.css */
2
+ @font-face {
3
+ font-family: 'Gilroy';
4
+ src: url('/assets/fonts/Gilroy-Thin.ttf') format('truetype');
5
+ font-style: normal;
6
+ font-weight: 100;
7
+ font-display: swap;
8
+ }
9
+ @font-face {
10
+ font-family: 'Gilroy';
11
+ src: url('/assets/fonts/Gilroy-UltraLight.ttf') format('truetype');
12
+ font-style: normal;
13
+ font-weight: 200;
14
+ font-display: swap;
15
+ }
16
+ @font-face {
17
+ font-family: 'Gilroy';
18
+ src: url('/assets/fonts/Gilroy-Light.ttf') format('truetype');
19
+ font-style: normal;
20
+ font-weight: 300;
21
+ font-display: swap;
22
+ }
23
+ @font-face {
24
+ font-family: 'Gilroy';
25
+ src: url('/assets/fonts/Gilroy-Regular.ttf') format('truetype');
26
+ font-style: normal;
27
+ font-weight: 400;
28
+ font-display: swap;
29
+ }
30
+ @font-face {
31
+ font-family: 'Gilroy';
32
+ src: url('/assets/fonts/Gilroy-Medium.ttf') format('truetype');
33
+ font-style: normal;
34
+ font-weight: 500;
35
+ font-display: swap;
36
+ }
37
+ @font-face {
38
+ font-family: 'Gilroy';
39
+ src: url('/assets/fonts/Gilroy-SemiBold.ttf') format('truetype');
40
+ font-style: normal;
41
+ font-weight: 600;
42
+ font-display: swap;
43
+ }
44
+ @font-face {
45
+ font-family: 'Gilroy';
46
+ src: url('/assets/fonts/Gilroy-Bold.ttf') format('truetype');
47
+ font-style: normal;
48
+ font-weight: 700;
49
+ font-display: swap;
50
+ }
51
+ @font-face {
52
+ font-family: 'Gilroy';
53
+ src: url('/assets/fonts/Gilroy-ExtraBold.ttf') format('truetype');
54
+ font-style: normal;
55
+ font-weight: 800;
56
+ font-display: swap;
57
+ }
58
+ @font-face {
59
+ font-family: 'Gilroy';
60
+ src: url('/assets/fonts/Gilroy-Black.ttf') format('truetype');
61
+ font-style: normal;
62
+ font-weight: 900;
63
+ font-display: swap;
64
+ }
65
+ @font-face {
66
+ font-family: 'Gilroy';
67
+ src: url('/assets/fonts/Gilroy-Heavy.ttf') format('truetype');
68
+ font-style: normal;
69
+ font-weight: 900;
70
+ font-display: swap;
71
+ }
72
+
73
+
74
+ @font-face {
75
+ font-family: 'Hanson';
76
+ src:
77
+ url(/assets/fonts/hanson-bold.woff2) format('woff2'),
78
+ url(/assets/fonts/hanson-bold.woff) format('woff');
79
+ font-style: normal;
80
+ font-weight: 700;
81
+ }
@@ -193,7 +193,7 @@ const initialState = {
193
193
  };
194
194
  const useTokensStore = zustand.create((set) => ({
195
195
  ...initialState,
196
- setTokens: async (data) => {
196
+ setTokens: (data) => {
197
197
  set({ tokens: data, assetMatrix: buildAssetMatrix(data) });
198
198
  },
199
199
  setSelectedToken: (data) => {
@@ -1109,7 +1109,9 @@ function useBalances(chainKey, address, priorityTokenSymbol) {
1109
1109
  const tokensList = [];
1110
1110
  for (const [, byChain] of Object.entries(assetMatrix)) {
1111
1111
  const token = byChain[chainKey];
1112
- if (token) tokensList.push(token);
1112
+ if (token && token.address && token.address.length > 2) {
1113
+ tokensList.push(token);
1114
+ }
1113
1115
  }
1114
1116
  return tokensList;
1115
1117
  }, [assetMatrix, chainKey]);
@@ -1117,7 +1119,10 @@ function useBalances(chainKey, address, priorityTokenSymbol) {
1117
1119
  if (!priorityTokenSymbol || !chainKey || !assetMatrix) return void 0;
1118
1120
  const normalizedSymbol = normalizeTickerSymbol$1(priorityTokenSymbol);
1119
1121
  const token = assetMatrix[normalizedSymbol]?.[chainKey];
1120
- return token;
1122
+ if (token && token.address && token.address.length > 2) {
1123
+ return token;
1124
+ }
1125
+ return void 0;
1121
1126
  }, [priorityTokenSymbol, chainKey, assetMatrix]);
1122
1127
  const query = reactQuery.useQuery({
1123
1128
  queryKey: ["balances", chainKey, address, priorityTokenSymbol],
@@ -1132,7 +1137,7 @@ function useBalances(chainKey, address, priorityTokenSymbol) {
1132
1137
  priorityToken
1133
1138
  );
1134
1139
  },
1135
- enabled: !!address && !!chainKey && tokensOnChain.length > 0 && isAddressValidForChain(chainKey, address),
1140
+ enabled: !!address && !!chainKey && !!assetMatrix && tokensOnChain.length > 0 && isAddressValidForChain(chainKey, address),
1136
1141
  staleTime: 6e4,
1137
1142
  gcTime: 5 * 6e4,
1138
1143
  refetchOnWindowFocus: false,
@@ -2877,7 +2882,7 @@ const Details = () => {
2877
2882
  })();
2878
2883
  const currentSlippageText = formatPercentage(slippageBps);
2879
2884
  const routeText = quote?.route ? getRouteDisplayName(quote.route) : t(`settings.routePresets.${routePriority}`);
2880
- return /* @__PURE__ */ jsxRuntime.jsx(accordion.Accordion, { type: "single", collapsible: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsxs(accordion.AccordionItem, { value: "item-1", className: "bg-muted rounded-lg", children: [
2885
+ return /* @__PURE__ */ jsxRuntime.jsx(accordion.Accordion, { type: "single", collapsible: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsxs(accordion.AccordionItem, { value: "item-1", className: "bg-muted rounded", children: [
2881
2886
  /* @__PURE__ */ jsxRuntime.jsx(accordion.AccordionTrigger, { className: "w-full gap-1 items-center py-6 px-5 rounded-b-lg data-[state=open]:pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex items-center justify-between", children: [
2882
2887
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-normal text-priority leading-4", children: t("bridge.youWillReceive", { defaultValue: "You will receive" }) }),
2883
2888
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-transparent hover:bg-transparent shadow-none h-4 p-0 px-0 py-0 flex items-center gap-2", children: [
@@ -3229,10 +3234,11 @@ function useBridgeTransaction() {
3229
3234
  dstChainKey: quote.dstChainKey
3230
3235
  };
3231
3236
  console.log(steps);
3232
- const txResult = await strategy.executeSteps(steps, context);
3233
- if (txResult?.hash) {
3234
- txStore.setSrcHash(txResult.hash);
3237
+ const txResult = await strategy.executeSteps(steps, context, (hash) => {
3238
+ txStore.setSrcHash(hash);
3235
3239
  txStore.updateStatus("processing");
3240
+ });
3241
+ if (txResult?.hash) {
3236
3242
  strategy.waitForCompletion(txResult.hash, context).then((result) => {
3237
3243
  if (result.completed) {
3238
3244
  if (result.dstTxHash) {
@@ -5698,7 +5704,7 @@ const TransactionManager = () => {
5698
5704
  return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog, { open: true, onOpenChange: () => {
5699
5705
  }, children: /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogContent, { showCloseButton: false, className: "p-0 gap-0 border-none max-w-[calc(100%-2rem)] sm:max-w-md", children: step }) });
5700
5706
  };
5701
- const useTokensRequest = () => {
5707
+ const useTokens = () => {
5702
5708
  const { setTokens, setSelectedToken, setSelectedAssetSymbol } = useTokensStore();
5703
5709
  const query = reactQuery.useQuery({
5704
5710
  queryKey: ["tokens"],
@@ -5733,7 +5739,7 @@ const useTokensRequest = () => {
5733
5739
  }, [query.isError, query.error]);
5734
5740
  return { ...query };
5735
5741
  };
5736
- const useChainsRequest = () => {
5742
+ const useChains = () => {
5737
5743
  const { setChains, setFromChain } = useChainsStore();
5738
5744
  const query = reactQuery.useQuery({
5739
5745
  queryKey: ["chains"],
@@ -5790,7 +5796,7 @@ class ChainStrategyRegistry {
5790
5796
  async getBalances(chainKey, address, tokens, priorityToken) {
5791
5797
  const strategy = this.getStrategy(chainKey);
5792
5798
  if (!strategy) return {};
5793
- return await strategy.getBalances(address, tokens, chainKey, priorityToken);
5799
+ return await strategy.getBalances(address, tokens, priorityToken);
5794
5800
  }
5795
5801
  isAddressValid(chainKey, address) {
5796
5802
  const strategy = this.getStrategy(chainKey);
@@ -5901,7 +5907,7 @@ function parseTonAddress(address) {
5901
5907
  }
5902
5908
  return ton.Address.parse(address);
5903
5909
  }
5904
- async function getEvmBalances(publicClient, address, tokens, chainKey, priorityToken) {
5910
+ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
5905
5911
  const balances = {};
5906
5912
  try {
5907
5913
  if (!address || !viem.isAddress(address)) {
@@ -5916,51 +5922,49 @@ async function getEvmBalances(publicClient, address, tokens, chainKey, priorityT
5916
5922
  (t) => !isNativeAddress(t.address) && viem.isAddress(t.address)
5917
5923
  );
5918
5924
  if (priorityToken) {
5919
- if (priorityToken.chainKey !== chainKey) {
5920
- console.debug(
5921
- `Skipping priority token ${priorityToken.symbol}: chain mismatch (expected ${chainKey}, got ${priorityToken.chainKey})`
5922
- );
5923
- } else {
5924
- try {
5925
- const isPriorityNative = isNativeAddress(priorityToken.address);
5926
- if (isPriorityNative) {
5927
- const ethBalance = await publicClient.getBalance({
5928
- address
5929
- });
5930
- const balance = parseFloat(
5931
- viem.formatUnits(ethBalance, priorityToken.decimals)
5932
- );
5933
- if (balance > 0) {
5934
- balances[priorityToken.symbol] = { balance, address };
5935
- }
5936
- } else if (viem.isAddress(priorityToken.address)) {
5937
- const tokenBalance = await publicClient.readContract({
5938
- address: priorityToken.address,
5939
- abi: [
5940
- {
5941
- name: "balanceOf",
5942
- type: "function",
5943
- stateMutability: "view",
5944
- inputs: [{ name: "owner", type: "address" }],
5945
- outputs: [{ name: "balance", type: "uint256" }]
5946
- }
5947
- ],
5948
- functionName: "balanceOf",
5949
- args: [address]
5950
- });
5951
- const balance = parseFloat(
5952
- viem.formatUnits(tokenBalance, priorityToken.decimals)
5953
- );
5954
- if (balance > 0) {
5955
- balances[priorityToken.symbol] = { balance, address };
5956
- }
5925
+ try {
5926
+ const isPriorityNative = isNativeAddress(priorityToken.address);
5927
+ console.log(priorityToken);
5928
+ console.log(isPriorityNative);
5929
+ if (isPriorityNative) {
5930
+ const ethBalance = await publicClient.getBalance({
5931
+ address
5932
+ });
5933
+ const balance = parseFloat(
5934
+ viem.formatUnits(ethBalance, priorityToken.decimals)
5935
+ );
5936
+ if (balance > 0) {
5937
+ balances[priorityToken.symbol] = { balance, address };
5957
5938
  }
5958
- } catch (error) {
5959
- console.debug(
5960
- `Failed to get priority token balance for ${priorityToken.symbol}:`,
5961
- error
5939
+ } else if (viem.isAddress(priorityToken.address)) {
5940
+ const tokenBalance = await publicClient.readContract({
5941
+ address: priorityToken.address,
5942
+ abi: [
5943
+ {
5944
+ name: "balanceOf",
5945
+ type: "function",
5946
+ stateMutability: "view",
5947
+ inputs: [{ name: "owner", type: "address" }],
5948
+ outputs: [{ name: "balance", type: "uint256" }]
5949
+ }
5950
+ ],
5951
+ functionName: "balanceOf",
5952
+ args: [address]
5953
+ });
5954
+ console.log(tokenBalance);
5955
+ const balance = parseFloat(
5956
+ viem.formatUnits(tokenBalance, priorityToken.decimals)
5962
5957
  );
5958
+ console.log(balance);
5959
+ if (balance > 0) {
5960
+ balances[priorityToken.symbol] = { balance, address };
5961
+ }
5963
5962
  }
5963
+ } catch (error) {
5964
+ console.debug(
5965
+ `Failed to get priority token balance for ${priorityToken.symbol}:`,
5966
+ error
5967
+ );
5964
5968
  }
5965
5969
  }
5966
5970
  for (const token of nativeTokens) {
@@ -6056,7 +6060,7 @@ async function getEvmBalances(publicClient, address, tokens, chainKey, priorityT
6056
6060
  }
6057
6061
  return balances;
6058
6062
  }
6059
- async function getTonBalances(address, tokens, chainKey, customTonClient, tonApiKey) {
6063
+ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6060
6064
  const balances = {};
6061
6065
  try {
6062
6066
  if (!isTonFriendlyAddress(address)) {
@@ -6215,7 +6219,7 @@ class EvmChainStrategy {
6215
6219
  getConnectLabel(t) {
6216
6220
  return t("wallets.connectEvmWallet");
6217
6221
  }
6218
- async getBalances(address, tokens, chainKey, priorityToken) {
6222
+ async getBalances(address, tokens, priorityToken) {
6219
6223
  if (!this.publicClient) {
6220
6224
  console.warn("No publicClient available for balance query");
6221
6225
  return {};
@@ -6224,7 +6228,6 @@ class EvmChainStrategy {
6224
6228
  this.publicClient,
6225
6229
  address,
6226
6230
  tokens,
6227
- chainKey,
6228
6231
  priorityToken
6229
6232
  );
6230
6233
  }
@@ -6296,7 +6299,7 @@ class EvmChainStrategy {
6296
6299
  throw new InvalidStepsError("evm", "Missing transaction data in steps");
6297
6300
  }
6298
6301
  }
6299
- async executeSteps(steps) {
6302
+ async executeSteps(steps, _context, onFirstHash) {
6300
6303
  if (!this.isConnected() || !this.provider) {
6301
6304
  throw new WalletNotConnectedError("evm");
6302
6305
  }
@@ -6310,11 +6313,17 @@ class EvmChainStrategy {
6310
6313
  if (step.type === "approve") {
6311
6314
  const hash = await this.approveTransaction(step);
6312
6315
  console.log(`Approval transaction hash: ${hash}`);
6313
- if (!firstTxHash) firstTxHash = hash;
6316
+ if (!firstTxHash) {
6317
+ firstTxHash = hash;
6318
+ onFirstHash?.(hash);
6319
+ }
6314
6320
  } else if (step.type === "bridge") {
6315
6321
  const hash = await this.executeTransaction(step);
6316
6322
  console.log(`Bridge transaction hash: ${hash}`);
6317
- if (!firstTxHash) firstTxHash = hash;
6323
+ if (!firstTxHash) {
6324
+ firstTxHash = hash;
6325
+ onFirstHash?.(hash);
6326
+ }
6318
6327
  } else {
6319
6328
  throw new InvalidStepsError(
6320
6329
  "evm",
@@ -6582,11 +6591,10 @@ class TonChainStrategy {
6582
6591
  getConnectLabel(t) {
6583
6592
  return t("wallets.connectTonWallet");
6584
6593
  }
6585
- async getBalances(address, tokens, chainKey) {
6594
+ async getBalances(address, tokens) {
6586
6595
  return await getTonBalances(
6587
6596
  address,
6588
6597
  tokens,
6589
- chainKey,
6590
6598
  this.config.tonClient,
6591
6599
  this.config.tonApiKey
6592
6600
  );
@@ -6650,7 +6658,7 @@ class TonChainStrategy {
6650
6658
  }
6651
6659
  }
6652
6660
  }
6653
- async executeSteps(steps) {
6661
+ async executeSteps(steps, _context, onFirstHash) {
6654
6662
  if (!this.isConnected() || !this.config.tonConnectUI) {
6655
6663
  throw new WalletNotConnectedError("ton");
6656
6664
  }
@@ -6676,9 +6684,11 @@ class TonChainStrategy {
6676
6684
  const result = await this.config.tonConnectUI.sendTransaction(
6677
6685
  transaction2
6678
6686
  );
6687
+ const hash = result.boc;
6688
+ onFirstHash?.(hash);
6679
6689
  return {
6680
6690
  chainKey: "ton",
6681
- hash: result.boc
6691
+ hash
6682
6692
  };
6683
6693
  } catch (error) {
6684
6694
  throw toChainStrategyError(error, "ton", "transaction");
@@ -6887,7 +6897,7 @@ class TronChainStrategy {
6887
6897
  throw new InvalidTransactionDataError("tron", "Missing transaction data");
6888
6898
  }
6889
6899
  }
6890
- async executeSteps(steps) {
6900
+ async executeSteps(steps, _context, onFirstHash) {
6891
6901
  console.log("executeSteps");
6892
6902
  const tronWeb = this.getTronWeb();
6893
6903
  if (!tronWeb) {
@@ -6902,6 +6912,7 @@ class TronChainStrategy {
6902
6912
  throw new WalletNotConnectedError("tron");
6903
6913
  }
6904
6914
  let lastTxId;
6915
+ let isFirstHash = true;
6905
6916
  for (const step of steps) {
6906
6917
  if (String(step.chainKey).toLowerCase() !== "tron") continue;
6907
6918
  const tx = step.transaction;
@@ -6967,6 +6978,10 @@ class TronChainStrategy {
6967
6978
  }
6968
6979
  const { txid } = await this.signAndBroadcast(tronWeb, unsigned);
6969
6980
  lastTxId = txid;
6981
+ if (isFirstHash) {
6982
+ onFirstHash?.(txid);
6983
+ isFirstHash = false;
6984
+ }
6970
6985
  }
6971
6986
  if (!lastTxId) {
6972
6987
  throw new TransactionFailedError(
@@ -7523,8 +7538,8 @@ const EvaaBridgeContent = ({
7523
7538
  onChainChange
7524
7539
  } = {}) => {
7525
7540
  const { t } = useBridgeTranslation();
7526
- useTokensRequest();
7527
- useChainsRequest();
7541
+ useTokens();
7542
+ useChains();
7528
7543
  const swap = useSwapModel();
7529
7544
  const { fromChain, toChain } = swap;
7530
7545
  const { selectedAssetSymbol, assetMatrix } = useTokensStore();