@xswap-link/sdk 0.3.5 → 0.4.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 (199) hide show
  1. package/.eslintrc.json +9 -5
  2. package/CHANGELOG.md +10 -0
  3. package/README.md +2 -1
  4. package/dist/index.d.mts +106 -20
  5. package/dist/index.d.ts +106 -20
  6. package/dist/index.global.js +963 -164
  7. package/dist/index.global.js.map +1 -0
  8. package/dist/index.js +105 -3564
  9. package/dist/index.js.map +1 -0
  10. package/dist/index.mjs +105 -3534
  11. package/dist/index.mjs.map +1 -0
  12. package/nodemon.json +1 -1
  13. package/package.json +16 -9
  14. package/postcss.config.js +8 -1
  15. package/src/{components → assets}/icons/ArrowDownIcon.tsx +1 -2
  16. package/src/assets/icons/ArrowDownLongIcon.tsx +12 -0
  17. package/src/{components → assets}/icons/ArrowLeftIcon.tsx +1 -5
  18. package/src/{components → assets}/icons/ArrowRightIcon.tsx +1 -5
  19. package/src/assets/icons/ArrowUpIcon.tsx +12 -0
  20. package/src/{components → assets}/icons/ArrowUpRightIcon.tsx +1 -5
  21. package/src/assets/icons/CashbacklIcon.tsx +28 -0
  22. package/src/{components → assets}/icons/CheckIcon.tsx +1 -5
  23. package/src/assets/icons/ChevronDownIcon.tsx +12 -0
  24. package/src/assets/icons/ChevronUpIcon.tsx +7 -0
  25. package/src/{components → assets}/icons/CircularProgressIcon.tsx +1 -2
  26. package/src/assets/icons/CloseIcon.tsx +15 -0
  27. package/src/{components → assets}/icons/CoinsIcon.tsx +0 -2
  28. package/src/assets/icons/CopyIcon.tsx +15 -0
  29. package/src/assets/icons/DotGreenIcon.tsx +12 -0
  30. package/src/{components → assets}/icons/DownArrorIcon.tsx +0 -2
  31. package/src/{components → assets}/icons/ErrorIcon.tsx +0 -1
  32. package/src/assets/icons/ErrorModalStatusIcon.tsx +31 -0
  33. package/src/assets/icons/HelpIcon.tsx +21 -0
  34. package/src/assets/icons/HistoryGradientBgIcon.tsx +32 -0
  35. package/src/assets/icons/HistoryIcon.tsx +12 -0
  36. package/src/{components → assets}/icons/HourGlassIcon.tsx +1 -5
  37. package/src/assets/icons/Icon.tsx +5 -0
  38. package/src/{components → assets}/icons/InfoIcon.tsx +0 -1
  39. package/src/assets/icons/LinkExternalIcon.tsx +15 -0
  40. package/src/{components → assets}/icons/PercentageIcon.tsx +0 -1
  41. package/src/assets/icons/RankIcon.tsx +28 -0
  42. package/src/assets/icons/SettingsGradientBgIcon.tsx +32 -0
  43. package/src/assets/icons/SettingsIcon.tsx +12 -0
  44. package/src/{components → assets}/icons/SignIcon.tsx +0 -2
  45. package/src/{components → assets}/icons/SuccessIcon.tsx +0 -1
  46. package/src/assets/icons/SuccessModalStatusIcon.tsx +31 -0
  47. package/src/assets/icons/ThumbUpRoundedIcon.tsx +15 -0
  48. package/src/{components → assets}/icons/TimerIcon.tsx +0 -1
  49. package/src/assets/icons/TokensIcon.tsx +16 -0
  50. package/src/assets/icons/WaitingIcon.tsx +15 -0
  51. package/src/{components → assets}/icons/XMarkIcon.tsx +1 -5
  52. package/src/assets/icons/XPowerIcon.tsx +28 -0
  53. package/src/{components → assets}/icons/index.ts +16 -0
  54. package/src/components/Alert/index.tsx +1 -1
  55. package/src/components/Button/index.tsx +57 -0
  56. package/src/components/MessageBar/SnackMessage.tsx +32 -0
  57. package/src/components/MessageBar/index.tsx +44 -0
  58. package/src/components/Modal/index.tsx +52 -0
  59. package/src/components/PoweredBy/index.tsx +12 -0
  60. package/src/components/SafeInput/index.tsx +51 -0
  61. package/src/components/Skeleton/index.tsx +5 -9
  62. package/src/components/Spinner/index.tsx +6 -8
  63. package/src/components/Swap/Header/Controls/index.tsx +57 -0
  64. package/src/components/Swap/Header/index.tsx +16 -0
  65. package/src/components/Swap/HistoryView/index.tsx +34 -0
  66. package/src/components/Swap/SettingsView/Delivery/index.tsx +42 -0
  67. package/src/components/Swap/SettingsView/Slippage/index.tsx +80 -0
  68. package/src/components/Swap/SettingsView/index.tsx +11 -0
  69. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +13 -0
  70. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Header/index.tsx +37 -0
  71. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Steps/index.tsx +145 -0
  72. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/SwapPanel/index.tsx +61 -0
  73. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +291 -0
  74. package/src/components/Swap/SwapView/ConfirmationView/TxResult/TokenItem/index.tsx +24 -0
  75. package/src/components/Swap/SwapView/ConfirmationView/TxResult/index.tsx +84 -0
  76. package/src/components/Swap/SwapView/ConfirmationView/index.tsx +17 -0
  77. package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +25 -0
  78. package/src/components/Swap/SwapView/FeesPanel/Fee/index.tsx +18 -0
  79. package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +71 -0
  80. package/src/components/Swap/SwapView/FeesPanel/index.tsx +67 -0
  81. package/src/components/Swap/SwapView/SwapButton/index.tsx +154 -0
  82. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +23 -0
  83. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +56 -0
  84. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +70 -0
  85. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +62 -0
  86. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +74 -0
  87. package/src/components/Swap/SwapView/SwapPanel/MaxPanel/index.tsx +35 -0
  88. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +40 -0
  89. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +62 -0
  90. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +399 -0
  91. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +104 -0
  92. package/src/components/Swap/SwapView/SwapPanel/index.tsx +42 -0
  93. package/src/components/Swap/SwapView/index.tsx +20 -0
  94. package/src/components/Swap/index.tsx +34 -0
  95. package/src/components/TextInput/index.tsx +67 -0
  96. package/src/components/Timer/index.tsx +57 -0
  97. package/src/components/ToggleButton/index.tsx +24 -0
  98. package/src/components/{UnknownTokenLogo/UnknownTokenLogo.tsx → TokenLogo/Unknown/index.tsx} +3 -4
  99. package/src/components/TokenLogo/WithChain/index.tsx +34 -0
  100. package/src/components/TokenLogo/index.tsx +22 -0
  101. package/src/components/Tooltip/index.tsx +108 -0
  102. package/src/components/TxConfigForm/index.tsx +63 -42
  103. package/src/components/TxDataCard/TokenDetails/index.tsx +30 -0
  104. package/src/components/TxDataCard/TxDataCardUI/index.tsx +133 -0
  105. package/src/components/TxDataCard/index.tsx +30 -0
  106. package/src/components/TxStatusButton/index.tsx +64 -108
  107. package/src/components/global.css +115 -4
  108. package/src/components/index.ts +18 -1
  109. package/src/config/fonts.ts +114 -0
  110. package/src/config/global.d.ts +4 -0
  111. package/src/config/init.tsx +35 -31
  112. package/src/constants/crosschainEstimationTimes.ts +52 -0
  113. package/src/constants/index.ts +8 -0
  114. package/src/context/GlobalDataProvider.tsx +165 -0
  115. package/src/context/HistoryProvider.tsx +339 -0
  116. package/src/context/ModalProvider.tsx +47 -0
  117. package/src/context/SwapProvider.tsx +664 -0
  118. package/src/context/TransactionProvider.tsx +86 -0
  119. package/src/context/TxUIWrapper.tsx +388 -0
  120. package/src/context/index.ts +5 -0
  121. package/src/contracts/abi/CustomXSwapRouter.json +953 -0
  122. package/src/contracts/abi/StakingStableAPR.json +1438 -0
  123. package/src/contracts/abi/XSwapRouter.json +1242 -0
  124. package/src/contracts/abi/XSwapTokenFeeDistributor.json +350 -0
  125. package/src/contracts/abi/index.ts +8 -0
  126. package/src/contracts/addresses.ts +24 -6
  127. package/src/fonts/Satoshi-Black.woff2 +0 -0
  128. package/src/fonts/Satoshi-BlackItalic.woff2 +0 -0
  129. package/src/fonts/Satoshi-Bold.woff2 +0 -0
  130. package/src/fonts/Satoshi-BoldItalic.woff2 +0 -0
  131. package/src/fonts/Satoshi-Light.woff2 +0 -0
  132. package/src/fonts/Satoshi-LightItalic.woff2 +0 -0
  133. package/src/fonts/Satoshi-Medium.woff2 +0 -0
  134. package/src/fonts/Satoshi-MediumItalic.woff2 +0 -0
  135. package/src/fonts/Satoshi-Regular.woff2 +0 -0
  136. package/src/fonts/Satoshi-RegularItalic.woff2 +0 -0
  137. package/src/fonts/Satoshi-Variable.woff2 +0 -0
  138. package/src/fonts/Satoshi-VariableItalic.woff2 +0 -0
  139. package/src/hooks/index.ts +5 -0
  140. package/src/hooks/networkManagement/clientToSigner.tsx +17 -0
  141. package/src/hooks/networkManagement/useNetworks.ts +51 -0
  142. package/src/hooks/useBatchQuery.ts +46 -0
  143. package/src/hooks/useDebounce.tsx +28 -0
  144. package/src/hooks/useEvmContractApi.ts +85 -0
  145. package/src/hooks/usePortal.ts +79 -0
  146. package/src/hooks/useXPower.ts +58 -0
  147. package/src/models/Addresses.ts +8 -2
  148. package/src/models/TokenData.ts +13 -0
  149. package/src/models/TransactionHistory.ts +2 -0
  150. package/src/models/TxUIWrapper.ts +51 -0
  151. package/src/models/XSwapConfig.ts +1 -0
  152. package/src/models/index.ts +1 -0
  153. package/src/models/payloads/GetBalancesPayload.ts +3 -0
  154. package/src/models/payloads/GetFinishedLeaderboardQuestsPayload.ts +3 -0
  155. package/src/models/payloads/GetLeaderboardChangePayload.ts +4 -0
  156. package/src/models/payloads/{GetSwapTxPayload.ts → ModalIntegrationPayload.ts} +3 -1
  157. package/src/models/payloads/index.ts +5 -2
  158. package/src/services/api.ts +34 -5
  159. package/src/services/integrations/monitoring.ts +49 -37
  160. package/src/services/integrations/transactions.ts +50 -6
  161. package/src/utils/contracts.ts +29 -0
  162. package/src/utils/index.ts +3 -3
  163. package/src/utils/numbers.ts +14 -0
  164. package/src/utils/parseWeb3Error.ts +7 -3
  165. package/tailwind.config.js +15 -5
  166. package/tsconfig.json +7 -7
  167. package/tsup.config.ts +61 -0
  168. package/xswap.config.ts +1 -0
  169. package/dist/index.css +0 -1
  170. package/src/components/TxConfigForm/BalanceComponent.tsx +0 -52
  171. package/src/components/TxConfigForm/Button.tsx +0 -20
  172. package/src/components/TxConfigForm/ChainListElement.tsx +0 -36
  173. package/src/components/TxConfigForm/ConfirmationAmount.tsx +0 -91
  174. package/src/components/TxConfigForm/ConfirmationView/ErrorView.tsx +0 -38
  175. package/src/components/TxConfigForm/ConfirmationView/SuccessView.tsx +0 -159
  176. package/src/components/TxConfigForm/ConfirmationView/index.tsx +0 -149
  177. package/src/components/TxConfigForm/ConnectWalletPrompt.tsx +0 -21
  178. package/src/components/TxConfigForm/Description.tsx +0 -17
  179. package/src/components/TxConfigForm/ErrorField.tsx +0 -19
  180. package/src/components/TxConfigForm/FeesDetails.tsx +0 -117
  181. package/src/components/TxConfigForm/Form.tsx +0 -574
  182. package/src/components/TxConfigForm/History.tsx +0 -131
  183. package/src/components/TxConfigForm/HistoryCard.tsx +0 -182
  184. package/src/components/TxConfigForm/PoweredBy.tsx +0 -12
  185. package/src/components/TxConfigForm/Settings.tsx +0 -143
  186. package/src/components/TxConfigForm/Summary.tsx +0 -105
  187. package/src/components/TxConfigForm/SwapPanel.tsx +0 -185
  188. package/src/components/TxConfigForm/TokenPicker.tsx +0 -176
  189. package/src/components/TxConfigForm/TopBar.tsx +0 -58
  190. package/src/components/TxConfigForm/UsdPrice.tsx +0 -44
  191. package/src/components/icons/ChevronDownIcon.tsx +0 -15
  192. package/src/components/icons/ChevronUpIcon.tsx +0 -10
  193. package/src/components/icons/CloseIcon.tsx +0 -15
  194. package/src/components/icons/HistoryIcon.tsx +0 -16
  195. package/src/components/icons/SettingsIcon.tsx +0 -16
  196. /package/src/{components → assets}/icons/ChainlinkCCIPIcon.tsx +0 -0
  197. /package/src/{components → assets}/icons/SearchIcon.tsx +0 -0
  198. /package/src/{components → assets}/icons/XSwapBadgeIcon.tsx +0 -0
  199. /package/src/{components → assets}/icons/XSwapLogo.tsx +0 -0
