@shapeshiftoss/swap-widget 0.0.2 → 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.
Files changed (158) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +18 -11
  3. package/package.json +77 -28
  4. package/Dockerfile +0 -87
  5. package/dist/assets/PhArrowCircleDown-B305t-Sh.js +0 -14
  6. package/dist/assets/PhArrowClockwise-CJPxQhr_.js +0 -14
  7. package/dist/assets/PhArrowDown-C4hT9BVu.js +0 -14
  8. package/dist/assets/PhArrowLeft-Way4Cu-r.js +0 -14
  9. package/dist/assets/PhArrowRight-Cp5ZME0F.js +0 -14
  10. package/dist/assets/PhArrowSquareOut-NnrK69c5.js +0 -14
  11. package/dist/assets/PhArrowUp-Dph6j8rm.js +0 -14
  12. package/dist/assets/PhArrowUpRight-BpJjRRRh.js +0 -14
  13. package/dist/assets/PhArrowsClockwise-CFUT8X7R.js +0 -14
  14. package/dist/assets/PhArrowsDownUp-BjBI4ckC.js +0 -14
  15. package/dist/assets/PhArrowsLeftRight-CuLpbKRk.js +0 -14
  16. package/dist/assets/PhBank-Dchr4XQJ.js +0 -14
  17. package/dist/assets/PhBrowser-dUu2TrC1.js +0 -14
  18. package/dist/assets/PhCaretDown-78IuKU3V.js +0 -14
  19. package/dist/assets/PhCaretLeft-_aiyH7n1.js +0 -14
  20. package/dist/assets/PhCaretRight-8zJQEuDX.js +0 -14
  21. package/dist/assets/PhCaretUp-CiCxKWwN.js +0 -14
  22. package/dist/assets/PhCheck-CcADx8br.js +0 -14
  23. package/dist/assets/PhCircleHalf-BYzSzd2h.js +0 -14
  24. package/dist/assets/PhClock-UItiXeJq.js +0 -14
  25. package/dist/assets/PhCompass-CUy3uA7t.js +0 -14
  26. package/dist/assets/PhCopy-C-PDgSlZ.js +0 -14
  27. package/dist/assets/PhCreditCard-CWRaUT6F.js +0 -14
  28. package/dist/assets/PhCurrencyDollar-Cqla3AXT.js +0 -14
  29. package/dist/assets/PhDesktop-BBIPrYLl.js +0 -14
  30. package/dist/assets/PhDeviceMobile-BdsPaATg.js +0 -14
  31. package/dist/assets/PhDotsThree-BMXCQl-0.js +0 -14
  32. package/dist/assets/PhEnvelope-yUsis6yU.js +0 -14
  33. package/dist/assets/PhFunnelSimple-Ba7BbWTp.js +0 -14
  34. package/dist/assets/PhGlobe-DgLxBk5U.js +0 -14
  35. package/dist/assets/PhIdentificationCard-Czjmq9Z3.js +0 -14
  36. package/dist/assets/PhImage-BAJ_erz6.js +0 -14
  37. package/dist/assets/PhInfo-Cr4DhVUE.js +0 -14
  38. package/dist/assets/PhLightbulb-BX_7duTr.js +0 -14
  39. package/dist/assets/PhMagnifyingGlass-Mygfryvz.js +0 -14
  40. package/dist/assets/PhPaperPlaneRight-BeuCA660.js +0 -14
  41. package/dist/assets/PhPlus-BMjcHjsT.js +0 -14
  42. package/dist/assets/PhPower-CGffGmdb.js +0 -14
  43. package/dist/assets/PhPuzzlePiece-wm_GpVSi.js +0 -14
  44. package/dist/assets/PhQrCode-DRwRzXCH.js +0 -14
  45. package/dist/assets/PhQuestion-M09j2U0T.js +0 -14
  46. package/dist/assets/PhQuestionMark-BP9EMB6h.js +0 -14
  47. package/dist/assets/PhSealCheck-BfG80yKn.js +0 -14
  48. package/dist/assets/PhSignOut-C5YOWlPT.js +0 -14
  49. package/dist/assets/PhSpinner-BXooDYzU.js +0 -14
  50. package/dist/assets/PhTrash-Biq6rmmL.js +0 -14
  51. package/dist/assets/PhUser-CAgZSpGe.js +0 -14
  52. package/dist/assets/PhVault-l2PHF38a.js +0 -14
  53. package/dist/assets/PhWallet-w25D16It.js +0 -14
  54. package/dist/assets/PhWarning-DPEydIPw.js +0 -14
  55. package/dist/assets/PhWarningCircle-BqjT745H.js +0 -14
  56. package/dist/assets/PhX-s-SmVExa.js +0 -14
  57. package/dist/assets/SwapController-If0bFrNc.js +0 -1
  58. package/dist/assets/ccip-BBB7uCdL.js +0 -1
  59. package/dist/assets/ccip-CkkdfKKI.js +0 -1
  60. package/dist/assets/data-capture-D4gAy-Yc.js +0 -242
  61. package/dist/assets/email-B1AJehis.js +0 -90
  62. package/dist/assets/embedded-wallet-Q6DQopDk.js +0 -410
  63. package/dist/assets/features-B6JAPAFb.js +0 -5
  64. package/dist/assets/index-5jd8RPN9.js +0 -7428
  65. package/dist/assets/index-B4kNtSTk.js +0 -1080
  66. package/dist/assets/index-B753eAob.js +0 -1
  67. package/dist/assets/index-BZoLTv77.js +0 -3
  68. package/dist/assets/index-Bcw9UURX.js +0 -3
  69. package/dist/assets/index-BkrV-ahK.js +0 -2
  70. package/dist/assets/index-CRQzQ_up.js +0 -9
  71. package/dist/assets/index-CSW0Gt5y.js +0 -132
  72. package/dist/assets/index-CZ4jTIsk.js +0 -138
  73. package/dist/assets/index-Cwa8SB3h.js +0 -61
  74. package/dist/assets/index-DEwQgT4r.js +0 -78
  75. package/dist/assets/index-DVfQiQ1d.js +0 -1
  76. package/dist/assets/index-cV3UdaMs.css +0 -1
  77. package/dist/assets/index-hAmu622O.js +0 -43
  78. package/dist/assets/onramp-XcPNCLRU.js +0 -422
  79. package/dist/assets/pay-with-exchange-BeHt4OF4.js +0 -280
  80. package/dist/assets/property-C9JG5tag.js +0 -27
  81. package/dist/assets/receive-7ff4he2S.js +0 -131
  82. package/dist/assets/send-CkMBIRXT.js +0 -554
  83. package/dist/assets/socials-DmmxuLrP.js +0 -250
  84. package/dist/assets/swaps-IHAYRQ0x.js +0 -1050
  85. package/dist/assets/transactions-9Cxdk7o9.js +0 -16
  86. package/dist/assets/v4-BOvFkHkt.js +0 -1
  87. package/dist/assets/w3m-modal-kJzFnBfB.js +0 -891
  88. package/dist/assets/wallet-standard-Dv8LMoUB.js +0 -1
  89. package/dist/favicon.png +0 -0
  90. package/dist/favicon.svg +0 -11
  91. package/dist/icon-192x192.png +0 -0
  92. package/dist/icon-512x512.png +0 -0
  93. package/dist/index.html +0 -33
  94. package/index.html +0 -32
  95. package/public/favicon.png +0 -0
  96. package/public/favicon.svg +0 -11
  97. package/public/icon-192x192.png +0 -0
  98. package/public/icon-512x512.png +0 -0
  99. package/railway.toml +0 -10
  100. package/src/api/client.ts +0 -95
  101. package/src/components/AddressInputModal.css +0 -173
  102. package/src/components/AddressInputModal.tsx +0 -250
  103. package/src/components/ApprovalStep.tsx +0 -92
  104. package/src/components/ExecutionStep.tsx +0 -27
  105. package/src/components/InputStep.tsx +0 -431
  106. package/src/components/QuoteSelector.css +0 -146
  107. package/src/components/QuoteSelector.tsx +0 -137
  108. package/src/components/QuotesModal.css +0 -250
  109. package/src/components/QuotesModal.tsx +0 -182
  110. package/src/components/SettingsModal.css +0 -145
  111. package/src/components/SettingsModal.tsx +0 -180
  112. package/src/components/StatusStep.tsx +0 -139
  113. package/src/components/SwapWidget.css +0 -713
  114. package/src/components/SwapWidget.tsx +0 -607
  115. package/src/components/TokenSelectModal.css +0 -438
  116. package/src/components/TokenSelectModal.tsx +0 -487
  117. package/src/components/WalletProvider.tsx +0 -92
  118. package/src/config/appkit.ts +0 -104
  119. package/src/config/wagmi.ts +0 -27
  120. package/src/constants/chains.ts +0 -72
  121. package/src/constants/defaults.ts +0 -28
  122. package/src/constants/swappers.ts +0 -48
  123. package/src/constants/viemChains.ts +0 -69
  124. package/src/contexts/SwapWalletContext.tsx +0 -25
  125. package/src/demo/App.css +0 -458
  126. package/src/demo/App.tsx +0 -481
  127. package/src/demo/main.tsx +0 -25
  128. package/src/hooks/useAssets.ts +0 -180
  129. package/src/hooks/useBalances.ts +0 -822
  130. package/src/hooks/useBitcoinSigning.ts +0 -276
  131. package/src/hooks/useMarketData.ts +0 -169
  132. package/src/hooks/useSolanaSigning.ts +0 -275
  133. package/src/hooks/useStatusPolling.ts +0 -137
  134. package/src/hooks/useSwapApproval.ts +0 -106
  135. package/src/hooks/useSwapDisplayValues.ts +0 -157
  136. package/src/hooks/useSwapExecution.ts +0 -199
  137. package/src/hooks/useSwapHandlers.ts +0 -119
  138. package/src/hooks/useSwapQuote.ts +0 -71
  139. package/src/hooks/useSwapQuoting.ts +0 -102
  140. package/src/hooks/useSwapRates.ts +0 -61
  141. package/src/index.ts +0 -43
  142. package/src/machines/SwapMachineContext.ts +0 -5
  143. package/src/machines/__tests__/guards.test.ts +0 -228
  144. package/src/machines/__tests__/setup.test.ts +0 -7
  145. package/src/machines/__tests__/swapMachine.test.ts +0 -544
  146. package/src/machines/__tests__/types.test.ts +0 -124
  147. package/src/machines/guards.ts +0 -33
  148. package/src/machines/swapMachine.ts +0 -288
  149. package/src/machines/types.ts +0 -54
  150. package/src/services/transactionStatus.ts +0 -322
  151. package/src/types/index.ts +0 -361
  152. package/src/utils/addressValidation.ts +0 -201
  153. package/src/utils/redirect.ts +0 -45
  154. package/src/vite-env.d.ts +0 -10
  155. package/tsconfig.json +0 -23
  156. package/tsconfig.node.json +0 -10
  157. package/vite.config.ts +0 -101
  158. package/vitest.config.ts +0 -18
