@wheelx-widget/widget 0.1.18 → 0.2.0

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
@@ -8,7 +8,7 @@ An open-source, framework-agnostic React widget for cross-chain token swaps and
8
8
  - 👛 **Built-in Wallet Connection** — Dynamic SDK + Wagmi v2 supporting EVM (MetaMask, OKX, etc.) and Solana (Phantom)
9
9
  - 🎨 **Configurable Theme** — 14 color tokens for custom skinning
10
10
  - ⚛️ **Framework Agnostic** — Works with any React framework (Next.js, Vite, Create React App, etc.)
11
- - 📦 **Tree-shakeable** — ESM + CJS builds with TypeScript declarations
11
+ - 📦 **ESM + CJS** — Dual-format builds with full TypeScript declarations
12
12
  - 🔌 **Configurable Default Tokens** — Set default from/to chains and tokens
13
13
  - 📱 **Deep Link Support** — Wallet app launch support in WebView (React Native) — see [Deep Link Guide](./DEEP_LINK_GUIDE.md)
14
14
 
@@ -22,6 +22,19 @@ Note: `@chakra-ui/react` and `@emotion/react` are required peer dependencies.
22
22
 
23
23
  ## Quick Start
24
24
 
25
+ If you don't have a project yet, scaffold one first:
26
+
27
+ ```bash
28
+ npm create vite@latest my-swap-page -- --template react-ts
29
+ cd my-swap-page
30
+ ```
31
+
32
+ Then install the widget and required peer dependencies:
33
+
34
+ ```bash
35
+ npm install @wheelx-widget/widget @chakra-ui/react @emotion/react
36
+ ```
37
+
25
38
  ```tsx
26
39
  // main.tsx — wrap with ChakraProvider
27
40
  import { ChakraProvider, defaultSystem } from '@chakra-ui/react'
@@ -38,7 +51,7 @@ createRoot(document.getElementById('root')!).render(
38
51
  ```tsx
39
52
  // App.tsx
40
53
  // Import the CSS for animations (required!)
41
- import '@wheelx-widget/widget/dist/index.css'
54
+ import '@wheelx-widget/widget/styles.css'
42
55
  import { WheelXProvider, WheelXWidget } from '@wheelx-widget/widget'
43
56
 
