@0xsquid/deposit-widget 0.1.0 → 0.1.1-beta.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/dist/types/DepositWidget.d.ts +1 -0
- package/dist/types/components/ViewTransition.d.ts +1 -0
- package/dist/types/components/shared/buttons/button.d.ts +1 -0
- package/dist/types/components/shared/icons/types.d.ts +1 -0
- package/dist/types/components/shared/icons/user-round.d.ts +1 -0
- package/dist/types/components/shared/navigation/base-navbar.d.ts +1 -0
- package/dist/types/components/shared/navigation/sub-navbar.d.ts +1 -0
- package/dist/types/components/token-badge-icon.d.ts +1 -0
- package/dist/types/components/token-list-item.d.ts +1 -0
- package/dist/types/components/view-container.d.ts +1 -0
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/hooks/ui/useMainCTAButtonState.d.ts +1 -0
- package/dist/types/hooks/use-auto-select-token.d.ts +1 -0
- package/dist/types/hooks/use-deposit-route.d.ts +1 -0
- package/dist/types/hooks/use-token-selection.d.ts +1 -0
- package/dist/types/hooks/use-transaction-history.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/services/assets-service.d.ts +1 -0
- package/dist/types/services/wallet-history/format.d.ts +1 -0
- package/dist/types/services/wallet-history/format.test.d.ts +1 -0
- package/dist/types/services/wallet-history/get-main-explorer-url.d.ts +1 -0
- package/dist/types/services/wallet-history/get-wallet-history.d.ts +1 -0
- package/dist/types/services/wallet-history/types.d.ts +1 -0
- package/dist/types/services/wallet-history/validation.d.ts +1 -0
- package/dist/types/store/use-deposit-store.d.ts +1 -0
- package/dist/types/store/use-input-mode.d.ts +1 -0
- package/dist/types/store/useRouter.d.ts +1 -0
- package/dist/types/types.d.ts +1 -0
- package/dist/types/utils/format-date.d.ts +1 -0
- package/dist/types/utils/format-date.test.d.ts +1 -0
- package/dist/types/utils/transaction.d.ts +1 -0
- package/dist/types/views/connect-wallet/connect-wallet-view.d.ts +1 -0
- package/dist/types/views/connect-wallet/wallet-list-item.d.ts +1 -0
- package/dist/types/views/main/amount-input.d.ts +1 -0
- package/dist/types/views/main/connect-prompt.d.ts +1 -0
- package/dist/types/views/main/deposit-amount-input.d.ts +1 -0
- package/dist/types/views/main/deposit-form.d.ts +1 -0
- package/dist/types/views/main/main-cta-button.d.ts +1 -0
- package/dist/types/views/main/main-view.d.ts +1 -0
- package/dist/types/views/main/navbar/actions.d.ts +1 -0
- package/dist/types/views/main/navbar/icon.d.ts +1 -0
- package/dist/types/views/main/navbar/navbar.d.ts +1 -0
- package/dist/types/views/main/navbar/title.d.ts +1 -0
- package/dist/types/views/main/recipient/account.d.ts +1 -0
- package/dist/types/views/main/recipient/recipient.d.ts +1 -0
- package/dist/types/views/main/token-selector.d.ts +1 -0
- package/dist/types/views/qr-code.d.ts +1 -0
- package/dist/types/views/render-view.d.ts +1 -0
- package/dist/types/views/select-chain/chain-type-meta.d.ts +1 -0
- package/dist/types/views/select-chain/select-chain-view.d.ts +1 -0
- package/dist/types/views/select-token.d.ts +1 -0
- package/dist/types/views/transaction-history/activity-list-item.d.ts +1 -0
- package/dist/types/views/transaction-history/transaction-history-view.d.ts +1 -0
- package/dist/types/views/transaction-progress/helpers.d.ts +1 -0
- package/dist/types/views/transaction-progress/transaction-progress-view.d.ts +1 -0
- package/dist/types/views/transaction-progress/use-transaction-progress.d.ts +1 -0
- package/package.json +7 -7
- package/src/DepositWidget.tsx +0 -158
- package/src/compiled-tailwind.css +0 -6100
- package/src/components/ViewTransition.tsx +0 -81
- package/src/components/shared/buttons/button.tsx +0 -17
- package/src/components/shared/icons/types.ts +0 -3
- package/src/components/shared/icons/user-round.tsx +0 -21
- package/src/components/shared/navigation/base-navbar.tsx +0 -15
- package/src/components/shared/navigation/sub-navbar.tsx +0 -46
- package/src/components/token-badge-icon.tsx +0 -31
- package/src/components/token-list-item.tsx +0 -84
- package/src/components/view-container.tsx +0 -16
- package/src/constants.ts +0 -1
- package/src/css.d.ts +0 -4
- package/src/fonts/DMSans-Variable.woff2 +0 -0
- package/src/hooks/ui/useMainCTAButtonState.ts +0 -143
- package/src/hooks/use-auto-select-token.ts +0 -65
- package/src/hooks/use-deposit-route.ts +0 -58
- package/src/hooks/use-token-selection.ts +0 -17
- package/src/hooks/use-transaction-history.ts +0 -198
- package/src/index.ts +0 -3
- package/src/services/assets-service.ts +0 -21
- package/src/services/wallet-history/format.test.ts +0 -63
- package/src/services/wallet-history/format.ts +0 -128
- package/src/services/wallet-history/get-main-explorer-url.ts +0 -74
- package/src/services/wallet-history/get-wallet-history.ts +0 -24
- package/src/services/wallet-history/types.ts +0 -66
- package/src/services/wallet-history/validation.ts +0 -60
- package/src/store/use-deposit-store.ts +0 -20
- package/src/store/use-input-mode.ts +0 -10
- package/src/store/useRouter.ts +0 -49
- package/src/tailwind.css +0 -16
- package/src/types.ts +0 -39
- package/src/utils/format-date.test.ts +0 -32
- package/src/utils/format-date.ts +0 -25
- package/src/utils/transaction.ts +0 -39
- package/src/views/connect-wallet/connect-wallet-view.tsx +0 -147
- package/src/views/connect-wallet/wallet-list-item.tsx +0 -69
- package/src/views/main/amount-input.tsx +0 -272
- package/src/views/main/connect-prompt.tsx +0 -47
- package/src/views/main/deposit-amount-input.tsx +0 -42
- package/src/views/main/deposit-form.tsx +0 -13
- package/src/views/main/main-cta-button.tsx +0 -14
- package/src/views/main/main-view.tsx +0 -24
- package/src/views/main/navbar/actions.tsx +0 -25
- package/src/views/main/navbar/icon.tsx +0 -11
- package/src/views/main/navbar/navbar.tsx +0 -16
- package/src/views/main/navbar/title.tsx +0 -64
- package/src/views/main/recipient/account.tsx +0 -81
- package/src/views/main/recipient/recipient.tsx +0 -64
- package/src/views/main/token-selector.tsx +0 -77
- package/src/views/qr-code.tsx +0 -14
- package/src/views/render-view.tsx +0 -28
- package/src/views/select-chain/chain-type-meta.ts +0 -37
- package/src/views/select-chain/select-chain-view.tsx +0 -97
- package/src/views/select-token.tsx +0 -227
- package/src/views/transaction-history/activity-list-item.tsx +0 -87
- package/src/views/transaction-history/transaction-history-view.tsx +0 -58
- package/src/views/transaction-progress/helpers.tsx +0 -93
- package/src/views/transaction-progress/transaction-progress-view.tsx +0 -217
- package/src/views/transaction-progress/use-transaction-progress.ts +0 -112
package/src/store/useRouter.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { create } from "zustand";
|
|
2
|
-
import type { WidgetView } from "../types";
|
|
3
|
-
|
|
4
|
-
const INITIAL_VIEW: WidgetView = { id: "main" };
|
|
5
|
-
|
|
6
|
-
export type NavigationDirection = "forward" | "backward";
|
|
7
|
-
|
|
8
|
-
interface WidgetNavigationState {
|
|
9
|
-
stack: WidgetView[];
|
|
10
|
-
direction: NavigationDirection | null;
|
|
11
|
-
push: (_view: WidgetView) => void;
|
|
12
|
-
pop: () => void;
|
|
13
|
-
popToRoot: () => void;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const selectCurrentView = (state: WidgetNavigationState): WidgetView =>
|
|
17
|
-
state.stack[state.stack.length - 1] ?? INITIAL_VIEW;
|
|
18
|
-
|
|
19
|
-
export const useRouter = create<WidgetNavigationState>((set) => ({
|
|
20
|
-
stack: [INITIAL_VIEW],
|
|
21
|
-
direction: null,
|
|
22
|
-
|
|
23
|
-
push: (view: WidgetView): void =>
|
|
24
|
-
set((state) => {
|
|
25
|
-
if (selectCurrentView(state).id === view.id) return state;
|
|
26
|
-
return {
|
|
27
|
-
stack: [...state.stack, view],
|
|
28
|
-
direction: "forward",
|
|
29
|
-
};
|
|
30
|
-
}),
|
|
31
|
-
|
|
32
|
-
pop: (): void =>
|
|
33
|
-
set((state) => {
|
|
34
|
-
if (state.stack.length <= 1) return state;
|
|
35
|
-
return {
|
|
36
|
-
stack: state.stack.slice(0, -1),
|
|
37
|
-
direction: "backward",
|
|
38
|
-
};
|
|
39
|
-
}),
|
|
40
|
-
|
|
41
|
-
popToRoot: (): void =>
|
|
42
|
-
set((state) => {
|
|
43
|
-
if (state.stack.length <= 1) return state;
|
|
44
|
-
return {
|
|
45
|
-
stack: [INITIAL_VIEW],
|
|
46
|
-
direction: "backward",
|
|
47
|
-
};
|
|
48
|
-
}),
|
|
49
|
-
}));
|
package/src/tailwind.css
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
@import "@0xsquid/ui/dist/custom-styles.css";
|
|
2
|
-
|
|
3
|
-
@font-face {
|
|
4
|
-
font-family: "DMSansVariable";
|
|
5
|
-
src:
|
|
6
|
-
local("DMSansVariable"),
|
|
7
|
-
url("./fonts/DMSans-Variable.woff2") format("woff2");
|
|
8
|
-
font-display: swap;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.squid-style-container--preflight {
|
|
12
|
-
@tailwind base;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@tailwind components;
|
|
16
|
-
@tailwind utilities;
|
package/src/types.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { Wallet } from "@0xsquid/react-hooks";
|
|
2
|
-
import type { ChainType } from "@0xsquid/squid-types";
|
|
3
|
-
import type { Theme, ThemeType } from "@0xsquid/ui";
|
|
4
|
-
|
|
5
|
-
// View definitions — discriminated union so params are typed per view
|
|
6
|
-
export type WidgetView =
|
|
7
|
-
| { id: "main" }
|
|
8
|
-
| { id: "connect-wallet"; chainType: ChainType | null }
|
|
9
|
-
| { id: "select-chain"; wallet: Wallet }
|
|
10
|
-
| { id: "qr-code" }
|
|
11
|
-
| { id: "select-token" }
|
|
12
|
-
| { id: "transaction-history" }
|
|
13
|
-
| { id: "transaction-progress" };
|
|
14
|
-
|
|
15
|
-
export type WidgetViewId = WidgetView["id"];
|
|
16
|
-
|
|
17
|
-
interface BaseDepositConfig {
|
|
18
|
-
destinationAddress: string;
|
|
19
|
-
|
|
20
|
-
destinationToken: {
|
|
21
|
-
address: string;
|
|
22
|
-
chainId: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
integrator: {
|
|
26
|
-
id: string;
|
|
27
|
-
name: string;
|
|
28
|
-
logoUrl: string;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
apiUrl?: string;
|
|
32
|
-
|
|
33
|
-
theme?: Theme;
|
|
34
|
-
themeType?: ThemeType;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export type DepositConfig =
|
|
38
|
-
| (BaseDepositConfig & { mode: "deposit" })
|
|
39
|
-
| (BaseDepositConfig & { mode: "payment"; amount: string });
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { formatDayHeader, formatDateToHhMm } from "./format-date";
|
|
3
|
-
|
|
4
|
-
describe("formatDayHeader", () => {
|
|
5
|
-
beforeEach(() => {
|
|
6
|
-
vi.useFakeTimers();
|
|
7
|
-
vi.setSystemTime(new Date(2026, 3, 14));
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
vi.useRealTimers();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("omits the year when the date is in the current year", () => {
|
|
15
|
-
expect(formatDayHeader("2026-01-05")).toBe("January 5");
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("includes the year when the date is not in the current year", () => {
|
|
19
|
-
expect(formatDayHeader("2024-12-31")).toBe("December 31, 2024");
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("handles single-digit months and days", () => {
|
|
23
|
-
expect(formatDayHeader("2026-03-07")).toBe("March 7");
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("formatDateToHhMm", () => {
|
|
28
|
-
it("formats a date to a 2-digit hour and minute string", () => {
|
|
29
|
-
const date = new Date(2026, 3, 14, 9, 5);
|
|
30
|
-
expect(formatDateToHhMm(date)).toMatch(/09:05/);
|
|
31
|
-
});
|
|
32
|
-
});
|
package/src/utils/format-date.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export function formatDateToHhMm(date: Date): string {
|
|
2
|
-
return date.toLocaleTimeString("en-US", {
|
|
3
|
-
hour: "2-digit",
|
|
4
|
-
minute: "2-digit",
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function formatDayHeader(yyyyMmDd: string): string {
|
|
9
|
-
const [year = 0, month = 0, day] = yyyyMmDd.split("-").map(Number);
|
|
10
|
-
const date = new Date(year, month - 1, day);
|
|
11
|
-
const currentYear = new Date().getFullYear();
|
|
12
|
-
|
|
13
|
-
if (year === currentYear) {
|
|
14
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
15
|
-
month: "long",
|
|
16
|
-
day: "numeric",
|
|
17
|
-
}).format(date);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
21
|
-
month: "long",
|
|
22
|
-
day: "numeric",
|
|
23
|
-
year: "numeric",
|
|
24
|
-
}).format(date);
|
|
25
|
-
}
|
package/src/utils/transaction.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { parseToBigInt } from "@0xsquid/react-hooks";
|
|
2
|
-
import type { SwapTransactionHistory } from "@0xsquid/react-hooks";
|
|
3
|
-
import { SquidTransaction } from "../services/wallet-history/types";
|
|
4
|
-
import type { DepositConfig } from "../types";
|
|
5
|
-
|
|
6
|
-
export function isSameTx(
|
|
7
|
-
tx: SquidTransaction,
|
|
8
|
-
pending: SwapTransactionHistory,
|
|
9
|
-
): boolean {
|
|
10
|
-
if (!tx.transactionId || !pending.transactionId) return false;
|
|
11
|
-
return tx.transactionId.toLowerCase() === pending.transactionId.toLowerCase();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function isSameAddress(a: string, b: string): boolean {
|
|
15
|
-
return a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function matchesDestinationToken(
|
|
19
|
-
toToken: { address: string; chainId: string },
|
|
20
|
-
destinationToken: DepositConfig["destinationToken"],
|
|
21
|
-
): boolean {
|
|
22
|
-
return (
|
|
23
|
-
toToken.chainId === destinationToken.chainId &&
|
|
24
|
-
isSameAddress(toToken.address, destinationToken.address)
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function isPaymentTx(
|
|
29
|
-
tx: SquidTransaction,
|
|
30
|
-
paymentAmount: string,
|
|
31
|
-
destinationTokenDecimals: number,
|
|
32
|
-
): boolean {
|
|
33
|
-
try {
|
|
34
|
-
const expected = parseToBigInt(paymentAmount, destinationTokenDecimals);
|
|
35
|
-
return tx.quote.route.estimate.toAmount === expected.toString();
|
|
36
|
-
} catch {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { useCallback, useMemo, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
ConnectingWalletStatus,
|
|
4
|
-
useWallet,
|
|
5
|
-
useWallets,
|
|
6
|
-
sortWallets,
|
|
7
|
-
} from "@0xsquid/react-hooks";
|
|
8
|
-
import type { ConnectorID, Wallet } from "@0xsquid/react-hooks";
|
|
9
|
-
import type { ChainType } from "@0xsquid/squid-types";
|
|
10
|
-
import Fuse from "fuse.js";
|
|
11
|
-
import { SubNavBar } from "../../components/shared/navigation/sub-navbar";
|
|
12
|
-
import { useRouter } from "../../store/useRouter";
|
|
13
|
-
import { WalletListItem } from "./wallet-list-item";
|
|
14
|
-
import { ViewContainer } from "../../components/view-container";
|
|
15
|
-
import { CHAIN_TYPE_META } from "../select-chain/chain-type-meta";
|
|
16
|
-
|
|
17
|
-
const WALLET_PRIORITY_LIST: ConnectorID[] = [
|
|
18
|
-
"walletConnect",
|
|
19
|
-
"metamask",
|
|
20
|
-
"phantom",
|
|
21
|
-
"rabby",
|
|
22
|
-
"trustwallet",
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
function walletSupportsChainType(wallet: Wallet, chainType: ChainType) {
|
|
26
|
-
if (wallet.isMultiChain) {
|
|
27
|
-
return wallet.supportedNetworks.some((n) => n.chainType === chainType);
|
|
28
|
-
}
|
|
29
|
-
return wallet.type === chainType;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface ConnectWalletViewProps {
|
|
33
|
-
chainType: ChainType | null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function ConnectWalletView({ chainType }: ConnectWalletViewProps) {
|
|
37
|
-
const { wallets } = useWallets();
|
|
38
|
-
const { connectWallet, connectingWalletState } = useWallet();
|
|
39
|
-
const pop = useRouter((s) => s.pop);
|
|
40
|
-
const push = useRouter((s) => s.push);
|
|
41
|
-
const [search, setSearch] = useState("");
|
|
42
|
-
|
|
43
|
-
const requiredChainType = chainType;
|
|
44
|
-
|
|
45
|
-
const connectingConnectorId =
|
|
46
|
-
connectingWalletState.status === ConnectingWalletStatus.CONNECTING
|
|
47
|
-
? connectingWalletState.wallet?.connectorId
|
|
48
|
-
: undefined;
|
|
49
|
-
|
|
50
|
-
const isMultiChainWallet = useCallback(
|
|
51
|
-
(wallet: Wallet) =>
|
|
52
|
-
!requiredChainType &&
|
|
53
|
-
wallet.isMultiChain &&
|
|
54
|
-
wallet.supportedNetworks.length > 1 &&
|
|
55
|
-
!!wallet.isInstalled?.(),
|
|
56
|
-
[requiredChainType],
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
const onWalletClicked = async (wallet: Wallet) => {
|
|
60
|
-
if (isMultiChainWallet(wallet)) {
|
|
61
|
-
push({ id: "select-chain", wallet });
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
const selectedChainTypes = requiredChainType
|
|
67
|
-
? [requiredChainType]
|
|
68
|
-
: undefined;
|
|
69
|
-
const connected = await connectWallet({ wallet, selectedChainTypes });
|
|
70
|
-
if (connected) {
|
|
71
|
-
pop();
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error("Failed to connect wallet:", error);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const sortedWallets = useMemo(
|
|
79
|
-
() =>
|
|
80
|
-
wallets.toSorted((a, b) => {
|
|
81
|
-
if (requiredChainType) {
|
|
82
|
-
const aSupports = walletSupportsChainType(a, requiredChainType);
|
|
83
|
-
const bSupports = walletSupportsChainType(b, requiredChainType);
|
|
84
|
-
if (aSupports !== bSupports) return aSupports ? -1 : 1;
|
|
85
|
-
}
|
|
86
|
-
return sortWallets(a, b, {
|
|
87
|
-
isMobile: false,
|
|
88
|
-
priorityList: WALLET_PRIORITY_LIST,
|
|
89
|
-
});
|
|
90
|
-
}),
|
|
91
|
-
[wallets, requiredChainType],
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const fuse = useMemo(
|
|
95
|
-
() =>
|
|
96
|
-
new Fuse(sortedWallets, {
|
|
97
|
-
isCaseSensitive: false,
|
|
98
|
-
includeScore: false,
|
|
99
|
-
minMatchCharLength: 1,
|
|
100
|
-
threshold: 0.4,
|
|
101
|
-
keys: ["name"],
|
|
102
|
-
}),
|
|
103
|
-
[sortedWallets],
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
const walletsToDisplay = useMemo(() => {
|
|
107
|
-
if (search.length === 0) return sortedWallets;
|
|
108
|
-
return fuse.search(search).map((result) => result.item);
|
|
109
|
-
}, [fuse, search, sortedWallets]);
|
|
110
|
-
|
|
111
|
-
const chainTypeWallets = useMemo(() => {
|
|
112
|
-
if (!requiredChainType) return walletsToDisplay;
|
|
113
|
-
return walletsToDisplay.filter((w) =>
|
|
114
|
-
walletSupportsChainType(w, requiredChainType),
|
|
115
|
-
);
|
|
116
|
-
}, [walletsToDisplay, requiredChainType]);
|
|
117
|
-
|
|
118
|
-
return (
|
|
119
|
-
<>
|
|
120
|
-
<SubNavBar
|
|
121
|
-
input={{
|
|
122
|
-
placeholder: requiredChainType
|
|
123
|
-
? `Select ${CHAIN_TYPE_META[requiredChainType].name} wallet`
|
|
124
|
-
: "Select wallet",
|
|
125
|
-
onChange: (e) => setSearch(e.target.value),
|
|
126
|
-
autoComplete: "off",
|
|
127
|
-
autoCorrect: "off",
|
|
128
|
-
spellCheck: false,
|
|
129
|
-
}}
|
|
130
|
-
/>
|
|
131
|
-
|
|
132
|
-
<ViewContainer>
|
|
133
|
-
<ul className="tw-flex tw-flex-col tw-items-start tw-flex-1 tw-self-stretch">
|
|
134
|
-
{chainTypeWallets.map((wallet) => (
|
|
135
|
-
<WalletListItem
|
|
136
|
-
key={wallet.connectorId}
|
|
137
|
-
wallet={wallet}
|
|
138
|
-
isConnecting={wallet.connectorId === connectingConnectorId}
|
|
139
|
-
showAsMultiChain={isMultiChainWallet(wallet)}
|
|
140
|
-
onClick={() => onWalletClicked(wallet)}
|
|
141
|
-
/>
|
|
142
|
-
))}
|
|
143
|
-
</ul>
|
|
144
|
-
</ViewContainer>
|
|
145
|
-
</>
|
|
146
|
-
);
|
|
147
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { Wallet } from "@0xsquid/react-hooks";
|
|
2
|
-
import { ChevronLargeRightIcon, Loader, cn } from "@0xsquid/ui";
|
|
3
|
-
|
|
4
|
-
interface WalletListItemProps extends React.ComponentProps<"button"> {
|
|
5
|
-
wallet: Wallet;
|
|
6
|
-
isConnecting?: boolean;
|
|
7
|
-
showAsMultiChain?: boolean;
|
|
8
|
-
parentProps?: React.ComponentProps<"li">;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function WalletListItem({
|
|
12
|
-
wallet,
|
|
13
|
-
isConnecting,
|
|
14
|
-
showAsMultiChain,
|
|
15
|
-
parentProps,
|
|
16
|
-
...props
|
|
17
|
-
}: WalletListItemProps) {
|
|
18
|
-
const isInstalled = wallet.isInstalled?.();
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<li className="tw-self-stretch" {...parentProps}>
|
|
22
|
-
<button
|
|
23
|
-
className="tw-group/wallet tw-flex tw-min-h-14 tw-h-14 tw-px-4 tw-items-center tw-gap-3 tw-self-stretch tw-w-full hover:tw-bg-material-light-thin"
|
|
24
|
-
disabled={isConnecting}
|
|
25
|
-
{...props}
|
|
26
|
-
>
|
|
27
|
-
{/* icon */}
|
|
28
|
-
<div className="tw-flex tw-size-squid-xl tw-justify-center tw-items-center tw-aspect-square tw-rounded-xl tw-shadow-icon-light dark:tw-shadow-icon-dark">
|
|
29
|
-
{wallet.icon && (
|
|
30
|
-
<img
|
|
31
|
-
src={wallet.icon}
|
|
32
|
-
alt={wallet.name}
|
|
33
|
-
className="tw-size-full tw-rounded-xl"
|
|
34
|
-
/>
|
|
35
|
-
)}
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
{/* label */}
|
|
39
|
-
<span className="tw-flex tw-flex-col tw-justify-center tw-items-start tw-gap-2 tw-flex-1 tw-self-stretch tw-text-grey-200 tw-text-lg">
|
|
40
|
-
{wallet.name}
|
|
41
|
-
</span>
|
|
42
|
-
|
|
43
|
-
{/* detail */}
|
|
44
|
-
{isConnecting ? (
|
|
45
|
-
<Loader size="20" className="tw-text-grey-100" />
|
|
46
|
-
) : (
|
|
47
|
-
<div className="tw-flex tw-items-center">
|
|
48
|
-
{isInstalled && (
|
|
49
|
-
<div
|
|
50
|
-
className={cn(
|
|
51
|
-
"tw-flex tw-py-squid-s tw-flex-col tw-justify-center tw-items-end tw-self-stretch tw-text-material-light-thick tw-text-base tw-transition-transform tw-duration-200",
|
|
52
|
-
showAsMultiChain && "group-hover/wallet:-tw-translate-x-1",
|
|
53
|
-
)}
|
|
54
|
-
>
|
|
55
|
-
Installed
|
|
56
|
-
</div>
|
|
57
|
-
)}
|
|
58
|
-
{showAsMultiChain && (
|
|
59
|
-
<ChevronLargeRightIcon
|
|
60
|
-
className="tw-text-material-light-thick tw-transition-all tw-duration-200 tw-w-0 tw-opacity-0 group-hover/wallet:tw-w-4 group-hover/wallet:tw-opacity-100"
|
|
61
|
-
size="0.75rem"
|
|
62
|
-
/>
|
|
63
|
-
)}
|
|
64
|
-
</div>
|
|
65
|
-
)}
|
|
66
|
-
</button>
|
|
67
|
-
</li>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AnimateNumber,
|
|
3
|
-
CaptionText,
|
|
4
|
-
ChevronTopSmallIcon,
|
|
5
|
-
cn,
|
|
6
|
-
NumericInputProps,
|
|
7
|
-
Tooltip,
|
|
8
|
-
useNumericInput,
|
|
9
|
-
UserInputType,
|
|
10
|
-
} from "@0xsquid/ui";
|
|
11
|
-
import { useEffect, useRef } from "react";
|
|
12
|
-
import { useInputMode } from "../../store/use-input-mode";
|
|
13
|
-
|
|
14
|
-
const placeholder = "0";
|
|
15
|
-
const BASE_FONT_PX = 48; // tw-text-5xl = 3rem
|
|
16
|
-
const WRAPPER_PAD_X = 20; // tw-px-squid-xs = 0.625rem × 2
|
|
17
|
-
const MIN_SCALE = 0.5;
|
|
18
|
-
|
|
19
|
-
interface AmountInputProps extends NumericInputProps {
|
|
20
|
-
allowMaxButton?: boolean;
|
|
21
|
-
readOnly?: boolean;
|
|
22
|
-
errorMessage?: string;
|
|
23
|
-
loading?: boolean;
|
|
24
|
-
forcedUsdDisplay?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function AmountInput({
|
|
28
|
-
balance = "0",
|
|
29
|
-
token,
|
|
30
|
-
onAmountChange,
|
|
31
|
-
forcedAmount,
|
|
32
|
-
maxUsdDecimals = 2,
|
|
33
|
-
formatIfVerySmall = {
|
|
34
|
-
token: "0.001",
|
|
35
|
-
usd: "0.01",
|
|
36
|
-
},
|
|
37
|
-
inputModeButton,
|
|
38
|
-
debounceInput = true,
|
|
39
|
-
allowMaxButton = true,
|
|
40
|
-
readOnly = false,
|
|
41
|
-
errorMessage,
|
|
42
|
-
loading = false,
|
|
43
|
-
forcedUsdDisplay,
|
|
44
|
-
}: AmountInputProps) {
|
|
45
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
46
|
-
const inputValueSpyRef = useRef<HTMLSpanElement>(null);
|
|
47
|
-
const inputWidthSpyRef = useRef<HTMLSpanElement>(null);
|
|
48
|
-
const wrapperRef = useRef<HTMLLabelElement & HTMLDivElement>(null);
|
|
49
|
-
const {
|
|
50
|
-
userInputType,
|
|
51
|
-
inputValue,
|
|
52
|
-
handleInputChange,
|
|
53
|
-
handleSwitchInputMode,
|
|
54
|
-
isTokenAmountVerySmall,
|
|
55
|
-
isUsdAmountVerySmall,
|
|
56
|
-
amountFormatted,
|
|
57
|
-
onBalanceButtonClick,
|
|
58
|
-
} = useNumericInput({
|
|
59
|
-
onAmountChange,
|
|
60
|
-
token,
|
|
61
|
-
balance,
|
|
62
|
-
debounceInput,
|
|
63
|
-
forcedAmount,
|
|
64
|
-
formatIfVerySmall,
|
|
65
|
-
inputModeButton,
|
|
66
|
-
maxUsdDecimals,
|
|
67
|
-
direction: "from",
|
|
68
|
-
initialInputMode: UserInputType.USD,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const setInputMode = useInputMode((s) => s.setMode);
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
setInputMode(userInputType);
|
|
74
|
-
}, [userInputType, setInputMode]);
|
|
75
|
-
|
|
76
|
-
const displayedNumber =
|
|
77
|
-
userInputType === UserInputType.USD && forcedUsdDisplay && !inputValue
|
|
78
|
-
? forcedUsdDisplay
|
|
79
|
-
: inputValue || placeholder;
|
|
80
|
-
const fullDisplayedNumber =
|
|
81
|
-
userInputType === UserInputType.USD
|
|
82
|
-
? `$${displayedNumber}`
|
|
83
|
-
: displayedNumber;
|
|
84
|
-
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
const spy = inputValueSpyRef.current;
|
|
87
|
-
const wrapper = wrapperRef.current;
|
|
88
|
-
const row = wrapper?.parentElement;
|
|
89
|
-
if (!spy || !wrapper || !row) return;
|
|
90
|
-
|
|
91
|
-
const apply = () => {
|
|
92
|
-
const containerWidth = row.clientWidth - WRAPPER_PAD_X;
|
|
93
|
-
const spyWidth = spy.getBoundingClientRect().width;
|
|
94
|
-
if (containerWidth === 0 || spyWidth === 0) return;
|
|
95
|
-
|
|
96
|
-
// Scale against the full visible value, including the "$" prefix in USD
|
|
97
|
-
// mode, so read-only/payment values don't overflow by the prefix width.
|
|
98
|
-
const scale = Math.min(1, Math.max(MIN_SCALE, containerWidth / spyWidth));
|
|
99
|
-
wrapper.style.fontSize = `${BASE_FONT_PX * scale}px`;
|
|
100
|
-
if (inputRef.current) {
|
|
101
|
-
const inputWidthSpy = inputWidthSpyRef.current;
|
|
102
|
-
// Editable USD renders "$" beside the input, so the input itself must
|
|
103
|
-
// be sized from the number-only spy. Token mode can reuse full width.
|
|
104
|
-
const inputWidth =
|
|
105
|
-
userInputType === UserInputType.USD && inputWidthSpy
|
|
106
|
-
? inputWidthSpy.getBoundingClientRect().width
|
|
107
|
-
: spyWidth;
|
|
108
|
-
|
|
109
|
-
inputRef.current.style.width = `${inputWidth * scale}px`;
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const observer = new ResizeObserver(apply);
|
|
114
|
-
observer.observe(spy);
|
|
115
|
-
observer.observe(row);
|
|
116
|
-
apply();
|
|
117
|
-
|
|
118
|
-
return () => observer.disconnect();
|
|
119
|
-
}, [readOnly, displayedNumber, fullDisplayedNumber, userInputType]);
|
|
120
|
-
const wrapperClassName = cn(
|
|
121
|
-
"tw-text-grey-100 tw-flex tw-items-center tw-overflow-hidden tw-px-squid-xs",
|
|
122
|
-
readOnly
|
|
123
|
-
? "tw-cursor-default"
|
|
124
|
-
: "tw-cursor-text focus-within:tw-bg-material-light-thin hover:tw-bg-material-light-thin group-focus-within/amount-input:tw-text-royal-500",
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
// em so the radius scales with the wrapper's font-size (which the
|
|
128
|
-
// auto-shrink effect mutates) — keeps the corner proportional to the
|
|
129
|
-
// shrunk height instead of looking pill-like at small font sizes.
|
|
130
|
-
const wrapperStyle = { borderRadius: "0.4em" };
|
|
131
|
-
|
|
132
|
-
const inputContent = (
|
|
133
|
-
<>
|
|
134
|
-
{/* Hidden full visible value, fixed at base font size, for wrapper scaling. */}
|
|
135
|
-
<span
|
|
136
|
-
ref={inputValueSpyRef}
|
|
137
|
-
className="tw-pointer-events-none tw-absolute tw-opacity-0 tw-text-5xl"
|
|
138
|
-
>
|
|
139
|
-
{fullDisplayedNumber}
|
|
140
|
-
</span>
|
|
141
|
-
{/* Hidden number-only value for editable USD input width. */}
|
|
142
|
-
<span
|
|
143
|
-
ref={inputWidthSpyRef}
|
|
144
|
-
className="tw-pointer-events-none tw-absolute tw-opacity-0 tw-text-5xl"
|
|
145
|
-
>
|
|
146
|
-
{displayedNumber}
|
|
147
|
-
</span>
|
|
148
|
-
|
|
149
|
-
{readOnly ? (
|
|
150
|
-
<span className="tw-relative tw-py-2 tw-flex tw-items-center">
|
|
151
|
-
{userInputType === UserInputType.USD && <span>$</span>}
|
|
152
|
-
<AnimateNumber
|
|
153
|
-
isLoading={loading}
|
|
154
|
-
number={displayedNumber}
|
|
155
|
-
showMask
|
|
156
|
-
/>
|
|
157
|
-
{loading && (
|
|
158
|
-
<span className="tw-pointer-events-none tw-absolute tw-inset-0 tw-z-10 tw-overflow-hidden">
|
|
159
|
-
<span className="tw-absolute tw-inset-0 tw-animate-shimmer tw-bg-[length:200%_100%] tw-bg-shimmer-overlay-light dark:tw-bg-shimmer-overlay-dark" />
|
|
160
|
-
</span>
|
|
161
|
-
)}
|
|
162
|
-
</span>
|
|
163
|
-
) : (
|
|
164
|
-
<>
|
|
165
|
-
{userInputType === UserInputType.USD && <span>$</span>}
|
|
166
|
-
<input
|
|
167
|
-
inputMode="decimal"
|
|
168
|
-
pattern="[0-9.,]*"
|
|
169
|
-
ref={inputRef}
|
|
170
|
-
value={inputValue}
|
|
171
|
-
onChange={handleInputChange}
|
|
172
|
-
className="tw-bg-transparent tw-placeholder-grey-100 tw-outline-none focus:tw-outline-none focus:tw-placeholder-royal-500"
|
|
173
|
-
placeholder={placeholder}
|
|
174
|
-
/>
|
|
175
|
-
</>
|
|
176
|
-
)}
|
|
177
|
-
</>
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<section className="tw-flex tw-flex-1 tw-flex-col tw-items-center tw-justify-center tw-self-stretch tw-gap-1 tw-relative tw-overflow-hidden">
|
|
182
|
-
<div className="tw-flex tw-w-full tw-items-center tw-justify-center tw-self-stretch tw-text-5xl tw-group/amount-input">
|
|
183
|
-
{readOnly ? (
|
|
184
|
-
<div
|
|
185
|
-
ref={wrapperRef}
|
|
186
|
-
className={wrapperClassName}
|
|
187
|
-
style={wrapperStyle}
|
|
188
|
-
>
|
|
189
|
-
{inputContent}
|
|
190
|
-
</div>
|
|
191
|
-
) : (
|
|
192
|
-
<label
|
|
193
|
-
ref={wrapperRef}
|
|
194
|
-
className={wrapperClassName}
|
|
195
|
-
style={wrapperStyle}
|
|
196
|
-
>
|
|
197
|
-
{inputContent}
|
|
198
|
-
</label>
|
|
199
|
-
)}
|
|
200
|
-
</div>
|
|
201
|
-
|
|
202
|
-
<div className="tw-relative tw-flex tw-justify-center tw-self-stretch">
|
|
203
|
-
<footer className="tw-flex tw-h-squid-m tw-items-center tw-justify-center tw-text-sm tw-text-material-light-thick tw-w-fit">
|
|
204
|
-
<Tooltip
|
|
205
|
-
{...(userInputType === UserInputType.TOKEN
|
|
206
|
-
? inputModeButton?.tokenModeTooltip
|
|
207
|
-
: inputModeButton?.usdModeTooltip)}
|
|
208
|
-
tooltipWidth="max"
|
|
209
|
-
childrenClassName="tw-rounded-squid-s"
|
|
210
|
-
containerClassName="tw-rounded-squid-s tw-w-fit"
|
|
211
|
-
>
|
|
212
|
-
<button
|
|
213
|
-
onClick={() => {
|
|
214
|
-
handleSwitchInputMode();
|
|
215
|
-
inputRef.current?.focus();
|
|
216
|
-
}}
|
|
217
|
-
className="tw-flex tw-flex-1 tw-items-center tw-gap-squid-xxs tw-rounded-squid-s tw-px-3 tw-py-0.5 hover:tw-bg-material-light-thin"
|
|
218
|
-
>
|
|
219
|
-
{userInputType === UserInputType.TOKEN ? (
|
|
220
|
-
<span className="tw-flex tw-items-center tw-justify-center">
|
|
221
|
-
<CaptionText>{isUsdAmountVerySmall ? "<" : ""}$</CaptionText>
|
|
222
|
-
<CaptionText>
|
|
223
|
-
{forcedUsdDisplay && !inputValue
|
|
224
|
-
? forcedUsdDisplay
|
|
225
|
-
: isUsdAmountVerySmall
|
|
226
|
-
? formatIfVerySmall.token
|
|
227
|
-
: amountFormatted}
|
|
228
|
-
</CaptionText>
|
|
229
|
-
</span>
|
|
230
|
-
) : (
|
|
231
|
-
<>
|
|
232
|
-
<CaptionText>
|
|
233
|
-
{isTokenAmountVerySmall ? "<" : ""}
|
|
234
|
-
{isTokenAmountVerySmall
|
|
235
|
-
? formatIfVerySmall.token
|
|
236
|
-
: amountFormatted}
|
|
237
|
-
</CaptionText>{" "}
|
|
238
|
-
<CaptionText>{token.symbol}</CaptionText>
|
|
239
|
-
</>
|
|
240
|
-
)}
|
|
241
|
-
|
|
242
|
-
<span className="tw-flex tw-items-center tw-justify-center tw-rounded-full tw-size-3 tw-bg-material-light-thin tw-aspect-square">
|
|
243
|
-
<ChevronTopSmallIcon />
|
|
244
|
-
</span>
|
|
245
|
-
</button>
|
|
246
|
-
</Tooltip>
|
|
247
|
-
|
|
248
|
-
{allowMaxButton && Number(balance) > 0 && (
|
|
249
|
-
<button
|
|
250
|
-
onClick={() => {
|
|
251
|
-
onBalanceButtonClick();
|
|
252
|
-
inputRef.current?.focus();
|
|
253
|
-
}}
|
|
254
|
-
className="tw-rounded-squid-s tw-px-3 tw-py-0.5 hover:tw-bg-material-light-thin"
|
|
255
|
-
>
|
|
256
|
-
<CaptionText>MAX</CaptionText>
|
|
257
|
-
</button>
|
|
258
|
-
)}
|
|
259
|
-
</footer>
|
|
260
|
-
|
|
261
|
-
{/* Anchored to the footer via top-full so it sits just below the
|
|
262
|
-
input + balance row regardless of the section's flex-1 height;
|
|
263
|
-
absolute so toggling it never reflows the input. */}
|
|
264
|
-
{errorMessage && (
|
|
265
|
-
<CaptionText className="tw-text-status-negative tw-text-center tw-absolute tw-top-full tw-mt-2 tw-left-0 tw-right-0 tw-px-4 [text-wrap:pretty]">
|
|
266
|
-
{errorMessage}
|
|
267
|
-
</CaptionText>
|
|
268
|
-
)}
|
|
269
|
-
</div>
|
|
270
|
-
</section>
|
|
271
|
-
);
|
|
272
|
-
}
|