package/src/demo/App.tsx DELETED
@@ -1,481 +0,0 @@
1
- import './App.css'
2
-
3
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
4
- import { useCallback, useMemo, useState } from 'react'
5
-
6
- import { SwapWidget } from '../components/SwapWidget'
7
- import type { ThemeConfig } from '../types'
8
-
9
- const PROJECT_ID = 'f58c0242def84c3b9befe9b1e6086bbd'
10
-
11
- const queryClient = new QueryClient()
12
-
13
- type ThemeColors = {
14
- bg: string
15
- card: string
16
- accent: string
17
- borderColor?: string
18
- borderRadius?: string
19
- buttonVariant?: 'filled' | 'outline'
20
- }
21
-
22
- const THEME_PRESETS: {
23
- name: string
24
- dark: ThemeColors
25
- light: ThemeColors
26
- }[] = [
27
- {
28
- name: 'Blue',
29
- dark: { bg: '#0a0a14', card: '#12121c', accent: '#3861fb' },
30
- light: { bg: '#f8f9fc', card: '#ffffff', accent: '#3861fb' },
31
- },
32
- {
33
- name: 'Rose',
34
- dark: { bg: '#140a0f', card: '#1c1218', accent: '#f43f5e' },
35
- light: { bg: '#fef2f4', card: '#ffffff', accent: '#f43f5e' },
36
- },
37
- {
38
- name: 'Purple',
39
- dark: { bg: '#0e0a14', card: '#1a1424', accent: '#a855f7' },
40
- light: { bg: '#faf5ff', card: '#ffffff', accent: '#a855f7' },
41
- },
42
- {
43
- name: 'Cyan',
44
- dark: { bg: '#0a1214', card: '#141d20', accent: '#06b6d4' },
45
- light: { bg: '#f0fdff', card: '#ffffff', accent: '#06b6d4' },
46
- },
47
- {
48
- name: 'Green',
49
- dark: { bg: '#0a140e', card: '#141c18', accent: '#10b981' },
50
- light: { bg: '#f0fdf6', card: '#ffffff', accent: '#10b981' },
51
- },
52
- {
53
- name: 'Orange',
54
- dark: { bg: '#14100a', card: '#1c1814', accent: '#f97316' },
55
- light: { bg: '#fff8f3', card: '#ffffff', accent: '#f97316' },
56
- },
57
- {
58
- name: 'Stucco',
59
- dark: {
60
- bg: '#0d1117',
61
- card: '#0d1117',
62
- accent: '#bea989',
63
- borderColor: '#2a2520',
64
- borderRadius: '6',
65
- buttonVariant: 'outline' as const,
66
- },
67
- light: {
68
- bg: '#f5f3ee',
69
- card: '#f5f3ee',
70
- accent: '#b8941f',
71
- borderColor: '#d4cfc7',
72
- borderRadius: '6',
73
- buttonVariant: 'outline' as const,
74
- },
75
- },
76
- ]
77
-
78
- type DemoContentProps = {
79
- theme: 'light' | 'dark'
80
- setTheme: (theme: 'light' | 'dark') => void
81
- }
82
-
83
- const DemoContent = ({ theme, setTheme }: DemoContentProps) => {
84
- const [showCustomizer, setShowCustomizer] = useState(true)
85
-
86
- const [darkColors, setDarkColors] = useState<ThemeColors>({
87
- bg: '#0a0a14',
88
- card: '#12121c',
89
- accent: '#3861fb',
90
- })
91
-
92
- const [lightColors, setLightColors] = useState<ThemeColors>({
93
- bg: '#f8f9fc',
94
- card: '#ffffff',
95
- accent: '#3861fb',
96
- })
97
-
98
- const currentColors = theme === 'dark' ? darkColors : lightColors
99
- const setCurrentColors = theme === 'dark' ? setDarkColors : setLightColors
100
-
101
- const themeConfig: ThemeConfig = useMemo(
102
- () => ({
103
- mode: theme,
104
- accentColor: currentColors.accent,
105
- backgroundColor: currentColors.bg,
106
- cardColor: currentColors.card,
107
- borderColor: currentColors.borderColor,
108
- borderRadius: currentColors.borderRadius,
109
- buttonVariant: currentColors.buttonVariant,
110
- }),
111
- [theme, currentColors],
112
- )
113
-
114
- const applyPreset = (preset: (typeof THEME_PRESETS)[0]) => {
115
- setDarkColors(preset.dark)
116
- setLightColors(preset.light)
117
- }
118
-
119
- const [copied, setCopied] = useState(false)
120
-
121
- const copyConfig = useCallback(() => {
122
- const formatColors = (colors: ThemeColors, mode: string) => {
123
- const lines = [
124
- ` mode: "${mode}",`,
125
- ` backgroundColor: "${colors.bg}",`,
126
- ` cardColor: "${colors.card}",`,
127
- ` accentColor: "${colors.accent}",`,
128
- ]
129
- if (colors.borderColor) lines.push(` borderColor: "${colors.borderColor}",`)
130
- if (colors.borderRadius) lines.push(` borderRadius: "${colors.borderRadius}",`)
131
- if (colors.buttonVariant) lines.push(` buttonVariant: "${colors.buttonVariant}",`)
132
- return lines.join('\n')
133
- }
134
-
135
- const code = `const themeConfig = {
136
- dark: {
137
- ${formatColors(darkColors, 'dark')}
138
- },
139
- light: {
140
- ${formatColors(lightColors, 'light')}
141
- },
142
- };
143
-
144
- // Usage:
145
- <SwapWidget theme={themeConfig.dark} />
146
- // or
147
- <SwapWidget theme={themeConfig.light} />`
148
-
149
- navigator.clipboard.writeText(code).then(() => {
150
- setCopied(true)
151
- setTimeout(() => setCopied(false), 2000)
152
- })
153
- }, [darkColors, lightColors])
154
-
155
- const handleSwapSuccess = (txHash: string) => {
156
- console.log('Swap successful:', txHash)
157
- }
158
-
159
- const handleSwapError = (error: Error) => {
160
- console.error('Swap failed:', error)
161
- }
162
-
163
- const demoStyle = useMemo(
164
- () =>
165
- ({
166
- '--demo-page-bg': currentColors.bg,
167
- '--demo-page-accent': currentColors.accent,
168
- }) as React.CSSProperties,
169
- [currentColors],
170
- )
171
-
172
- return (
173
- <div className={`demo-app ${theme}`} style={demoStyle}>
174
- <header className='demo-header'>
175
- <a
176
- href='https://shapeshift.com'
177
- className='demo-logo'
178
- target='_blank'
179
- rel='noopener noreferrer'
180
- >
181
- <svg width='28' height='28' viewBox='0 0 57 62' fill='currentColor'>
182
- <path d='M51.67 5.1L48.97 21.3L39.37 10L51.67 5.1ZM49.03 28.27L51.43 37.14L33.06 42.2L49.03 28.27ZM9.03 23.8L18.88 10.93H35.99L46.92 23.8H9.03ZM45.66 26.99L27.85 42.53L9.7 26.99H45.66ZM15.58 10.01L6.78 21.51L4.08 5.17L15.58 10.01ZM22.57 42.2L4.02 37.15L6.56 28.48L22.57 42.2ZM25.99 46.43L22.49 50.28C19.53 47.46 16.26 44.96 12.78 42.83L25.99 46.43ZM42.98 42.77C39.5 44.94 36.24 47.47 33.29 50.32L29.72 46.42L42.98 42.77ZM55.73 0.06L36.42 7.75H18.42L0 0L4.18 25.3L0.17 38.99L10.65 45.26C15.61 48.23 20.06 51.94 23.86 56.3L27.94 60.97L32.23 56.06C35.9 51.84 40.18 48.22 44.95 45.29L55.23 38.99L51.52 25.31L55.73 0.06Z' />
183
- </svg>
184
- <span className='demo-logo-text'>ShapeShift</span>
185
- </a>
186
-
187
- <div className='demo-header-actions'>
188
- <button
189
- className='demo-customize-btn'
190
- onClick={() => setShowCustomizer(!showCustomizer)}
191
- type='button'
192
- >
193
- <svg
194
- width='18'
195
- height='18'
196
- viewBox='0 0 24 24'
197
- fill='none'
198
- stroke='currentColor'
199
- strokeWidth='2'
200
- >
201
- <circle cx='12' cy='12' r='3' />
202
- <path d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z' />
203
- </svg>
204
- Customize
205
- </button>
206
- </div>
207
- </header>
208
-
209
- <main className='demo-main'>
210
- <div className='demo-content'>
211
- <div className='demo-hero'>
212
- <h1 className='demo-title'>Swap Widget</h1>
213
- <p className='demo-subtitle'>
214
- Embeddable multi-chain swap widget powered by ShapeShift
215
- </p>
216
- </div>
217
-
218
- <div className='demo-layout'>
219
- {showCustomizer && (
220
- <div className='demo-customizer'>
221
- <h3 className='demo-customizer-title'>Customize Widget</h3>
222
-
223
- <div className='demo-customizer-section'>
224
- <span className='demo-customizer-label'>Presets</span>
225
- <div className='demo-preset-grid'>
226
- {THEME_PRESETS.map(preset => {
227
- const previewColors = theme === 'dark' ? preset.dark : preset.light
228
- return (
229
- <button
230
- key={preset.name}
231
- className='demo-preset-btn'
232
- onClick={() => applyPreset(preset)}
233
- title={preset.name}
234
- type='button'
235
- >
236
- <div
237
- className='demo-preset-preview'
238
- style={{ background: previewColors.bg }}
239
- >
240
- <div
241
- className='demo-preset-card'
242
- style={{ background: previewColors.card }}
243
- />
244
- <div
245
- className='demo-preset-accent'
246
- style={{ background: previewColors.accent }}
247
- />
248
- </div>
249
- <span className='demo-preset-name'>{preset.name}</span>
250
- </button>
251
- )
252
- })}
253
- </div>
254
- </div>
255
-
256
- <div className='demo-customizer-section'>
257
- <span className='demo-customizer-label'>Theme</span>
258
- <div className='demo-theme-toggle'>
259
- <button
260
- className={`demo-theme-btn ${theme === 'light' ? 'active' : ''}`}
261
- onClick={() => setTheme('light')}
262
- type='button'
263
- >
264
- <svg
265
- width='16'
266
- height='16'
267
- viewBox='0 0 24 24'
268
- fill='none'
269
- stroke='currentColor'
270
- strokeWidth='2'
271
- >
272
- <circle cx='12' cy='12' r='5' />
273
- <path d='M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42' />
274
- </svg>
275
- Light
276
- </button>
277
- <button
278
- className={`demo-theme-btn ${theme === 'dark' ? 'active' : ''}`}
279
- onClick={() => setTheme('dark')}
280
- type='button'
281
- >
282
- <svg
283
- width='16'
284
- height='16'
285
- viewBox='0 0 24 24'
286
- fill='none'
287
- stroke='currentColor'
288
- strokeWidth='2'
289
- >
290
- <path d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z' />
291
- </svg>
292
- Dark
293
- </button>
294
- </div>
295
- </div>
296
-
297
- <div className='demo-customizer-section'>
298
- <span className='demo-customizer-label'>Background Color</span>
299
- <div className='demo-color-input-row'>
300
- <input
301
- type='color'
302
- value={currentColors.bg}
303
- onChange={e => setCurrentColors(c => ({ ...c, bg: e.target.value }))}
304
- className='demo-color-picker'
305
- />
306
- <input
307
- type='text'
308
- value={currentColors.bg}
309
- onChange={e => setCurrentColors(c => ({ ...c, bg: e.target.value }))}
310
- className='demo-color-text'
311
- />
312
- </div>
313
- </div>
314
-
315
- <div className='demo-customizer-section'>
316
- <span className='demo-customizer-label'>Card Color</span>
317
- <div className='demo-color-input-row'>
318
- <input
319
- type='color'
320
- value={currentColors.card}
321
- onChange={e =>
322
- setCurrentColors(c => ({
323
- ...c,
324
- card: e.target.value,
325
- }))
326
- }
327
- className='demo-color-picker'
328
- />
329
- <input
330
- type='text'
331
- value={currentColors.card}
332
- onChange={e =>
333
- setCurrentColors(c => ({
334
- ...c,
335
- card: e.target.value,
336
- }))
337
- }
338
- className='demo-color-text'
339
- />
340
- </div>
341
- </div>
342
-
343
- <div className='demo-customizer-section'>
344
- <span className='demo-customizer-label'>Accent Color</span>
345
- <div className='demo-color-input-row'>
346
- <input
347
- type='color'
348
- value={currentColors.accent}
349
- onChange={e =>
350
- setCurrentColors(c => ({
351
- ...c,
352
- accent: e.target.value,
353
- }))
354
- }
355
- className='demo-color-picker'
356
- />
357
- <input
358
- type='text'
359
- value={currentColors.accent}
360
- onChange={e =>
361
- setCurrentColors(c => ({
362
- ...c,
363
- accent: e.target.value,
364
- }))
365
- }
366
- className='demo-color-text'
367
- />
368
- </div>
369
- </div>
370
-
371
- <div className='demo-customizer-section'>
372
- <span className='demo-customizer-label'>Border Radius</span>
373
- <div className='demo-color-input-row'>
374
- <input
375
- type='range'
376
- min='0'
377
- max='20'
378
- value={currentColors.borderRadius ?? '16'}
379
- onChange={e =>
380
- setCurrentColors(c => ({ ...c, borderRadius: e.target.value }))
381
- }
382
- className='demo-range-input'
383
- />
384
- <input
385
- type='text'
386
- value={`${currentColors.borderRadius ?? '16'}px`}
387
- readOnly
388
- className='demo-color-text'
389
- style={{ width: 60 }}
390
- />
391
- </div>
392
- </div>
393
-
394
- <div className='demo-customizer-section'>
395
- <span className='demo-customizer-label'>Button Style</span>
396
- <div className='demo-theme-toggle'>
397
- <button
398
- className={`demo-theme-btn ${
399
- currentColors.buttonVariant !== 'outline' ? 'active' : ''
400
- }`}
401
- onClick={() => setCurrentColors(c => ({ ...c, buttonVariant: 'filled' }))}
402
- type='button'
403
- >
404
- Filled
405
- </button>
406
- <button
407
- className={`demo-theme-btn ${
408
- currentColors.buttonVariant === 'outline' ? 'active' : ''
409
- }`}
410
- onClick={() => setCurrentColors(c => ({ ...c, buttonVariant: 'outline' }))}
411
- type='button'
412
- >
413
- Outline
414
- </button>
415
- </div>
416
- </div>
417
-
418
- <div className='demo-customizer-section'>
419
- <button className='demo-copy-btn' onClick={copyConfig} type='button'>
420
- {copied ? (
421
- <>
422
- <svg
423
- width='16'
424
- height='16'
425
- viewBox='0 0 24 24'
426
- fill='none'
427
- stroke='currentColor'
428
- strokeWidth='2'
429
- >
430
- <path d='M20 6L9 17l-5-5' />
431
- </svg>
432
- Copied!
433
- </>
434
- ) : (
435
- <>
436
- <svg
437
- width='16'
438
- height='16'
439
- viewBox='0 0 24 24'
440
- fill='none'
441
- stroke='currentColor'
442
- strokeWidth='2'
443
- >
444
- <rect x='9' y='9' width='13' height='13' rx='2' ry='2' />
445
- <path d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1' />
446
- </svg>
447
- Copy Theme Config
448
- </>
449
- )}
450
- </button>
451
- </div>
452
- </div>
453
- )}
454
-
455
- <div className='demo-widget-container'>
456
- <SwapWidget
457
- affiliateAddress='0x0000000000000000000000000000000000000001'
458
- theme={themeConfig}
459
- onSwapSuccess={handleSwapSuccess}
460
- onSwapError={handleSwapError}
461
- showPoweredBy={true}
462
- enableWalletConnection={true}
463
- walletConnectProjectId={PROJECT_ID}
464
- />
465
- </div>
466
- </div>
467
- </div>
468
- </main>
469
- </div>
470
- )
471
- }
472
-
473
- export const App = () => {
474
- const [theme, setTheme] = useState<'light' | 'dark'>('dark')
475
-
476
- return (
477
- <QueryClientProvider client={queryClient}>
478
- <DemoContent theme={theme} setTheme={setTheme} />
479
- </QueryClientProvider>
480
- )
481
- }
package/src/demo/main.tsx DELETED
@@ -1,25 +0,0 @@
1
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2
- import React from 'react'
3
- import ReactDOM from 'react-dom/client'
4
-
5
- import { App } from './App'
6
-
7
- const queryClient = new QueryClient({
8
- defaultOptions: {
9
- queries: {
10
- staleTime: 30_000,
11
- refetchOnWindowFocus: false,
12
- },
13
- },
14
- })
15
-
16
- const rootElement = document.getElementById('root')
17
- if (!rootElement) throw new Error('Root element not found')
18
-
19
- ReactDOM.createRoot(rootElement).render(
20
- <React.StrictMode>
21
- <QueryClientProvider client={queryClient}>
22
- <App />
23
- </QueryClientProvider>
24
- </React.StrictMode>,
25
- )
@@ -1,180 +0,0 @@
1
- import { ASSET_NAMESPACE, fromAssetId } from '@shapeshiftoss/caip'
2
- import { useQuery } from '@tanstack/react-query'
3
-
4
- import type { Asset, AssetId, ChainId } from '../types'
5
-
6
- const SHAPESHIFT_ASSET_CDN = 'https://app.shapeshift.com'
7
- const ASSET_QUERY_STALE_TIME = 5 * 60 * 1000
8
-
9
- type AssetManifest = {
10
- assetData: string
11
- relatedAssetIndex: string
12
- }
13
-
14
- type RawAssetData = {
15
- byId: Record<AssetId, Asset>
16
- ids: AssetId[]
17
- }
18
-
19
- const fetchAssetManifest = async (): Promise<AssetManifest> => {
20
- const response = await fetch(`${SHAPESHIFT_ASSET_CDN}/generated/asset-manifest.json`)
21
- if (!response.ok) {
22
- return { assetData: Date.now().toString(), relatedAssetIndex: '' }
23
- }
24
- return response.json()
25
- }
26
-
27
- const fetchAssetData = async (): Promise<RawAssetData> => {
28
- const manifest = await fetchAssetManifest()
29
- const response = await fetch(
30
- `${SHAPESHIFT_ASSET_CDN}/generated/generatedAssetData.json?v=${manifest.assetData}`,
31
- )
32
-
33
- if (!response.ok) {
34
- throw new Error('Failed to fetch asset data')
35
- }
36
-
37
- return response.json()
38
- }
39
-
40
- export const useAssetData = () => {
41
- return useQuery({
42
- queryKey: ['assetData'],
43
- queryFn: fetchAssetData,
44
- staleTime: ASSET_QUERY_STALE_TIME,
45
- gcTime: 30 * 60 * 1000,
46
- })
47
- }
48
-
49
- export const useAssets = () => {
50
- const { data, ...rest } = useAssetData()
51
-
52
- const assets = data ? data.ids.map(id => data.byId[id]).filter(Boolean) : []
53
-
54
- return { data: assets, ...rest }
55
- }
56
-
57
- export const useAssetsById = () => {
58
- const { data, ...rest } = useAssetData()
59
- return { data: data?.byId ?? {}, ...rest }
60
- }
61
-
62
- export const useAssetById = (assetId: AssetId | undefined) => {
63
- const { data: assetsById, ...rest } = useAssetsById()
64
- return {
65
- data: assetId ? assetsById[assetId] : undefined,
66
- ...rest,
67
- }
68
- }
69
-
70
- export type ChainInfo = {
71
- chainId: ChainId
72
- name: string
73
- icon?: string
74
- color?: string
75
- nativeAsset: Asset
76
- }
77
-
78
- const isNativeAsset = (assetId: string): boolean => {
79
- try {
80
- const { assetNamespace } = fromAssetId(assetId)
81
- return assetNamespace === ASSET_NAMESPACE.slip44
82
- } catch {
83
- return false
84
- }
85
- }
86
-
87
- export const useChains = () => {
88
- const { data: assets, ...rest } = useAssets()
89
-
90
- const chains = (() => {
91
- if (!assets.length) return []
92
-
93
- const chainMap = new Map<ChainId, ChainInfo>()
94
-
95
- for (const asset of assets) {
96
- if (chainMap.has(asset.chainId)) continue
97
-
98
- if (isNativeAsset(asset.assetId)) {
99
- chainMap.set(asset.chainId, {
100
- chainId: asset.chainId,
101
- name: asset.networkName ?? asset.name,
102
- icon: (asset as Asset & { networkIcon?: string }).networkIcon ?? asset.icon,
103
- color: (asset as Asset & { networkColor?: string }).networkColor ?? asset.color,
104
- nativeAsset: asset,
105
- })
106
- }
107
- }
108
-
109
- return Array.from(chainMap.values()).sort((a, b) => a.name.localeCompare(b.name))
110
- })()
111
-
112
- return { data: chains, ...rest }
113
- }
114
-
115
- export const useChainInfo = (chainId: ChainId | undefined) => {
116
- const { data: chains, ...rest } = useChains()
117
- const chainInfo = chainId ? chains.find(c => c.chainId === chainId) : undefined
118
- return { data: chainInfo, ...rest }
119
- }
120
-
121
- export const useAssetsByChainId = (chainId: ChainId | undefined) => {
122
- const { data: assets, ...rest } = useAssets()
123
-
124
- const filteredAssets = chainId ? assets.filter(asset => asset.chainId === chainId) : assets
125
-
126
- return { data: filteredAssets, ...rest }
127
- }
128
-
129
- const scoreAsset = (asset: Asset, query: string): number => {
130
- const lowerQuery = query.toLowerCase()
131
- const symbolLower = asset.symbol.toLowerCase()
132
- const nameLower = asset.name.toLowerCase()
133
-
134
- let score = 0
135
-
136
- if (symbolLower === lowerQuery) score += 1000
137
- else if (symbolLower.startsWith(lowerQuery)) score += 500
138
- else if (symbolLower.includes(lowerQuery)) score += 100
139
-
140
- if (nameLower === lowerQuery) score += 800
141
- else if (nameLower.startsWith(lowerQuery)) score += 300
142
- else if (nameLower.includes(lowerQuery)) score += 50
143
-
144
- if (isNativeAsset(asset.assetId)) score += 200
145
-
146
- return score
147
- }
148
-
149
- export const useAssetSearch = (query: string, chainId?: ChainId) => {
150
- const { data: assets, ...rest } = useAssets()
151
-
152
- const searchResults = (() => {
153
- let filtered = chainId ? assets.filter(a => a.chainId === chainId) : assets
154
-
155
- if (!query.trim()) {
156
- const natives = filtered.filter(a => isNativeAsset(a.assetId))
157
- const others = filtered.filter(a => !isNativeAsset(a.assetId)).slice(0, 50 - natives.length)
158
- return [...natives, ...others]
159
- }
160
-
161
- const lowerQuery = query.toLowerCase()
162
-
163
- const matched = filtered
164
- .filter(asset => {
165
- return (
166
- asset.symbol.toLowerCase().includes(lowerQuery) ||
167
- asset.name.toLowerCase().includes(lowerQuery) ||
168
- asset.assetId.toLowerCase().includes(lowerQuery)
169
- )
170
- })
171
- .map(asset => ({ asset, score: scoreAsset(asset, query) }))
172
- .sort((a, b) => b.score - a.score)
173
- .slice(0, 100)
174
- .map(item => item.asset)
175
-
176
- return matched
177
- })()
178
-
179
- return { data: searchResults, ...rest }
180
- }