@rash2x/bridge-widget 0.1.19 → 0.1.21

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
@@ -204,13 +204,11 @@ Simply import the styles and you're good to go:
204
204
  import '@evaa/bridge-widget/styles.css';
205
205
  ```
206
206
 
207
- All Tailwind utility classes used by the widget are already included in the compiled CSS.
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
208
 
209
209
  ### Theme Customization
210
210
 
211
- #### Option 1: CSS Variables (Simple)
212
-
213
- Customize colors by overriding CSS variables in your own stylesheet:
211
+ Customize the widget's appearance by overriding CSS variables in your own stylesheet:
214
212
 
215
213
  ```css
216
214
  :root {
@@ -219,7 +217,8 @@ Customize colors by overriding CSS variables in your own stylesheet:
219
217
  --foreground: #171717; /* Text color */
220
218
  --card: #f2f2f2; /* Card background */
221
219
  --border: #00000029; /* Border color */
222
- /* ... see styles.css for all available variables */
220
+ --radius: 0.625rem; /* Border radius */
221
+ /* ... see dist/styles.css for all available variables */
223
222
  }
224
223
 
225
224
  [data-theme="dark"] {
@@ -230,30 +229,13 @@ Customize colors by overriding CSS variables in your own stylesheet:
230
229
  }
231
230
  ```
232
231
 
233
- #### Option 2: Tailwind Integration (Advanced)
234
-
235
- If your project already uses Tailwind CSS and you want full control:
236
-
237
- 1. Add the widget to your Tailwind `content` configuration:
238
-
239
- ```js
240
- // tailwind.config.js
241
- module.exports = {
242
- content: [
243
- './src/**/*.{js,ts,jsx,tsx}',
244
- './node_modules/@evaa/bridge-widget/**/*.{js,mjs}', // Add this line
245
- ],
246
- theme: {
247
- extend: {
248
- // Your custom theme extensions will apply to the widget
249
- },
250
- },
251
- };
252
- ```
253
-
254
- 2. The widget will use your project's Tailwind configuration in addition to its pre-compiled styles.
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
255
237
 
256
- **Note:** The widget will work perfectly fine without Tailwind in your project.
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`.
257
239
 
258
240
  ## Advanced Usage
259
241
 
@@ -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,
@@ -2194,7 +2199,9 @@ const SwapButton = () => {
2194
2199
  };