44
57
  function App() {
@@ -106,18 +119,6 @@ Customize 14 visual tokens:
106
119
  </WheelXProvider>
107
120
  ```
108
121
 
109
- ### API Base URL
110
-
111
- Override the default WheelX API endpoint. Useful for testing against a staging or development environment.
112
-
113
- ```tsx
114
- <WheelXProvider config={{
115
- apiBaseUrl: 'https://dev-api.wheelx.fi' // Default: 'https://api.wheelx.fi'
116
- }}>
117
- <WheelXWidget />
118
- </WheelXProvider>
119
- ```
120
-
121
122
  ### Fixed Recipient Address (Different Address)
122
123
 
123
124
  Configure fixed recipient addresses for EVM or Solana chains. When set, the widget will:
@@ -170,9 +171,6 @@ The main trading widget component.
170
171
  interface WidgetConfig {
171
172
  theme?: Partial<WidgetTheme>
172
173
 
173
- /** API base URL. Default 'https://api.wheelx.fi' */
174
- apiBaseUrl?: string
175
-
176
174
  from?: {
177
175
  chains?: number[]
178
176
  defaultChainId?: number
@@ -242,6 +240,16 @@ In short, three things are required:
242
240
  2. Configure `<queries>` declaration in Android's `AndroidManifest.xml`
243
241
  3. Configure `LSApplicationQueriesSchemes` in iOS's `Info.plist`
244
242
 
243
+ ## Troubleshooting
244
+
245
+ | Problem | Symptom | Solution |
246
+ |----------|---------|----------|
247
+ | **Missing ChakraProvider** | White screen or unstyled component | Wrap your app in `<ChakraProvider value={defaultSystem}>` — the widget depends on Chakra's context |
248
+ | **Forgot to import CSS** | Component works but has no styling/animations | Add `import '@wheelx-widget/widget/styles.css'` in your entry file |
249
+ | **Vite dev server starts slow** | `vite dev` takes 30+ seconds | Normal — Vite pre-bundles large wallet dependencies (wagmi, viem, ethers, etc.). Subsequent starts with cache are faster |
250
+ | **Build output is large** | dist/ folder tens of MB, main bundle ~7.5MB (1.9MB gzipped) | Expected — the widget bundles all wallet SDKs. Use code-splitting or lazy-loading in your host app if needed |
251
+ | **React hooks errors** | "Invalid hook call" or context mismatch | You may have duplicate React instances. Ensure `react` and `react-dom` are peer dependencies in your project, and use a single version (18 or 19) |
252
+
245
253
  ## License
246
254
 
247
255
  MIT
package/dist/index.d.mts CHANGED
@@ -36,8 +36,6 @@ interface WidgetTheme {
36
36
  }
37
37
  interface WidgetConfig {
38
38
  theme?: Partial<WidgetTheme>;
39
- /** API base URL. Default 'https://api.wheelx.fi' */
40
- apiBaseUrl?: string;
41
39
  from?: {
42
40
  chains?: number[];
43
41
  defaultChainId?: number;
@@ -74,6 +72,8 @@ interface WidgetConfig {
74
72
  evmDifferentAddress?: string;
75
73
  /** Solana链固定收款异地址(base58格式)。配置后,to网络为Solana链时优先使用此地址 */
76
74
  solanaDifferentAddress?: string;
75
+ /** Tron链固定收款异地址(T地址格式,以T开头)。配置后,to网络为Tron链时优先使用此地址 */
76
+ tronDifferentAddress?: string;
77
77
  /**
78
78
  * 返佣ID(affiliation code)。
79
79
  * 配置后在 quote 请求中优先使用此值;为空时回退到从 URL path 中提取。
@@ -87,7 +87,7 @@ interface WheelXProviderProps {
87
87
  }
88
88
  declare const WheelXProvider: React.FC<WheelXProviderProps>;
89
89
 
90
- interface routesItem {
90
+ interface routesItem$1 {
91
91
  name: string;
92
92
  logo: string;
93
93
  }
@@ -108,7 +108,9 @@ interface TxInfoProps {
108
108
  amountOut: string;
109
109
  fromTokenInUsd?: Fraction;
110
110
  router_type: string | null | undefined;
111
- routes?: routesItem[] | undefined;
111
+ routes?: routesItem$1[] | undefined;
112
+ onToggleAiRouter?: () => void;
113
+ hasMultipleQuotes?: boolean;
112
114
  }
113
115
 
114
116
  interface RefetchQuoteParams {
@@ -128,6 +130,29 @@ interface QuoteRequest {
128
130
  to_platform_id: number;
129
131
  sponsor_gas?: boolean;
130
132
  }
133
+ interface routesItem {
134
+ name: string;
135
+ logo: string;
136
+ }
137
+ interface QuoteItem {
138
+ request_id: string;
139
+ router: string;
140
+ amount_out: string;
141
+ tx: {
142
+ chainId: number;
143
+ data: `0x${string}`;
144
+ to: `0x${string}`;
145
+ value: string;
146
+ gas?: bigint | null;
147
+ maxFeePerGas?: bigint | undefined;
148
+ maxPriorityFeePerGas?: bigint | undefined;
149
+ message?: string;
150
+ sender?: string;
151
+ tx?: string;
152
+ };
153
+ routes: routesItem[];
154
+ gas_fee?: string | null;
155
+ }
131
156
  type QuoteErrorType = 'business_error' | 'http_error' | 'network_error' | 'timeout' | 'unknown_error';
132
157
  interface QuoteMutationError extends Error {
133
158
  httpStatus?: number;
@@ -154,6 +179,7 @@ interface TokenInfo {
154
179
  platform_id?: number;
155
180
  platform_type?: string[];
156
181
  isSolana?: boolean;
182
+ isTron?: boolean;
157
183
  fee_level?: FeeLevel;
158
184
  }
159
185
  interface TokenInfoWithBalance extends TokenInfo {
@@ -199,7 +225,7 @@ interface ChainsAndTokens {
199
225
  };
200
226
  }
201
227
  declare function getChainsAndTokens(): Promise<ChainsAndTokens>;
202
- declare const useChainsAndTokens: (enabled?: boolean) => _tanstack_react_query.UseQueryResult<ChainsAndTokens, Error>;
228
+ declare const useChainsAndTokens: (enabled?: boolean) => _tanstack_react_query.UseQueryResult<NoInfer<ChainsAndTokens>, Error>;
203
229
  declare function mergeTokensWithCompositeKey(arr1: TokenInfoWithBalance[], arr2: TokenInfoWithBalance[]): TokenInfoWithBalance[];
204
230
 
205
231
  type WheelXWidgetProps = {
@@ -221,7 +247,8 @@ interface QuoteInfo {
221
247
  tx_value?: string | null;
222
248
  points?: number | 0 | string;
223
249
  quote_message?: string | null;
224
- routes?: routesItem[];
250
+ routes?: routesItem$1[];
251
+ quotes?: QuoteItem[];
225
252
  solanaTxMessage?: string;
226
253
  solanaTxSender?: string;
227
254
  }
@@ -314,7 +341,7 @@ declare const useRefreshLoading: () => {
314
341
  interface Props {
315
342
  chainId: number;
316
343
  tokenAddress?: `0x${string}`;
317
- connectAddress?: `0x${string}`;
344
+ connectAddress?: string;
318
345
  }
319
346
  interface BalanceResult {
320
347
  decimals: number;
@@ -322,7 +349,7 @@ interface BalanceResult {
322
349
  symbol: string;
323
350
  value: bigint;
324
351
  }
325
- declare const useTokenBalance: ({ chainId, tokenAddress, connectAddress }: Props) => BalanceResult | undefined;
352
+ declare const useTokenBalance: ({ chainId, tokenAddress, connectAddress }: Props) => NoInfer<BalanceResult> | undefined;
326
353
 
327
354
  interface ChainsStore {
328
355
  chains: ChainInfo[] | null;
@@ -354,6 +381,27 @@ declare const useEvmAddress: () => `0x${string}` | undefined;
354
381
  * Used to detect and intercept deep links when the widget runs inside
355
382
  * a WebView (e.g., React Native, Android WebView, WKWebView).
356
383
  */
384
+ declare global {
385
+ interface Window {
386
+ ReactNativeWebView?: {
387
+ postMessage?: (msg: string) => void;
388
+ };
389
+ __wheelx_wallet_callback_url__?: string;
390
+ __walletx_callback_params__?: Record<string, string>;
391
+ __wheelx_trigger_url_update__?: () => void;
392
+ __wheelx_callback_listener_installed?: boolean;
393
+ __wheelx_pending_callback__?: string;
394
+ DynamicLabs?: {
395
+ utils?: {
396
+ PlatformService?: unknown;
397
+ };
398
+ };
399
+ __DYNAMIC_LABS__?: {
400
+ PlatformService?: unknown;
401
+ };
402
+ PlatformService?: unknown;
403
+ }
404
+ }
357
405
  /** Check if running inside a React Native WebView */
358
406
  declare const isReactNativeWebView: () => boolean;
359
407
  /** Check if running in any WebView (Android/iOS) */
@@ -401,11 +449,15 @@ interface WalletStore {
401
449
  setIsEthWalletConnected: (isEthWalletConnected: boolean) => void;
402
450
  isSolanaWalletConnected: boolean;
403
451
  setIsSolanaWalletConnected: (isSolanaWalletConnected: boolean) => void;
452
+ isTronWalletConnected: boolean;
453
+ setIsTronWalletConnected: (isTronWalletConnected: boolean) => void;
404
454
  totalConnectedWallets: number;
405
455
  setTotalConnectedWallets: () => void;
406
456
  totalWallets: number;
407
457
  solanaWalletAddress: string | null;
408
458
  setSolanaWalletAddress: (address: string | null) => void;
459
+ tronWalletAddress: string | null;
460
+ setTronWalletAddress: (address: string | null) => void;
409
461
  evmWalletAddress: string | null;
410
462
  evmWalletConnectorId: string | null;
411
463
  setEvmWalletInfo: (address: string | null, connectorId: string | null) => void;
package/dist/index.d.ts CHANGED
@@ -36,8 +36,6 @@ interface WidgetTheme {
36
36
  }
37
37
  interface WidgetConfig {
38
38
  theme?: Partial<WidgetTheme>;
39
- /** API base URL. Default 'https://api.wheelx.fi' */
40
- apiBaseUrl?: string;
41
39
  from?: {
42
40
  chains?: number[];
43
41
  defaultChainId?: number;
@@ -74,6 +72,8 @@ interface WidgetConfig {
74
72
  evmDifferentAddress?: string;
75
73
  /** Solana链固定收款异地址(base58格式)。配置后,to网络为Solana链时优先使用此地址 */
76
74
  solanaDifferentAddress?: string;
75
+ /** Tron链固定收款异地址(T地址格式,以T开头)。配置后,to网络为Tron链时优先使用此地址 */
76
+ tronDifferentAddress?: string;
77
77
  /**
78
78
  * 返佣ID(affiliation code)。
79
79
  * 配置后在 quote 请求中优先使用此值;为空时回退到从 URL path 中提取。
@@ -87,7 +87,7 @@ interface WheelXProviderProps {
87
87
  }
88
88
  declare const WheelXProvider: React.FC<WheelXProviderProps>;
89
89
 
90
- interface routesItem {
90
+ interface routesItem$1 {
91
91
  name: string;
92
92
  logo: string;
93
93
  }
@@ -108,7 +108,9 @@ interface TxInfoProps {
108
108
  amountOut: string;
109
109
  fromTokenInUsd?: Fraction;
110
110
  router_type: string | null | undefined;
111
- routes?: routesItem[] | undefined;
111
+ routes?: routesItem$1[] | undefined;
112
+ onToggleAiRouter?: () => void;
113
+ hasMultipleQuotes?: boolean;
112
114
  }
113
115
 
114
116
  interface RefetchQuoteParams {
@@ -128,6 +130,29 @@ interface QuoteRequest {
128
130
  to_platform_id: number;
129
131
  sponsor_gas?: boolean;
130
132
  }
133
+ interface routesItem {
134
+ name: string;
135
+ logo: string;
136
+ }
137
+ interface QuoteItem {
138
+ request_id: string;
139
+ router: string;
140
+ amount_out: string;
141
+ tx: {
142
+ chainId: number;
143
+ data: `0x${string}`;
144
+ to: `0x${string}`;
145
+ value: string;
146
+ gas?: bigint | null;
147
+ maxFeePerGas?: bigint | undefined;
148
+ maxPriorityFeePerGas?: bigint | undefined;
149
+ message?: string;
150
+ sender?: string;
151
+ tx?: string;
152
+ };
153
+ routes: routesItem[];
154
+ gas_fee?: string | null;
155
+ }
131
156
  type QuoteErrorType = 'business_error' | 'http_error' | 'network_error' | 'timeout' | 'unknown_error';
132
157
  interface QuoteMutationError extends Error {
133
158
  httpStatus?: number;
@@ -154,6 +179,7 @@ interface TokenInfo {
154
179
  platform_id?: number;
155
180
  platform_type?: string[];
156
181
  isSolana?: boolean;
182
+ isTron?: boolean;
157
183
  fee_level?: FeeLevel;
158
184
  }
159
185
  interface TokenInfoWithBalance extends TokenInfo {
@@ -199,7 +225,7 @@ interface ChainsAndTokens {
199
225
  };
200
226
  }
201
227
  declare function getChainsAndTokens(): Promise<ChainsAndTokens>;
202
- declare const useChainsAndTokens: (enabled?: boolean) => _tanstack_react_query.UseQueryResult<ChainsAndTokens, Error>;
228
+ declare const useChainsAndTokens: (enabled?: boolean) => _tanstack_react_query.UseQueryResult<NoInfer<ChainsAndTokens>, Error>;
203
229
  declare function mergeTokensWithCompositeKey(arr1: TokenInfoWithBalance[], arr2: TokenInfoWithBalance[]): TokenInfoWithBalance[];
204
230
 
205
231
  type WheelXWidgetProps = {
@@ -221,7 +247,8 @@ interface QuoteInfo {
221
247
  tx_value?: string | null;
222
248
  points?: number | 0 | string;
223
249
  quote_message?: string | null;
224
- routes?: routesItem[];
250
+ routes?: routesItem$1[];
251
+ quotes?: QuoteItem[];
225
252
  solanaTxMessage?: string;
226
253
  solanaTxSender?: string;
227
254
  }
@@ -314,7 +341,7 @@ declare const useRefreshLoading: () => {
314
341
  interface Props {
315
342
  chainId: number;
316
343
  tokenAddress?: `0x${string}`;
317
- connectAddress?: `0x${string}`;
344
+ connectAddress?: string;
318
345
  }
319
346
  interface BalanceResult {
320
347
  decimals: number;
@@ -322,7 +349,7 @@ interface BalanceResult {
322
349
  symbol: string;
323
350
  value: bigint;
324
351
  }
325
- declare const useTokenBalance: ({ chainId, tokenAddress, connectAddress }: Props) => BalanceResult | undefined;
352
+ declare const useTokenBalance: ({ chainId, tokenAddress, connectAddress }: Props) => NoInfer<BalanceResult> | undefined;
326
353
 
327
354
  interface ChainsStore {
328
355
  chains: ChainInfo[] | null;
@@ -354,6 +381,27 @@ declare const useEvmAddress: () => `0x${string}` | undefined;
354
381
  * Used to detect and intercept deep links when the widget runs inside
355
382
  * a WebView (e.g., React Native, Android WebView, WKWebView).
356
383
  */
384
+ declare global {
385
+ interface Window {
386
+ ReactNativeWebView?: {
387
+ postMessage?: (msg: string) => void;
388
+ };
389
+ __wheelx_wallet_callback_url__?: string;
390
+ __walletx_callback_params__?: Record<string, string>;
391
+ __wheelx_trigger_url_update__?: () => void;
392
+ __wheelx_callback_listener_installed?: boolean;
393
+ __wheelx_pending_callback__?: string;
394
+ DynamicLabs?: {
395
+ utils?: {
396
+ PlatformService?: unknown;
397
+ };
398
+ };
399
+ __DYNAMIC_LABS__?: {
400
+ PlatformService?: unknown;
401
+ };
402
+ PlatformService?: unknown;
403
+ }
404
+ }
357
405
  /** Check if running inside a React Native WebView */
358
406
  declare const isReactNativeWebView: () => boolean;
359
407
  /** Check if running in any WebView (Android/iOS) */
@@ -401,11 +449,15 @@ interface WalletStore {
401
449
  setIsEthWalletConnected: (isEthWalletConnected: boolean) => void;
402
450
  isSolanaWalletConnected: boolean;
403
451
  setIsSolanaWalletConnected: (isSolanaWalletConnected: boolean) => void;
452
+ isTronWalletConnected: boolean;
453
+ setIsTronWalletConnected: (isTronWalletConnected: boolean) => void;
404
454
  totalConnectedWallets: number;
405
455
  setTotalConnectedWallets: () => void;
406
456
  totalWallets: number;
407
457
  solanaWalletAddress: string | null;
408
458
  setSolanaWalletAddress: (address: string | null) => void;
459
+ tronWalletAddress: string | null;
460
+ setTronWalletAddress: (address: string | null) => void;
409
461
  evmWalletAddress: string | null;
410
462
  evmWalletConnectorId: string | null;
411
463
  setEvmWalletInfo: (address: string | null, connectorId: string | null) => void;