@hongming-wang/usdc-bridge-widget 0.1.1 → 0.2.1

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
@@ -38,7 +38,7 @@ import { mainnet, arbitrum, base, optimism, polygon } from "viem/chains";
38
38
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
39
39
  import { injected } from "wagmi/connectors";
40
40
 
41
- // Create wagmi config
41
+ // Create wagmi config - IMPORTANT: Include transports for ALL chains you want to fetch balances from
42
42
  const config = createConfig({
43
43
  chains: [mainnet, arbitrum, base, optimism, polygon],
44
44
  connectors: [injected()],
@@ -54,16 +54,20 @@ const config = createConfig({
54
54
  const queryClient = new QueryClient();
55
55
 
56
56
  function App() {
57
+ // You need to provide onConnectWallet to handle wallet connection
58
+ const handleConnectWallet = () => {
59
+ // For RainbowKit: use openConnectModal from useConnectModal()
60
+ // For ConnectKit: use open from useModal()
61
+ // For web3modal: use open from useWeb3Modal()
62
+ };
63
+
57
64
  return (
58
65
  <WagmiProvider config={config}>
59
66
  <QueryClientProvider client={queryClient}>
60
- {/* Minimal - uses all 17 CCTP chains by default */}
61
- <BridgeWidget />
62
-
63
- {/* Or with options */}
64
67
  <BridgeWidget
65
68
  defaultSourceChainId={1}
66
69
  defaultDestinationChainId={8453}
70
+ onConnectWallet={handleConnectWallet}
67
71
  onBridgeSuccess={({ txHash, amount }) => {
68
72
  console.log(`Bridged ${amount} USDC: ${txHash}`);
69
73
  }}
@@ -74,6 +78,23 @@ function App() {
74
78
  }
75
79
  ```
76
80
 
81
+ ### RainbowKit Integration
82
+
83
+ ```tsx
84
+ import { useConnectModal } from '@rainbow-me/rainbowkit';
85
+
86
+ function App() {
87
+ const { openConnectModal } = useConnectModal();
88
+
89
+ return (
90
+ <BridgeWidget
91
+ onConnectWallet={openConnectModal}
92
+ // ... other props
93
+ />
94
+ );
95
+ }
96
+ ```
97
+
77
98
  ## Props
78
99
 
79
100
  ### BridgeWidgetProps
@@ -86,8 +107,9 @@ function App() {
86
107
  | `onBridgeStart` | `function` | - | Called when bridge starts |
87
108
  | `onBridgeSuccess` | `function` | - | Called on successful bridge |
88
109
  | `onBridgeError` | `function` | - | Called on bridge error |
89
- | `onConnectWallet` | `function` | - | Called when "Connect Wallet" clicked |
110
+ | `onConnectWallet` | `function` | - | **Recommended.** Called when "Connect Wallet" clicked. Required for wallet connection to work. |
90
111
  | `theme` | `BridgeWidgetTheme` | Default theme | Custom theme overrides |
112
+ | `borderless` | `boolean` | `false` | Remove borders/shadows for seamless integration |
91
113
  | `className` | `string` | - | Custom CSS class |
92
114
  | `style` | `CSSProperties` | - | Custom inline styles |
93
115
 
@@ -169,6 +191,22 @@ const customChainConfig = {
169
191
  />
170
192
  ```
171
193
 
194
+ ## Borderless Mode
195
+
196
+ Use the `borderless` prop for seamless integration into your existing UI. This removes all borders, shadows, and backgrounds from the widget container and its child components:
197
+
198
+ ```tsx
199
+ <BridgeWidget borderless />
200
+
201
+ {/* Or combine with custom styling */}
202
+ <div className="my-custom-container">
203
+ <BridgeWidget
204
+ borderless
205
+ style={{ padding: 0 }}
206
+ />
207
+ </div>
208
+ ```
209
+
172
210
  ## Callbacks
173
211
 
174
212
  ```tsx
package/dist/index.d.mts CHANGED
@@ -121,11 +121,23 @@ interface BridgeWidgetProps {
121
121
  onBridgeError?: (error: Error) => void;
122
122
  /**
123
123
  * Callback fired when the user clicks "Connect Wallet".
124
- * If not provided, the widget will attempt to use wagmi's connectors.
124
+ * Recommended for wallet connection to work. The widget does not auto-connect.
125
+ * If not provided, a warning will be logged in development mode.
126
+ *
127
+ * For RainbowKit: use `openConnectModal` from `useConnectModal()`
128
+ * For ConnectKit: use `open` from `useModal()`
129
+ * For web3modal: use `open` from `useWeb3Modal()`
130
+ *
131
+ * @example
132
+ * // RainbowKit
133
+ * const { openConnectModal } = useConnectModal();
134
+ * <BridgeWidget onConnectWallet={openConnectModal} />
125
135
  */
126
136
  onConnectWallet?: () => void;
127
137
  /** Custom theme overrides to customize the widget appearance */
128
138
  theme?: BridgeWidgetTheme;
139
+ /** Remove all borders from the widget for seamless integration */
140
+ borderless?: boolean;
129
141
  /** Custom CSS class name to apply to the widget container */
130
142
  className?: string;
131
143
  /** Custom inline styles to apply to the widget container */
@@ -160,7 +172,7 @@ interface BridgeResult {
160
172
  error?: string;
161
173
  }
162
174
 
163
- declare function BridgeWidget({ chains, defaultSourceChainId, defaultDestinationChainId, onBridgeStart, onBridgeSuccess, onBridgeError, onConnectWallet, theme: themeOverrides, className, style, }: BridgeWidgetProps): react_jsx_runtime.JSX.Element;
175
+ declare function BridgeWidget({ chains, defaultSourceChainId, defaultDestinationChainId, onBridgeStart, onBridgeSuccess, onBridgeError, onConnectWallet, theme: themeOverrides, borderless, className, style, }: BridgeWidgetProps): react_jsx_runtime.JSX.Element;
164
176
 
165
177
  /**
166
178
  * Hook to get USDC balance for a specific chain
package/dist/index.d.ts CHANGED
@@ -121,11 +121,23 @@ interface BridgeWidgetProps {
121
121
  onBridgeError?: (error: Error) => void;
122
122
  /**
123
123
  * Callback fired when the user clicks "Connect Wallet".
124
- * If not provided, the widget will attempt to use wagmi's connectors.
124
+ * Recommended for wallet connection to work. The widget does not auto-connect.
125
+ * If not provided, a warning will be logged in development mode.
126
+ *
127
+ * For RainbowKit: use `openConnectModal` from `useConnectModal()`
128
+ * For ConnectKit: use `open` from `useModal()`
129
+ * For web3modal: use `open` from `useWeb3Modal()`
130
+ *
131
+ * @example
132
+ * // RainbowKit
133
+ * const { openConnectModal } = useConnectModal();
134
+ * <BridgeWidget onConnectWallet={openConnectModal} />
125
135
  */
126
136
  onConnectWallet?: () => void;
127
137
  /** Custom theme overrides to customize the widget appearance */
128
138
  theme?: BridgeWidgetTheme;
139
+ /** Remove all borders from the widget for seamless integration */
140
+ borderless?: boolean;
129
141
  /** Custom CSS class name to apply to the widget container */
130
142
  className?: string;
131
143
  /** Custom inline styles to apply to the widget container */
@@ -160,7 +172,7 @@ interface BridgeResult {
160
172
  error?: string;
161
173
  }
162
174
 
163
- declare function BridgeWidget({ chains, defaultSourceChainId, defaultDestinationChainId, onBridgeStart, onBridgeSuccess, onBridgeError, onConnectWallet, theme: themeOverrides, className, style, }: BridgeWidgetProps): react_jsx_runtime.JSX.Element;
175
+ declare function BridgeWidget({ chains, defaultSourceChainId, defaultDestinationChainId, onBridgeStart, onBridgeSuccess, onBridgeError, onConnectWallet, theme: themeOverrides, borderless, className, style, }: BridgeWidgetProps): react_jsx_runtime.JSX.Element;
164
176
 
165
177
  /**
166
178
  * Hook to get USDC balance for a specific chain
package/dist/index.js CHANGED
@@ -621,7 +621,7 @@ function useUSDCBalance(chainConfig) {
621
621
  const { address } = (0, import_wagmi2.useAccount)();
622
622
  const {
623
623
  data: balance,
624
- isLoading,
624
+ isLoading: queryLoading,
625
625
  refetch
626
626
  } = (0, import_wagmi2.useReadContract)({
627
627
  address: chainConfig?.usdcAddress,
@@ -632,6 +632,7 @@ function useUSDCBalance(chainConfig) {
632
632
  enabled: !!address && !!chainConfig?.usdcAddress
633
633
  }
634
634
  });
635
+ const isLoading = !!address && queryLoading;
635
636
  return {
636
637
  balance: balance ?? 0n,
637
638
  balanceFormatted: balance ? (0, import_viem2.formatUnits)(balance, USDC_DECIMALS) : "0",
@@ -653,7 +654,7 @@ function useAllUSDCBalances(chainConfigs) {
653
654
  }, [address, chainConfigs]);
654
655
  const {
655
656
  data: results,
656
- isLoading,
657
+ isLoading: queryLoading,
657
658
  refetch
658
659
  } = (0, import_wagmi2.useReadContracts)({
659
660
  contracts,
@@ -661,6 +662,7 @@ function useAllUSDCBalances(chainConfigs) {
661
662
  enabled: !!address && contracts.length > 0
662
663
  }
663
664
  });
665
+ const isLoading = !!address && queryLoading;
664
666
  const balances = (0, import_react2.useMemo)(() => {
665
667
  const balanceMap = {};
666
668
  if (!results) return balanceMap;
@@ -691,7 +693,7 @@ function useUSDCAllowance(chainConfig, spenderAddress) {
691
693
  const effectiveSpender = spenderAddress || chainConfig?.tokenMessengerAddress;
692
694
  const {
693
695
  data: allowance,
694
- isLoading,
696
+ isLoading: queryLoading,
695
697
  refetch
696
698
  } = (0, import_wagmi2.useReadContract)({
697
699
  address: chainConfig?.usdcAddress,
@@ -702,6 +704,7 @@ function useUSDCAllowance(chainConfig, spenderAddress) {
702
704
  enabled: !!address && !!chainConfig?.usdcAddress && !!effectiveSpender
703
705
  }
704
706
  });
707
+ const isLoading = !!address && queryLoading;
705
708
  const { writeContractAsync, isPending: isApproving } = (0, import_wagmi2.useWriteContract)();
706
709
  const [approvalTxHash, setApprovalTxHash] = (0, import_react2.useState)();
707
710
  const [approvalError, setApprovalError] = (0, import_react2.useState)(null);
@@ -1269,12 +1272,40 @@ function WalletIcon({
1269
1272
 
1270
1273
  // src/BridgeWidget.tsx
1271
1274
  var import_jsx_runtime2 = require("react/jsx-runtime");
1275
+ var TYPE_AHEAD_RESET_MS = 1e3;
1276
+ var DROPDOWN_MAX_HEIGHT = 300;
1277
+ var BOX_SHADOW_COLOR = "rgba(0,0,0,0.3)";
1278
+ var DISABLED_BUTTON_BACKGROUND = "rgba(255,255,255,0.1)";
1279
+ function getBorderlessStyles(borderless, theme, options) {
1280
+ const bgColor = options?.useBackgroundColor ? theme.backgroundColor : theme.cardBackgroundColor;
1281
+ return {
1282
+ borderRadius: borderless ? 0 : `${theme.borderRadius}px`,
1283
+ background: borderless ? "transparent" : bgColor,
1284
+ border: borderless ? "none" : `1px solid ${theme.borderColor}`,
1285
+ ...options?.includeBoxShadow && {
1286
+ boxShadow: borderless ? "none" : `0 4px 24px ${BOX_SHADOW_COLOR}`
1287
+ }
1288
+ };
1289
+ }
1290
+ var SPINNER_KEYFRAMES = `@keyframes cc-balance-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`;
1291
+ var KEYFRAMES_ATTR = "data-cc-spinner-keyframes";
1292
+ function injectSpinnerKeyframes() {
1293
+ if (typeof document === "undefined") return;
1294
+ if (document.querySelector(`style[${KEYFRAMES_ATTR}]`)) return;
1295
+ const style = document.createElement("style");
1296
+ style.setAttribute(KEYFRAMES_ATTR, "true");
1297
+ style.textContent = SPINNER_KEYFRAMES;
1298
+ document.head.appendChild(style);
1299
+ }
1272
1300
  function ChainIcon({
1273
1301
  chainConfig,
1274
1302
  theme,
1275
1303
  size = 24
1276
1304
  }) {
1277
1305
  const [hasError, setHasError] = (0, import_react3.useState)(false);
1306
+ (0, import_react3.useEffect)(() => {
1307
+ setHasError(false);
1308
+ }, [chainConfig.iconUrl]);
1278
1309
  if (!chainConfig.iconUrl || hasError) {
1279
1310
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1280
1311
  "div",
@@ -1308,6 +1339,9 @@ function ChainIcon({
1308
1339
  );
1309
1340
  }
1310
1341
  function BalanceSpinner({ size = 12 }) {
1342
+ (0, import_react3.useEffect)(() => {
1343
+ injectSpinnerKeyframes();
1344
+ }, []);
1311
1345
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1312
1346
  "svg",
1313
1347
  {
@@ -1323,7 +1357,6 @@ function BalanceSpinner({ size = 12 }) {
1323
1357
  },
1324
1358
  "aria-hidden": "true",
1325
1359
  children: [
1326
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `@keyframes cc-balance-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }` }),
1327
1360
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: "0.25" }),
1328
1361
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 2a10 10 0 0 1 10 10", strokeLinecap: "round" })
1329
1362
  ]
@@ -1340,7 +1373,8 @@ function ChainSelector({
1340
1373
  id,
1341
1374
  balances,
1342
1375
  isLoadingBalances,
1343
- disabled
1376
+ disabled,
1377
+ borderless
1344
1378
  }) {
1345
1379
  const [isOpen, setIsOpen] = (0, import_react3.useState)(false);
1346
1380
  const [focusedIndex, setFocusedIndex] = (0, import_react3.useState)(-1);
@@ -1348,8 +1382,9 @@ function ChainSelector({
1348
1382
  const typeAheadTimeoutRef = (0, import_react3.useRef)(null);
1349
1383
  const buttonRef = (0, import_react3.useRef)(null);
1350
1384
  const listRef = (0, import_react3.useRef)(null);
1351
- const availableChains = chains.filter(
1352
- (c) => c.chain.id !== excludeChainId
1385
+ const availableChains = (0, import_react3.useMemo)(
1386
+ () => chains.filter((c) => c.chain.id !== excludeChainId),
1387
+ [chains, excludeChainId]
1353
1388
  );
1354
1389
  (0, import_react3.useEffect)(() => {
1355
1390
  return () => {
@@ -1412,7 +1447,7 @@ function ChainSelector({
1412
1447
  }
1413
1448
  typeAheadTimeoutRef.current = setTimeout(() => {
1414
1449
  setTypeAhead("");
1415
- }, 1e3);
1450
+ }, TYPE_AHEAD_RESET_MS);
1416
1451
  const matchIndex = availableChains.findIndex(
1417
1452
  (chain) => chain.chain.name.toLowerCase().startsWith(newTypeAhead)
1418
1453
  );
@@ -1489,9 +1524,7 @@ function ChainSelector({
1489
1524
  alignItems: "center",
1490
1525
  justifyContent: "space-between",
1491
1526
  padding: "10px 12px",
1492
- borderRadius: `${theme.borderRadius}px`,
1493
- background: theme.cardBackgroundColor,
1494
- border: `1px solid ${theme.borderColor}`,
1527
+ ...getBorderlessStyles(borderless, theme),
1495
1528
  cursor: disabled ? "not-allowed" : "pointer",
1496
1529
  opacity: disabled ? 0.6 : 1,
1497
1530
  transition: "all 0.2s"
@@ -1526,7 +1559,7 @@ function ChainSelector({
1526
1559
  " Loading..."
1527
1560
  ]
1528
1561
  }
1529
- ) : selectedBalance ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1562
+ ) : balances && selectedBalance ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1530
1563
  "span",
1531
1564
  {
1532
1565
  style: {
@@ -1584,11 +1617,11 @@ function ChainSelector({
1584
1617
  width: "100%",
1585
1618
  marginTop: "8px",
1586
1619
  borderRadius: `${theme.borderRadius}px`,
1587
- boxShadow: "0 10px 40px rgba(0,0,0,0.3)",
1620
+ boxShadow: `0 10px 40px ${BOX_SHADOW_COLOR}`,
1588
1621
  background: theme.cardBackgroundColor,
1589
1622
  backdropFilter: "blur(10px)",
1590
1623
  border: `1px solid ${theme.borderColor}`,
1591
- maxHeight: "300px",
1624
+ maxHeight: `${DROPDOWN_MAX_HEIGHT}px`,
1592
1625
  overflowY: "auto",
1593
1626
  overflowX: "hidden",
1594
1627
  padding: 0,
@@ -1600,6 +1633,7 @@ function ChainSelector({
1600
1633
  const chainBalance = balances?.[chainConfig.chain.id];
1601
1634
  const isFocused = index === focusedIndex;
1602
1635
  const isSelected = chainConfig.chain.id === selectedChain.chain.id;
1636
+ const hasPositiveBalance = chainBalance ? parseFloat(chainBalance.formatted) > 0 : false;
1603
1637
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1604
1638
  "li",
1605
1639
  {
@@ -1649,28 +1683,19 @@ function ChainSelector({
1649
1683
  },
1650
1684
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BalanceSpinner, { size: 10 })
1651
1685
  }
1652
- ) : chainBalance ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1686
+ ) : balances && chainBalance ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1653
1687
  "span",
1654
1688
  {
1655
1689
  style: {
1656
1690
  fontSize: "10px",
1657
- color: parseFloat(chainBalance.formatted) > 0 ? theme.successColor : theme.mutedTextColor
1691
+ color: hasPositiveBalance ? theme.successColor : theme.mutedTextColor
1658
1692
  },
1659
1693
  children: [
1660
1694
  formatNumber(chainBalance.formatted, 2),
1661
1695
  " USDC"
1662
1696
  ]
1663
1697
  }
1664
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1665
- "span",
1666
- {
1667
- style: {
1668
- fontSize: "10px",
1669
- color: theme.mutedTextColor
1670
- },
1671
- children: "0.00 USDC"
1672
- }
1673
- )
1698
+ ) : null
1674
1699
  ] })
1675
1700
  ]
1676
1701
  },
@@ -1722,7 +1747,9 @@ function AmountInput({
1722
1747
  onMaxClick,
1723
1748
  theme,
1724
1749
  id,
1725
- disabled
1750
+ disabled,
1751
+ showBalance = true,
1752
+ borderless
1726
1753
  }) {
1727
1754
  const inputId = `${id}-input`;
1728
1755
  const labelId = `${id}-label`;
@@ -1768,7 +1795,7 @@ function AmountInput({
1768
1795
  children: "Amount"
1769
1796
  }
1770
1797
  ),
1771
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1798
+ showBalance && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1772
1799
  "span",
1773
1800
  {
1774
1801
  style: { fontSize: "10px", color: theme.mutedTextColor },
@@ -1792,10 +1819,8 @@ function AmountInput({
1792
1819
  style: {
1793
1820
  display: "flex",
1794
1821
  alignItems: "center",
1795
- borderRadius: `${theme.borderRadius}px`,
1796
1822
  overflow: "hidden",
1797
- background: theme.cardBackgroundColor,
1798
- border: `1px solid ${theme.borderColor}`,
1823
+ ...getBorderlessStyles(borderless, theme),
1799
1824
  opacity: disabled ? 0.6 : 1
1800
1825
  },
1801
1826
  children: [
@@ -1922,6 +1947,7 @@ function BridgeWidget({
1922
1947
  onBridgeError,
1923
1948
  onConnectWallet,
1924
1949
  theme: themeOverrides,
1950
+ borderless = false,
1925
1951
  className,
1926
1952
  style
1927
1953
  }) {
@@ -1929,13 +1955,11 @@ function BridgeWidget({
1929
1955
  const { address, isConnected } = (0, import_wagmi3.useAccount)();
1930
1956
  const currentChainId = (0, import_wagmi3.useChainId)();
1931
1957
  const { switchChainAsync } = (0, import_wagmi3.useSwitchChain)();
1932
- const { connect, connectors } = (0, import_wagmi3.useConnect)();
1933
1958
  const [configError, setConfigError] = (0, import_react3.useState)(null);
1934
1959
  (0, import_react3.useEffect)(() => {
1935
1960
  const validation = validateChainConfigs(chains);
1936
1961
  if (!validation.isValid) {
1937
1962
  const errorMsg = validation.errors.join("; ");
1938
- console.error("[BridgeWidget] Invalid chain configuration:", errorMsg);
1939
1963
  setConfigError(errorMsg);
1940
1964
  } else {
1941
1965
  setConfigError(null);
@@ -1962,22 +1986,19 @@ function BridgeWidget({
1962
1986
  const [txHash, setTxHash] = (0, import_react3.useState)();
1963
1987
  const [error, setError] = (0, import_react3.useState)(null);
1964
1988
  const { balances: allBalances, isLoading: isLoadingAllBalances, refetch: refetchAllBalances } = useAllUSDCBalances(chains);
1965
- const { balanceFormatted, refetch: refetchBalance } = useUSDCBalance(
1966
- sourceChainConfig
1967
- );
1989
+ const balanceFormatted = (0, import_react3.useMemo)(() => {
1990
+ return allBalances[sourceChainConfig.chain.id]?.formatted ?? "0";
1991
+ }, [allBalances, sourceChainConfig.chain.id]);
1992
+ const parsedBalance = (0, import_react3.useMemo)(() => parseFloat(balanceFormatted), [balanceFormatted]);
1993
+ const parsedAmount = (0, import_react3.useMemo)(() => parseFloat(amount) || 0, [amount]);
1968
1994
  const { needsApproval, approve, isApproving } = useUSDCAllowance(
1969
1995
  sourceChainConfig
1970
1996
  );
1971
- const refetchBalances = (0, import_react3.useCallback)(() => {
1972
- refetchBalance();
1973
- refetchAllBalances();
1974
- }, [refetchBalance, refetchAllBalances]);
1975
1997
  (0, import_react3.useEffect)(() => {
1976
1998
  if (address) {
1977
1999
  refetchAllBalances();
1978
- refetchBalance();
1979
2000
  }
1980
- }, [address, refetchAllBalances, refetchBalance]);
2001
+ }, [address, refetchAllBalances]);
1981
2002
  const { bridge: executeBridge, state: bridgeState, reset: resetBridge } = useBridge();
1982
2003
  const { isLoading: isConfirming, isSuccess } = (0, import_wagmi3.useWaitForTransactionReceipt)({
1983
2004
  hash: txHash
@@ -1990,11 +2011,11 @@ function BridgeWidget({
1990
2011
  onBridgeErrorRef.current = onBridgeError;
1991
2012
  const needsChainSwitch = isConnected && currentChainId !== sourceChainConfig.chain.id;
1992
2013
  const handleSwapChains = (0, import_react3.useCallback)(() => {
1993
- setSourceChainConfig((prev) => {
1994
- setDestChainConfig(prev);
1995
- return destChainConfig;
1996
- });
1997
- }, [destChainConfig]);
2014
+ const newSource = destChainConfig;
2015
+ const newDest = sourceChainConfig;
2016
+ setSourceChainConfig(newSource);
2017
+ setDestChainConfig(newDest);
2018
+ }, [destChainConfig, sourceChainConfig]);
1998
2019
  const handleMaxClick = (0, import_react3.useCallback)(() => {
1999
2020
  setAmount(balanceFormatted);
2000
2021
  }, [balanceFormatted]);
@@ -2006,7 +2027,7 @@ function BridgeWidget({
2006
2027
  }
2007
2028
  }, [switchChainAsync, sourceChainConfig.chain.id]);
2008
2029
  const handleBridge = (0, import_react3.useCallback)(async () => {
2009
- if (!address || !amount || parseFloat(amount) <= 0) return;
2030
+ if (!address || !amount || parsedAmount <= 0) return;
2010
2031
  setError(null);
2011
2032
  resetBridge();
2012
2033
  try {
@@ -2040,6 +2061,7 @@ function BridgeWidget({
2040
2061
  }, [
2041
2062
  address,
2042
2063
  amount,
2064
+ parsedAmount,
2043
2065
  needsApproval,
2044
2066
  approve,
2045
2067
  executeBridge,
@@ -2070,7 +2092,7 @@ function BridgeWidget({
2070
2092
  const currentDestChainId = destChainConfig.chain.id;
2071
2093
  const currentTxHash = bridgeState.txHash;
2072
2094
  setAmount("");
2073
- refetchBalances();
2095
+ refetchAllBalances();
2074
2096
  if (currentTxHash) {
2075
2097
  onBridgeSuccessRef.current?.({
2076
2098
  sourceChainId: currentSourceChainId,
@@ -2086,14 +2108,14 @@ function BridgeWidget({
2086
2108
  bridgeState.status,
2087
2109
  bridgeState.txHash,
2088
2110
  bridgeState.error,
2089
- refetchBalances,
2111
+ refetchAllBalances,
2090
2112
  amount,
2091
2113
  sourceChainConfig.chain.id,
2092
2114
  destChainConfig.chain.id
2093
2115
  ]);
2094
- const isButtonDisabled = !isConnected || needsChainSwitch || !amount || parseFloat(amount) <= 0 || parseFloat(amount) > parseFloat(balanceFormatted) || isConfirming || isApproving || isBridging;
2116
+ const isButtonDisabled = !isConnected || needsChainSwitch || !amount || parsedAmount <= 0 || parsedAmount > parsedBalance || isConfirming || isApproving || isBridging;
2095
2117
  const isButtonActuallyDisabled = isButtonDisabled && !needsChainSwitch && isConnected;
2096
- const getButtonText = (0, import_react3.useCallback)(() => {
2118
+ const buttonText = (0, import_react3.useMemo)(() => {
2097
2119
  if (!isConnected) return "Connect Wallet";
2098
2120
  if (needsChainSwitch) return `Switch to ${sourceChainConfig.chain.name}`;
2099
2121
  if (bridgeState.status === "loading") return "Preparing Bridge...";
@@ -2104,8 +2126,8 @@ function BridgeWidget({
2104
2126
  if (isConfirming || isApproving) {
2105
2127
  return "Approving...";
2106
2128
  }
2107
- if (!amount || parseFloat(amount) <= 0) return "Enter Amount";
2108
- if (parseFloat(amount) > parseFloat(balanceFormatted)) {
2129
+ if (!amount || parsedAmount <= 0) return "Enter Amount";
2130
+ if (parsedAmount > parsedBalance) {
2109
2131
  return "Insufficient Balance";
2110
2132
  }
2111
2133
  if (needsApproval(amount)) return "Approve & Bridge USDC";
@@ -2118,18 +2140,18 @@ function BridgeWidget({
2118
2140
  isConfirming,
2119
2141
  isApproving,
2120
2142
  amount,
2121
- balanceFormatted,
2143
+ parsedAmount,
2144
+ parsedBalance,
2122
2145
  needsApproval
2123
2146
  ]);
2124
2147
  const handleButtonClick = (0, import_react3.useCallback)(() => {
2125
2148
  if (!isConnected) {
2126
2149
  if (onConnectWallet) {
2127
2150
  onConnectWallet();
2128
- } else if (connectors.length > 0) {
2129
- const injectedConnector = connectors.find(
2130
- (c) => c.type === "injected"
2151
+ } else {
2152
+ console.warn(
2153
+ "[BridgeWidget] onConnectWallet prop is not provided. Please provide onConnectWallet to handle wallet connection (e.g., openConnectModal from RainbowKit)."
2131
2154
  );
2132
- connect({ connector: injectedConnector || connectors[0] });
2133
2155
  }
2134
2156
  return;
2135
2157
  }
@@ -2141,8 +2163,6 @@ function BridgeWidget({
2141
2163
  }, [
2142
2164
  isConnected,
2143
2165
  onConnectWallet,
2144
- connectors,
2145
- connect,
2146
2166
  needsChainSwitch,
2147
2167
  handleSwitchChain,
2148
2168
  handleBridge
@@ -2158,7 +2178,7 @@ function BridgeWidget({
2158
2178
  cursor: isButtonActuallyDisabled ? "not-allowed" : "pointer",
2159
2179
  transition: "all 0.2s",
2160
2180
  color: isButtonActuallyDisabled ? theme.mutedTextColor : theme.textColor,
2161
- background: isButtonActuallyDisabled ? "rgba(255,255,255,0.1)" : `linear-gradient(135deg, ${theme.primaryColor} 0%, ${theme.secondaryColor} 100%)`,
2181
+ background: isButtonActuallyDisabled ? DISABLED_BUTTON_BACKGROUND : `linear-gradient(135deg, ${theme.primaryColor} 0%, ${theme.secondaryColor} 100%)`,
2162
2182
  boxShadow: isButtonActuallyDisabled ? "none" : `0 4px 14px ${theme.primaryColor}60, inset 0 1px 0 rgba(255,255,255,0.2)`
2163
2183
  }),
2164
2184
  [
@@ -2180,11 +2200,11 @@ function BridgeWidget({
2180
2200
  fontFamily: theme.fontFamily,
2181
2201
  maxWidth: "480px",
2182
2202
  width: "100%",
2183
- borderRadius: `${theme.borderRadius}px`,
2184
2203
  padding: "16px",
2185
- background: theme.backgroundColor,
2186
- border: `1px solid ${theme.borderColor}`,
2187
- boxShadow: "0 4px 24px rgba(0,0,0,0.3)",
2204
+ ...getBorderlessStyles(borderless, theme, {
2205
+ includeBoxShadow: true,
2206
+ useBackgroundColor: true
2207
+ }),
2188
2208
  ...style
2189
2209
  },
2190
2210
  children: [
@@ -2208,9 +2228,10 @@ function BridgeWidget({
2208
2228
  onSelect: setSourceChainConfig,
2209
2229
  excludeChainId: destChainConfig.chain.id,
2210
2230
  theme,
2211
- balances: allBalances,
2212
- isLoadingBalances: isLoadingAllBalances,
2213
- disabled: isOperationPending
2231
+ balances: isConnected ? allBalances : void 0,
2232
+ isLoadingBalances: isConnected && isLoadingAllBalances,
2233
+ disabled: isOperationPending,
2234
+ borderless
2214
2235
  }
2215
2236
  ),
2216
2237
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SwapButton, { onClick: handleSwapChains, theme, disabled: isOperationPending }),
@@ -2224,9 +2245,10 @@ function BridgeWidget({
2224
2245
  onSelect: setDestChainConfig,
2225
2246
  excludeChainId: sourceChainConfig.chain.id,
2226
2247
  theme,
2227
- balances: allBalances,
2228
- isLoadingBalances: isLoadingAllBalances,
2229
- disabled: isOperationPending
2248
+ balances: isConnected ? allBalances : void 0,
2249
+ isLoadingBalances: isConnected && isLoadingAllBalances,
2250
+ disabled: isOperationPending,
2251
+ borderless
2230
2252
  }
2231
2253
  )
2232
2254
  ]
@@ -2241,7 +2263,9 @@ function BridgeWidget({
2241
2263
  balance: balanceFormatted,
2242
2264
  onMaxClick: handleMaxClick,
2243
2265
  theme,
2244
- disabled: isOperationPending
2266
+ disabled: isOperationPending,
2267
+ showBalance: isConnected,
2268
+ borderless
2245
2269
  }
2246
2270
  ) }),
2247
2271
  configError && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
@@ -2284,7 +2308,7 @@ function BridgeWidget({
2284
2308
  disabled: isButtonActuallyDisabled,
2285
2309
  "aria-busy": isConfirming || isApproving || isBridging,
2286
2310
  style: buttonStyles,
2287
- children: getButtonText()
2311
+ children: buttonText
2288
2312
  }
2289
2313
  )
2290
2314
  ]