@@ -0,0 +1,104 @@
1
+ import { ArrowDownIcon } from "@src/assets/icons";
2
+ import { TokenLogo } from "@src/components";
3
+ import { useSwapContext } from "@src/context";
4
+ import { useModal } from "@src/context/ModalProvider";
5
+ import { Chain, Token, TokenOption } from "@src/models";
6
+ import { useMemo, useState } from "react";
7
+ import { SwapPanelType } from "../../index";
8
+ import { TokenPicker } from "./TokenPicker";
9
+
10
+ type Props = {
11
+ chain: Chain | undefined;
12
+ token: Token | undefined;
13
+ type: SwapPanelType;
14
+ };
15
+
16
+ export const TokenPanel = ({ chain, token, type }: Props) => {
17
+ const [open, setOpen] = useState(false);
18
+
19
+ const {
20
+ srcChainTokensOptions,
21
+ srcChainOtherTokensOptions,
22
+ dstChainTokensOptions,
23
+ dstChainOtherTokensOptions,
24
+ setSrcToken,
25
+ setSrcChain,
26
+ supportedChains,
27
+ setDstToken,
28
+ setDstChain,
29
+ } = useSwapContext();
30
+
31
+ const { openModal, closeModal } = useModal();
32
+
33
+ const tokensWithBalances = useMemo(
34
+ () => (type === "source" ? srcChainTokensOptions : dstChainTokensOptions),
35
+ [dstChainTokensOptions, srcChainTokensOptions, type],
36
+ );
37
+
38
+ const otherTokensWithBalances = useMemo(
39
+ () =>
40
+ type === "source"
41
+ ? srcChainOtherTokensOptions
42
+ : dstChainOtherTokensOptions,
43
+ [dstChainOtherTokensOptions, srcChainOtherTokensOptions, type],
44
+ );
45
+
46
+ const onTokenSelect = (token: TokenOption) => {
47
+ const newChain = supportedChains.find(
48
+ (chain) => chain.chainId === token.chainId,
49
+ );
50
+
51
+ if (type === "source") {
52
+ setSrcToken(token);
53
+ setSrcChain(newChain);
54
+ } else {
55
+ setDstToken(token);
56
+ setDstChain(newChain);
57
+ }
58
+ closeModal();
59
+ };
60
+
61
+ const pickerDisabled = useMemo(() => type === "destination", [type]);
62
+
63
+ return (
64
+ <>
65
+ <button
66
+ type="button"
67
+ onClick={() =>
68
+ openModal(
69
+ <TokenPicker
70
+ type={type}
71
+ chain={chain!}
72
+ tokens={tokensWithBalances}
73
+ otherTokens={otherTokensWithBalances}
74
+ selectedTokenAddress={token?.address}
75
+ onSelect={onTokenSelect}
76
+ isOpen={open}
77
+ setModalOpen={setOpen}
78
+ />,
79
+ )
80
+ }
81
+ disabled={pickerDisabled}
82
+ >
83
+ <div className="flex justify-between items-center p-4 gap-8 border-r border-solid border-white border-opacity-10">
84
+ <div className="flex gap-2 items-center">
85
+ <TokenLogo
86
+ token={token}
87
+ className="w-[34px] h-[34px]"
88
+ generatedLogoClassName=" text-[16px]"
89
+ />
90
+ <div className="flex flex-col font-medium items-start">
91
+ <p className="text-xs opacity-60">Token: </p>
92
+ <p className={`${token ? "" : "opacity-60"}`}>
93
+ {token ? token.symbol : "Select"}
94
+ </p>
95
+ </div>
96
+ </div>
97
+ <div className={`w-4 h-2 fill-white ${pickerDisabled && "hidden"}`}>
98
+ <ArrowDownIcon />
99
+ </div>
100
+ </div>
101
+ </button>
102
+ </>
103
+ );
104
+ };
@@ -0,0 +1,42 @@
1
+ import { useMemo } from "react";
2
+ import { useSwapContext } from "@src/context";
3
+ import { SwapPanelType } from "../index";
4
+ import { AmountPanel } from "./AmountPanel";
5
+ import { ChainPanel } from "./ChainPanel";
6
+ import { MaxPanel } from "./MaxPanel";
7
+ import { TokenPanel } from "./TokenPanel";
8
+
9
+ type Props = {
10
+ type: SwapPanelType;
11
+ };
12
+ export const SwapPanel = ({ type }: Props) => {
13
+ const { srcChain, srcToken, dstChain, dstToken } = useSwapContext();
14
+
15
+ const token = useMemo(
16
+ () => (type === "source" ? srcToken : dstToken),
17
+ [type, srcToken, dstToken],
18
+ );
19
+
20
+ const chain = useMemo(
21
+ () => (type === "source" ? srcChain : dstChain),
22
+ [type, srcChain, dstChain],
23
+ );
24
+
25
+ return (
26
+ <div className="flex flex-col x-border rounded-xl bg-x_gray_500">
27
+ <div className="grid grid-cols-2 border-b border-solid border-white border-opacity-10">
28
+ <TokenPanel chain={chain} token={token} type={type} />
29
+ <ChainPanel chain={chain} type={type} />
30
+ </div>
31
+ <div
32
+ className={`flex justify-between ${
33
+ type === "destination" &&
34
+ "bg-gradient-to-r from-x_blue_300_20 to-x_blue_400_20"
35
+ }`}
36
+ >
37
+ <AmountPanel type={type} />
38
+ <MaxPanel type={type} />
39
+ </div>
40
+ </div>
41
+ );
42
+ };
@@ -0,0 +1,20 @@
1
+ import { FeesPanel } from "./FeesPanel";
2
+ import { SwapButton } from "./SwapButton";
3
+ import { SwapPanel } from "./SwapPanel";
4
+ import { ArrowIcon } from "@src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon";
5
+
6
+ export type SwapPanelType = "source" | "destination";
7
+
8
+ export const SwapView = () => {
9
+ return (
10
+ <div className="flex flex-col gap-2 fill-white">
11
+ <div className="relative flex flex-col gap-5">
12
+ <SwapPanel type="source" />
13
+ <ArrowIcon />
14
+ <SwapPanel type="destination" />
15
+ </div>
16
+ <FeesPanel />
17
+ <SwapButton />
18
+ </div>
19
+ );
20
+ };
@@ -0,0 +1,34 @@
1
+ import { useSwapContext } from "@src/context";
2
+ import { Route } from "@src/models";
3
+ import { useMemo } from "react";
4
+ import { Header } from "./Header";
5
+ import { HistoryView } from "./HistoryView";
6
+ import { SettingsView } from "./SettingsView";
7
+ import { SwapView } from "./SwapView";
8
+
9
+ type Props = {
10
+ onSubmit: (route: Route) => void;
11
+ onClose: () => void;
12
+ };
13
+ export const Swap = ({ onClose }: Props) => {
14
+ const { tab } = useSwapContext();
15
+
16
+ const view = useMemo(() => {
17
+ return tab === "Settings" ? (
18
+ <SettingsView />
19
+ ) : tab === "History" ? (
20
+ <HistoryView />
21
+ ) : (
22
+ <SwapView />
23
+ );
24
+ }, [tab]);
25
+
26
+ return (
27
+ <div
28
+ className={`flex flex-col gap-5 p-4 mx-auto text-white bg-x_gray_600 rounded-3xl`}
29
+ >
30
+ <Header onClose={onClose} />
31
+ {view}
32
+ </div>
33
+ );
34
+ };
@@ -0,0 +1,67 @@
1
+ import { HTMLInputTypeAttribute, forwardRef } from "react";
2
+
3
+ interface Props<T = string> {
4
+ inputIcon?: JSX.Element;
5
+ required?: boolean;
6
+ name?: string;
7
+ value: string;
8
+ placeholder?: string;
9
+ type?: HTMLInputTypeAttribute;
10
+ handleChange: (value: T) => void;
11
+ error?: string;
12
+ warning?: string;
13
+ disabled?: boolean;
14
+ className?: string;
15
+ }
16
+
17
+ export const TextInput = forwardRef<HTMLInputElement, Props>((props, ref) => {
18
+ const {
19
+ inputIcon,
20
+ required,
21
+ name,
22
+ value,
23
+ placeholder,
24
+ type,
25
+ handleChange,
26
+ error,
27
+ warning,
28
+ disabled = false,
29
+ className = "",
30
+ } = props;
31
+ return (
32
+ <>
33
+ <div className="flex items-center border border-solid border-white border-opacity-10 rounded-lg py-0 px-3 gap-2 bg-x_gray_500">
34
+ {inputIcon}
35
+ <input
36
+ ref={ref}
37
+ disabled={disabled}
38
+ required={!!required}
39
+ name={name || ""}
40
+ value={value}
41
+ placeholder={placeholder}
42
+ type={type ? type : "text"}
43
+ className={`relative h-10 leading-10 z-[1] outline-none w-full text-white bg-transparent border-none ${
44
+ error
45
+ ? "border border-x_red_500 bg-gradient-to-r from-x_red_500/15 to-x_gray_500/15 px-3 shadow-[0_0_6px_rgba(255,0,0,0.5)]"
46
+ : ""
47
+ } ${
48
+ warning
49
+ ? "border-orange-500 bg-gradient-to-r from-x_orange_500/15 to-x_gray_500/15 px-3 shadow-[0_0_6px_rgba(255,165,0,0.5)]"
50
+ : ""
51
+ } ${className}`}
52
+ onChange={(e) => handleChange(e.target.value)}
53
+ />
54
+ </div>
55
+ {error && (
56
+ <div className="flex justify-between pt-[10px]">
57
+ <div className="px-5 text-x_red_500">{error}</div>
58
+ </div>
59
+ )}
60
+ {warning && (
61
+ <div className="flex justify-between pt-[10px]">
62
+ <div className="px-5 text-x_orange_500">{warning}</div>
63
+ </div>
64
+ )}
65
+ </>
66
+ );
67
+ });
@@ -0,0 +1,57 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useTimer } from "react-timer-hook";
3
+
4
+ export enum TimerDisplayFormat {
5
+ Minutes,
6
+ Hours,
7
+ Days,
8
+ }
9
+
10
+ interface Props {
11
+ expiryTimestamp: Date;
12
+ displayFormat?: TimerDisplayFormat;
13
+ customTextOnExpire?: string;
14
+ }
15
+
16
+ export const Timer = ({
17
+ expiryTimestamp,
18
+ displayFormat = TimerDisplayFormat.Days,
19
+ customTextOnExpire,
20
+ }: Props) => {
21
+ const [expired, setExpired] = useState(
22
+ expiryTimestamp.getTime() < Date.now(),
23
+ );
24
+ const { seconds, minutes, hours, days, restart } = useTimer({
25
+ expiryTimestamp,
26
+ onExpire: () => setExpired(true),
27
+ });
28
+ useEffect(() => {
29
+ restart(expiryTimestamp);
30
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31
+ }, [expiryTimestamp]);
32
+ return (
33
+ <>
34
+ {expired && customTextOnExpire ? (
35
+ <>{customTextOnExpire}</>
36
+ ) : (
37
+ <>
38
+ {displayFormat === TimerDisplayFormat.Minutes && (
39
+ <span>{`${(days * 24 + hours) * 60 + minutes}:${seconds
40
+ .toString()
41
+ .padStart(2, "0")}`}</span>
42
+ )}
43
+ {displayFormat === TimerDisplayFormat.Hours && (
44
+ <span>{`${days * 24 + hours}:${minutes
45
+ .toString()
46
+ .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`}</span>
47
+ )}
48
+ {displayFormat === TimerDisplayFormat.Days && (
49
+ <span>{`${days}:${hours.toString().padStart(2, "0")}:${minutes
50
+ .toString()
51
+ .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`}</span>
52
+ )}
53
+ </>
54
+ )}
55
+ </>
56
+ );
57
+ };
@@ -0,0 +1,24 @@
1
+ type Props = {
2
+ checked: boolean;
3
+ onClick: () => void;
4
+ };
5
+
6
+ const ToggleButton = ({ checked, onClick }: Props) => {
7
+ return (
8
+ <div>
9
+ <span
10
+ className="inline-flex w-14 h-9 p-3 relative align-middle box-border overflow-hidden cursor-pointer"
11
+ onClick={onClick}
12
+ >
13
+ <span className="h-full, w-full rounded-lg bg-[rgba(255,255,255,0.3)]"></span>
14
+ <span
15
+ className={`transition-all w-5 h-5 rounded-full absolute translate-y-[-4px]
16
+ ${checked ? "translate-x-[12px] bg-x_blue" : "bg-white"} `}
17
+ ></span>
18
+ </span>
19
+ </div>
20
+ );
21
+ };
22
+
23
+ ToggleButton.displayName = "ToggleButton";
24
+ export { ToggleButton };
@@ -1,12 +1,11 @@
1
- interface Props {
1
+ type Props = {
2
2
  tokenName: string;
3
3
  className?: string;
4
- }
5
-
4
+ };
6
5
  export const UnknownTokenLogo = ({ tokenName, className }: Props) => {
7
6
  return (
8
7
  <div
9
- className={`xpay-w-5 xpay-h-5 xpay-rounded-full xpay-bg-white xpay-shadow-sm xpay-flex xpay-items-center xpay-justify-center xpay-text-black ${className}`}
8
+ className={`w-5 h-5 rounded-full bg-white shadow-sm flex items-center justify-center text-black ${className}`}
10
9
  >
11
10
  {tokenName.substring(0, 1)}
12
11
  </div>
@@ -0,0 +1,34 @@
1
+ import { TokenLogo } from "@src/components";
2
+ import { Chain, Token } from "@src/models";
3
+
4
+ type Props = {
5
+ token: Partial<Token> | undefined;
6
+ chain: Chain | undefined;
7
+ tokenLogoClassName?: string;
8
+ generatedLogoClassName?: string;
9
+ chainLogoClassName?: string;
10
+ };
11
+ export const TokenLogoWithChain = ({
12
+ token,
13
+ chain,
14
+ tokenLogoClassName,
15
+ generatedLogoClassName,
16
+ chainLogoClassName,
17
+ }: Props) => {
18
+ return (
19
+ <div className="relative flex items-end pr-1 pb-1">
20
+ <TokenLogo
21
+ token={token}
22
+ className={tokenLogoClassName}
23
+ generatedLogoClassName={generatedLogoClassName}
24
+ />
25
+ {chain && (
26
+ <img
27
+ src={chain.image}
28
+ alt={chain.name}
29
+ className={`absolute bottom-0 right-0 border border-solid border-x_gray_600 rounded-3xl ${chainLogoClassName}`}
30
+ />
31
+ )}
32
+ </div>
33
+ );
34
+ };
@@ -0,0 +1,22 @@
1
+ import { UnknownTokenLogo } from "./Unknown";
2
+ import { Token } from "@src/models";
3
+
4
+ type Props = {
5
+ token: Partial<Token> | undefined;
6
+ className?: string;
7
+ generatedLogoClassName?: string;
8
+ };
9
+ export const TokenLogo = ({
10
+ token,
11
+ className,
12
+ generatedLogoClassName,
13
+ }: Props) => {
14
+ return token?.image ? (
15
+ <img src={token.image} alt={token.name} className={className} />
16
+ ) : token ? (
17
+ <UnknownTokenLogo
18
+ tokenName={token.name!}
19
+ className={generatedLogoClassName}
20
+ />
21
+ ) : null;
22
+ };
@@ -0,0 +1,108 @@
1
+ import { xpayShadowRoot } from "@src/config";
2
+ import { FC, RefObject, useEffect, useState } from "react";
3
+ import { createPortal } from "react-dom";
4
+
5
+ type Position = "TOP" | "BOTTOM" | "LEFT" | "RIGHT";
6
+
7
+ const positionToClass: Record<Position, string> = {
8
+ TOP: "-translate-x-1/2 -translate-y-full",
9
+ BOTTOM: "-translate-x-1/2",
10
+ LEFT: "-translate-x-full -translate-y-1/2",
11
+ RIGHT: "-translate-y-1/2",
12
+ };
13
+
14
+ export const Tooltip: FC<{
15
+ id: string;
16
+ position: "TOP" | "BOTTOM" | "LEFT" | "RIGHT";
17
+ text: string;
18
+ triggerRef: RefObject<Element>;
19
+ }> = ({ id, position, text, triggerRef }) => {
20
+ const [positionPx, setPositionPx] = useState({ top: 0, left: 0 });
21
+ const [visible, setVisible] = useState(false);
22
+
23
+ useEffect(() => {
24
+ const trigger = triggerRef.current;
25
+
26
+ const updatePosition = () => {
27
+ if (!trigger) {
28
+ return;
29
+ }
30
+
31
+ const rect = trigger.getBoundingClientRect();
32
+ switch (position) {
33
+ case "TOP": {
34
+ setPositionPx({
35
+ top: rect.top,
36
+ left: rect.left + rect.width / 2,
37
+ });
38
+ break;
39
+ }
40
+ case "BOTTOM": {
41
+ setPositionPx({
42
+ top: rect.top + rect.height,
43
+ left: rect.left + rect.width / 2,
44
+ });
45
+ break;
46
+ }
47
+ case "LEFT": {
48
+ setPositionPx({
49
+ top: rect.top + rect.height / 2,
50
+ left: rect.left,
51
+ });
52
+ break;
53
+ }
54
+ case "RIGHT": {
55
+ setPositionPx({
56
+ top: rect.top + rect.height / 2,
57
+ left: rect.left + rect.width,
58
+ });
59
+ break;
60
+ }
61
+ }
62
+ };
63
+
64
+ const handleMouseEnter = () => {
65
+ updatePosition();
66
+ setVisible(true);
67
+ };
68
+
69
+ const handleMouseLeave = () => {
70
+ setVisible(false);
71
+ };
72
+
73
+ if (trigger) {
74
+ trigger.addEventListener("mouseenter", handleMouseEnter);
75
+ trigger.addEventListener("mouseleave", handleMouseLeave);
76
+ }
77
+
78
+ window.addEventListener("scroll", updatePosition, true);
79
+ window.addEventListener("resize", updatePosition, true);
80
+
81
+ return () => {
82
+ if (trigger) {
83
+ trigger.removeEventListener("mouseenter", handleMouseEnter);
84
+ trigger.removeEventListener("mouseleave", handleMouseLeave);
85
+ }
86
+
87
+ window.removeEventListener("scroll", updatePosition, true);
88
+ window.removeEventListener("resize", updatePosition, true);
89
+ };
90
+ }, [triggerRef, position]);
91
+
92
+ return createPortal(
93
+ visible && (
94
+ <div
95
+ id={id}
96
+ className={`fixed z-50 x-border rounded-xl py-2 px-4 bg-x_gray_500 text-sm max-w-80 ${positionToClass[position]}`}
97
+ style={{
98
+ top: positionPx.top,
99
+ left: positionPx.left,
100
+ }}
101
+ >
102
+ {text}
103
+ </div>
104
+ ),
105
+ xpayShadowRoot!,
106
+ id,
107
+ );
108
+ };