2195
2200
  const WalletBalance = (props) => {
2196
2201
  const { value, isLoading = false } = props;
2197
- if (isLoading) {
2202
+ const hasNoData = !value || value === "0" || value === "0.00" || value === "0.0";
2203
+ const shouldShowSkeleton = isLoading && hasNoData;
2204
+ if (shouldShowSkeleton) {
2198
2205
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 items-center", children: [
2199
2206
  /* @__PURE__ */ jsxRuntime.jsx(WalletIcon, { className: "text-muted-foreground" }),
2200
2207
  /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-16 rounded-md" })
@@ -2877,7 +2884,7 @@ const Details = () => {
2877
2884
  })();
2878
2885
  const currentSlippageText = formatPercentage(slippageBps);
2879
2886
  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: [
2887
+ 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
2888
  /* @__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
2889
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-normal text-priority leading-4", children: t("bridge.youWillReceive", { defaultValue: "You will receive" }) }),
2883
2890
  /* @__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 +3236,11 @@ function useBridgeTransaction() {
3229
3236
  dstChainKey: quote.dstChainKey
3230
3237
  };
3231
3238
  console.log(steps);
3232
- const txResult = await strategy.executeSteps(steps, context);
3233
- if (txResult?.hash) {
3234
- txStore.setSrcHash(txResult.hash);
3239
+ const txResult = await strategy.executeSteps(steps, context, (hash) => {
3240
+ txStore.setSrcHash(hash);
3235
3241
  txStore.updateStatus("processing");
3242
+ });
3243
+ if (txResult?.hash) {
3236
3244
  strategy.waitForCompletion(txResult.hash, context).then((result) => {
3237
3245
  if (result.completed) {
3238
3246
  if (result.dstTxHash) {
@@ -5698,7 +5706,7 @@ const TransactionManager = () => {
5698
5706
  return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog, { open: true, onOpenChange: () => {
5699
5707
  }, 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
5708
  };
5701
- const useTokensRequest = () => {
5709
+ const useTokens = () => {
5702
5710
  const { setTokens, setSelectedToken, setSelectedAssetSymbol } = useTokensStore();
5703
5711
  const query = reactQuery.useQuery({
5704
5712
  queryKey: ["tokens"],
@@ -5733,7 +5741,7 @@ const useTokensRequest = () => {
5733
5741
  }, [query.isError, query.error]);
5734
5742
  return { ...query };
5735
5743
  };
5736
- const useChainsRequest = () => {
5744
+ const useChains = () => {
5737
5745
  const { setChains, setFromChain } = useChainsStore();
5738
5746
  const query = reactQuery.useQuery({
5739
5747
  queryKey: ["chains"],
@@ -5790,7 +5798,7 @@ class ChainStrategyRegistry {
5790
5798
  async getBalances(chainKey, address, tokens, priorityToken) {
5791
5799
  const strategy = this.getStrategy(chainKey);
5792
5800
  if (!strategy) return {};
5793
- return await strategy.getBalances(address, tokens, chainKey, priorityToken);
5801
+ return await strategy.getBalances(address, tokens, priorityToken);
5794
5802
  }
5795
5803
  isAddressValid(chainKey, address) {
5796
5804
  const strategy = this.getStrategy(chainKey);
@@ -5901,7 +5909,7 @@ function parseTonAddress(address) {
5901
5909
  }
5902
5910
  return ton.Address.parse(address);
5903
5911
  }
5904
- async function getEvmBalances(publicClient, address, tokens, chainKey, priorityToken) {
5912
+ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
5905
5913
  const balances = {};
5906
5914
  try {
5907
5915
  if (!address || !viem.isAddress(address)) {
@@ -5913,49 +5921,47 @@ async function getEvmBalances(publicClient, address, tokens, chainKey, priorityT
5913
5921
  }
5914
5922
  const nativeTokens = tokens.filter((t) => isNativeAddress(t.address));
5915
5923
  const erc20Tokens = tokens.filter(
5916
- (t) => !isNativeAddress(t.address) && viem.isAddress(t.address)
5924
+ (t) => !isNativeAddress(t.address) && viem.isAddress(t.address) && (!priorityToken || t.address !== priorityToken.address)
5917
5925
  );
5918
5926
  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
- }
5927
+ try {
5928
+ const isPriorityNative = isNativeAddress(priorityToken.address);
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) {
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
+ const balance = parseFloat(
5955
+ viem.formatUnits(tokenBalance, priorityToken.decimals)
5956
+ );
5957
+ if (balance > 0) {
5958
+ balances[priorityToken.symbol] = { balance, address };
5959
+ }
5960
+ }
5961
+ } catch (error) {
5962
+ const errorMessage = error instanceof Error ? error.message : String(error);
5963
+ const isZeroDataError = errorMessage.includes('returned no data ("0x")');
5964
+ if (!isZeroDataError) {
5959
5965
  console.debug(
5960
5966
  `Failed to get priority token balance for ${priorityToken.symbol}:`,
5961
5967
  error
@@ -6056,7 +6062,7 @@ async function getEvmBalances(publicClient, address, tokens, chainKey, priorityT
6056
6062
  }
6057
6063
  return balances;
6058
6064
  }
6059
- async function getTonBalances(address, tokens, chainKey, customTonClient, tonApiKey) {
6065
+ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6060
6066
  const balances = {};
6061
6067
  try {
6062
6068
  if (!isTonFriendlyAddress(address)) {
@@ -6215,7 +6221,7 @@ class EvmChainStrategy {
6215
6221
  getConnectLabel(t) {
6216
6222
  return t("wallets.connectEvmWallet");
6217
6223
  }
6218
- async getBalances(address, tokens, chainKey, priorityToken) {
6224
+ async getBalances(address, tokens, priorityToken) {
6219
6225
  if (!this.publicClient) {
6220
6226
  console.warn("No publicClient available for balance query");
6221
6227
  return {};
@@ -6224,7 +6230,6 @@ class EvmChainStrategy {
6224
6230
  this.publicClient,
6225
6231
  address,
6226
6232
  tokens,
6227
- chainKey,
6228
6233
  priorityToken
6229
6234
  );
6230
6235
  }
@@ -6296,7 +6301,7 @@ class EvmChainStrategy {
6296
6301
  throw new InvalidStepsError("evm", "Missing transaction data in steps");
6297
6302
  }
6298
6303
  }
6299
- async executeSteps(steps) {
6304
+ async executeSteps(steps, _context, onFirstHash) {
6300
6305
  if (!this.isConnected() || !this.provider) {
6301
6306
  throw new WalletNotConnectedError("evm");
6302
6307
  }
@@ -6310,11 +6315,17 @@ class EvmChainStrategy {
6310
6315
  if (step.type === "approve") {
6311
6316
  const hash = await this.approveTransaction(step);
6312
6317
  console.log(`Approval transaction hash: ${hash}`);
6313
- if (!firstTxHash) firstTxHash = hash;
6318
+ if (!firstTxHash) {
6319
+ firstTxHash = hash;
6320
+ onFirstHash?.(hash);
6321
+ }
6314
6322
  } else if (step.type === "bridge") {
6315
6323
  const hash = await this.executeTransaction(step);
6316
6324
  console.log(`Bridge transaction hash: ${hash}`);
6317
- if (!firstTxHash) firstTxHash = hash;
6325
+ if (!firstTxHash) {
6326
+ firstTxHash = hash;
6327
+ onFirstHash?.(hash);
6328
+ }
6318
6329
  } else {
6319
6330
  throw new InvalidStepsError(
6320
6331
  "evm",
@@ -6582,11 +6593,10 @@ class TonChainStrategy {
6582
6593
  getConnectLabel(t) {
6583
6594
  return t("wallets.connectTonWallet");
6584
6595
  }
6585
- async getBalances(address, tokens, chainKey) {
6596
+ async getBalances(address, tokens) {
6586
6597
  return await getTonBalances(
6587
6598
  address,
6588
6599
  tokens,
6589
- chainKey,
6590
6600
  this.config.tonClient,
6591
6601
  this.config.tonApiKey
6592
6602
  );
@@ -6650,7 +6660,7 @@ class TonChainStrategy {
6650
6660
  }
6651
6661
  }
6652
6662
  }
6653
- async executeSteps(steps) {
6663
+ async executeSteps(steps, _context, onFirstHash) {
6654
6664
  if (!this.isConnected() || !this.config.tonConnectUI) {
6655
6665
  throw new WalletNotConnectedError("ton");
6656
6666
  }
@@ -6676,9 +6686,11 @@ class TonChainStrategy {
6676
6686
  const result = await this.config.tonConnectUI.sendTransaction(
6677
6687
  transaction2
6678
6688
  );
6689
+ const hash = result.boc;
6690
+ onFirstHash?.(hash);
6679
6691
  return {
6680
6692
  chainKey: "ton",
6681
- hash: result.boc
6693
+ hash
6682
6694
  };
6683
6695
  } catch (error) {
6684
6696
  throw toChainStrategyError(error, "ton", "transaction");
@@ -6887,7 +6899,7 @@ class TronChainStrategy {
6887
6899
  throw new InvalidTransactionDataError("tron", "Missing transaction data");
6888
6900
  }
6889
6901
  }
6890
- async executeSteps(steps) {
6902
+ async executeSteps(steps, _context, onFirstHash) {
6891
6903
  console.log("executeSteps");
6892
6904
  const tronWeb = this.getTronWeb();
6893
6905
  if (!tronWeb) {
@@ -6902,6 +6914,7 @@ class TronChainStrategy {
6902
6914
  throw new WalletNotConnectedError("tron");
6903
6915
  }
6904
6916
  let lastTxId;
6917
+ let isFirstHash = true;
6905
6918
  for (const step of steps) {
6906
6919
  if (String(step.chainKey).toLowerCase() !== "tron") continue;
6907
6920
  const tx = step.transaction;
@@ -6967,6 +6980,10 @@ class TronChainStrategy {
6967
6980
  }
6968
6981
  const { txid } = await this.signAndBroadcast(tronWeb, unsigned);
6969
6982
  lastTxId = txid;
6983
+ if (isFirstHash) {
6984
+ onFirstHash?.(txid);
6985
+ isFirstHash = false;
6986
+ }
6970
6987
  }
6971
6988
  if (!lastTxId) {
6972
6989
  throw new TransactionFailedError(
@@ -7523,8 +7540,8 @@ const EvaaBridgeContent = ({
7523
7540
  onChainChange
7524
7541
  } = {}) => {
7525
7542
  const { t } = useBridgeTranslation();
7526
- useTokensRequest();
7527
- useChainsRequest();
7543
+ useTokens();
7544
+ useChains();
7528
7545
  const swap = useSwapModel();
7529
7546
  const { fromChain, toChain } = swap;
7530
7547
  const { selectedAssetSymbol, assetMatrix } = useTokensStore();