@medialane/ui 0.256.0 → 0.258.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/dist/components/account/add-guardian-dialog.cjs +1 -1
- package/dist/components/account/add-guardian-dialog.cjs.map +1 -1
- package/dist/components/account/add-guardian-dialog.js +1 -1
- package/dist/components/account/add-guardian-dialog.js.map +1 -1
- package/dist/components/account/device-approval-dialog.cjs +2 -2
- package/dist/components/account/device-approval-dialog.cjs.map +1 -1
- package/dist/components/account/device-approval-dialog.js +2 -2
- package/dist/components/account/device-approval-dialog.js.map +1 -1
- package/dist/components/account/devices-section.cjs +1 -1
- package/dist/components/account/devices-section.cjs.map +1 -1
- package/dist/components/account/devices-section.js +1 -1
- package/dist/components/account/devices-section.js.map +1 -1
- package/dist/components/account/guardian-recovery-section.cjs +1 -1
- package/dist/components/account/guardian-recovery-section.cjs.map +1 -1
- package/dist/components/account/guardian-recovery-section.js +1 -1
- package/dist/components/account/guardian-recovery-section.js.map +1 -1
- package/dist/components/account/input-otp.d.cts +2 -2
- package/dist/components/account/input-otp.d.ts +2 -2
- package/dist/components/asset-page.cjs +8 -7
- package/dist/components/asset-page.cjs.map +1 -1
- package/dist/components/asset-page.js +8 -7
- package/dist/components/asset-page.js.map +1 -1
- package/dist/components/asset-publication.cjs +1 -3
- package/dist/components/asset-publication.cjs.map +1 -1
- package/dist/components/asset-publication.js +1 -3
- package/dist/components/asset-publication.js.map +1 -1
- package/dist/components/button.d.cts +2 -2
- package/dist/components/button.d.ts +2 -2
- package/dist/components/drop/create/launch-dialog.cjs +1 -1
- package/dist/components/drop/create/launch-dialog.cjs.map +1 -1
- package/dist/components/drop/create/launch-dialog.js +1 -1
- package/dist/components/drop/create/launch-dialog.js.map +1 -1
- package/dist/components/drop/page/drop-manage.cjs +1 -1
- package/dist/components/drop/page/drop-manage.cjs.map +1 -1
- package/dist/components/drop/page/drop-manage.js +1 -1
- package/dist/components/drop/page/drop-manage.js.map +1 -1
- package/dist/components/drop/page/drop-mint-dialog.cjs +1 -1
- package/dist/components/drop/page/drop-mint-dialog.cjs.map +1 -1
- package/dist/components/drop/page/drop-mint-dialog.js +1 -1
- package/dist/components/drop/page/drop-mint-dialog.js.map +1 -1
- package/dist/components/empty-or-error.cjs +2 -2
- package/dist/components/empty-or-error.cjs.map +1 -1
- package/dist/components/empty-or-error.js +2 -2
- package/dist/components/empty-or-error.js.map +1 -1
- package/dist/components/fast-mint/fast-mint.cjs +2 -1
- package/dist/components/fast-mint/fast-mint.cjs.map +1 -1
- package/dist/components/fast-mint/fast-mint.d.cts +2 -2
- package/dist/components/fast-mint/fast-mint.d.ts +2 -2
- package/dist/components/fast-mint/fast-mint.js +2 -1
- package/dist/components/fast-mint/fast-mint.js.map +1 -1
- package/dist/components/launchpad/edition-mint-schema.d.cts +2 -2
- package/dist/components/launchpad/edition-mint-schema.d.ts +2 -2
- package/dist/components/license-request-page.cjs +1 -1
- package/dist/components/license-request-page.cjs.map +1 -1
- package/dist/components/license-request-page.js +1 -1
- package/dist/components/license-request-page.js.map +1 -1
- package/dist/components/media-wallet/activate-card.cjs +1 -1
- package/dist/components/media-wallet/activate-card.cjs.map +1 -1
- package/dist/components/media-wallet/activate-card.js +1 -1
- package/dist/components/media-wallet/activate-card.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-activity.cjs +1 -1
- package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-activity.js +1 -1
- package/dist/components/media-wallet/media-wallet-activity.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-send.cjs +2 -6
- package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-send.js +2 -6
- package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
- package/dist/components/sheet.d.cts +1 -1
- package/dist/components/sheet.d.ts +1 -1
- package/dist/components/transaction-dialog.cjs +4 -4
- package/dist/components/transaction-dialog.cjs.map +1 -1
- package/dist/components/transaction-dialog.d.cts +3 -1
- package/dist/components/transaction-dialog.d.ts +3 -1
- package/dist/components/transaction-dialog.js +4 -4
- package/dist/components/transaction-dialog.js.map +1 -1
- package/dist/components/wallet/export-key-section.cjs +3 -3
- package/dist/components/wallet/export-key-section.cjs.map +1 -1
- package/dist/components/wallet/export-key-section.d.cts +1 -2
- package/dist/components/wallet/export-key-section.d.ts +1 -2
- package/dist/components/wallet/export-key-section.js +3 -3
- package/dist/components/wallet/export-key-section.js.map +1 -1
- package/dist/index.cjs +0 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/describe-error.cjs +16 -11
- package/dist/utils/describe-error.cjs.map +1 -1
- package/dist/utils/describe-error.d.cts +4 -4
- package/dist/utils/describe-error.d.ts +4 -4
- package/dist/utils/describe-error.js +16 -10
- package/dist/utils/describe-error.js.map +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
- package/dist/utils/use-email-code.cjs +2 -2
- package/dist/utils/use-email-code.cjs.map +1 -1
- package/dist/utils/use-email-code.js +2 -2
- package/dist/utils/use-email-code.js.map +1 -1
- package/dist/utils/use-transaction.cjs +16 -2
- package/dist/utils/use-transaction.cjs.map +1 -1
- package/dist/utils/use-transaction.d.cts +1 -0
- package/dist/utils/use-transaction.d.ts +1 -0
- package/dist/utils/use-transaction.js +17 -3
- package/dist/utils/use-transaction.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/run-intent-calls.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, useWriteAction } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(\"STRK\", address);\n const eth = useTokenBalance(\"ETH\", address);\n const usdc = useTokenBalance(\"USDC\", address);\n const wbtc = useTokenBalance(\"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.intents.create(\"transfer-token\", { owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-2xs font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/run-intent-calls.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, useWriteAction } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(\"STRK\", address);\n const eth = useTokenBalance(\"ETH\", address);\n const usdc = useTokenBalance(\"USDC\", address);\n const wbtc = useTokenBalance(\"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e).message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.intents.create(\"transfer-token\", { owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-2xs font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -10,7 +10,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
|
|
|
10
10
|
declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
|
|
11
11
|
declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const sheetVariants: (props?: ({
|
|
13
|
-
side?: "
|
|
13
|
+
side?: "bottom" | "left" | "right" | "top" | null | undefined;
|
|
14
14
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
15
15
|
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
|
|
16
16
|
overlayClassName?: string;
|
|
@@ -10,7 +10,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
|
|
|
10
10
|
declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
|
|
11
11
|
declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const sheetVariants: (props?: ({
|
|
13
|
-
side?: "
|
|
13
|
+
side?: "bottom" | "left" | "right" | "top" | null | undefined;
|
|
14
14
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
15
15
|
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
|
|
16
16
|
overlayClassName?: string;
|
|
@@ -30,7 +30,7 @@ var import_button = require("./button.js");
|
|
|
30
30
|
var import_confetti = require("../utils/media-wallet/confetti.js");
|
|
31
31
|
const ACTIVE_STEP = { preparing: 0, submitting: 1, confirming: 2 };
|
|
32
32
|
function TransactionDialog({ tx, title, workingLabel, firstStepLabel = "Prepare", children }) {
|
|
33
|
-
const { phase, error, reset } = tx;
|
|
33
|
+
const { phase, error, reset, retryable = true } = tx;
|
|
34
34
|
const working = phase === "preparing" || phase === "submitting" || phase === "confirming";
|
|
35
35
|
const success = phase === "success";
|
|
36
36
|
const failed = phase === "error";
|
|
@@ -74,10 +74,10 @@ function TransactionDialog({ tx, title, workingLabel, firstStepLabel = "Prepare"
|
|
|
74
74
|
failed && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center gap-5 py-2", children: [
|
|
75
75
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex h-16 w-16 items-center justify-center rounded-full bg-destructive/10", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.XCircle, { className: "h-9 w-9 text-destructive" }) }),
|
|
76
76
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1 text-center", children: [
|
|
77
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xl font-bold", children:
|
|
78
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mx-auto max-w-xs text-sm text-muted-foreground", children: error
|
|
77
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xl font-bold", children: title }),
|
|
78
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mx-auto max-w-xs text-sm text-muted-foreground", children: error })
|
|
79
79
|
] }),
|
|
80
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_button.Button, { variant: "outline", className: "w-full", onClick: reset, children: "Try again" })
|
|
80
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_button.Button, { variant: "outline", className: "w-full", onClick: reset, children: retryable ? "Try again" : "Close" })
|
|
81
81
|
] })
|
|
82
82
|
]
|
|
83
83
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/transaction-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type ReactNode } from \"react\";\nimport { CheckCircle2, Loader2, XCircle } from \"lucide-react\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Button } from \"./button.js\";\nimport { fireConfetti } from \"../utils/media-wallet/confetti.js\";\nimport type { useTransaction } from \"../utils/use-transaction.js\";\n\nexport interface TransactionDialogProps {\n tx: Pick<ReturnType<typeof useTransaction>, \"phase\" | \"error\" | \"reset\"
|
|
1
|
+
{"version":3,"sources":["../../src/components/transaction-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type ReactNode } from \"react\";\nimport { CheckCircle2, Loader2, XCircle } from \"lucide-react\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Button } from \"./button.js\";\nimport { fireConfetti } from \"../utils/media-wallet/confetti.js\";\nimport type { useTransaction } from \"../utils/use-transaction.js\";\n\nexport interface TransactionDialogProps {\n tx: Pick<ReturnType<typeof useTransaction>, \"phase\" | \"error\" | \"reset\"> & { retryable?: boolean };\n title: string;\n workingLabel: string;\n firstStepLabel?: string;\n children?: ReactNode;\n}\n\nconst ACTIVE_STEP = { preparing: 0, submitting: 1, confirming: 2 } as const;\n\nexport function TransactionDialog({ tx, title, workingLabel, firstStepLabel = \"Prepare\", children }: TransactionDialogProps) {\n const { phase, error, reset, retryable = true } = tx;\n const working = phase === \"preparing\" || phase === \"submitting\" || phase === \"confirming\";\n const success = phase === \"success\";\n const failed = phase === \"error\";\n const steps = [firstStepLabel, \"Submit transaction\", \"Confirm transaction\"];\n\n const confettiFired = useRef(false);\n useEffect(() => {\n if (success && !confettiFired.current) {\n confettiFired.current = true;\n fireConfetti();\n }\n if (!success) confettiFired.current = false;\n }, [success]);\n\n return (\n <Dialog open={phase !== \"idle\"} modal onOpenChange={(open) => { if (!open && !working) reset(); }}>\n <DialogContent\n className=\"sm:max-w-md\"\n onInteractOutside={working ? (e) => e.preventDefault() : undefined}\n onEscapeKeyDown={working ? (e) => e.preventDefault() : undefined}\n {...(working ? { hideClose: true } : {})}\n >\n <DialogTitle className=\"sr-only\">{working ? workingLabel : title}</DialogTitle>\n\n {working && (\n <div className=\"flex flex-col items-center gap-6 py-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-primary/10\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n <div className=\"space-y-1 text-center\">\n <p className=\"text-lg font-semibold\">{workingLabel}</p>\n <p className=\"text-sm text-muted-foreground\">\n {phase === \"confirming\" ? \"Waiting for block confirmation\" : \"Submitting transaction\"}\n </p>\n </div>\n <ol className=\"w-full space-y-2 rounded-xl border border-border/60 bg-muted/30 p-4\">\n {steps.map((label, i) => {\n const active = i === ACTIVE_STEP[phase];\n const done = i < ACTIVE_STEP[phase];\n return (\n <li key={label} data-step aria-current={active ? \"step\" : undefined} className=\"flex items-center gap-3\">\n {done ? (\n <CheckCircle2 className=\"h-4 w-4 shrink-0 text-emerald-500\" />\n ) : active ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin text-primary\" />\n ) : (\n <div className=\"h-4 w-4 shrink-0 rounded-full border-2 border-muted-foreground/30\" />\n )}\n <span className={done ? \"text-sm text-foreground\" : active ? \"text-sm font-medium text-primary\" : \"text-sm text-muted-foreground\"}>\n {label}\n </span>\n </li>\n );\n })}\n </ol>\n <p className=\"text-center text-xs text-muted-foreground\">This usually takes 10–30 seconds. Do not close this window.</p>\n </div>\n )}\n\n {success && children}\n\n {failed && (\n <div className=\"flex flex-col items-center gap-5 py-2\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-destructive/10\">\n <XCircle className=\"h-9 w-9 text-destructive\" />\n </div>\n <div className=\"space-y-1 text-center\">\n <p className=\"text-xl font-bold\">{title}</p>\n <p className=\"mx-auto max-w-xs text-sm text-muted-foreground\">{error}</p>\n </div>\n <Button variant=\"outline\" className=\"w-full\" onClick={reset}>\n {retryable ? \"Try again\" : \"Close\"}\n </Button>\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CQ;AAzCR,mBAAkD;AAClD,0BAA+C;AAC/C,oBAAmD;AACnD,oBAAuB;AACvB,sBAA6B;AAW7B,MAAM,cAAc,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,EAAE;AAE1D,SAAS,kBAAkB,EAAE,IAAI,OAAO,cAAc,iBAAiB,WAAW,SAAS,GAA2B;AAC3H,QAAM,EAAE,OAAO,OAAO,OAAO,YAAY,KAAK,IAAI;AAClD,QAAM,UAAU,UAAU,eAAe,UAAU,gBAAgB,UAAU;AAC7E,QAAM,UAAU,UAAU;AAC1B,QAAM,SAAS,UAAU;AACzB,QAAM,QAAQ,CAAC,gBAAgB,sBAAsB,qBAAqB;AAE1E,QAAM,oBAAgB,qBAAO,KAAK;AAClC,8BAAU,MAAM;AACd,QAAI,WAAW,CAAC,cAAc,SAAS;AACrC,oBAAc,UAAU;AACxB,wCAAa;AAAA,IACf;AACA,QAAI,CAAC,QAAS,eAAc,UAAU;AAAA,EACxC,GAAG,CAAC,OAAO,CAAC;AAEZ,SACE,4CAAC,wBAAO,MAAM,UAAU,QAAQ,OAAK,MAAC,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,QAAQ,CAAC,QAAS,OAAM;AAAA,EAAG,GAC9F;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,mBAAmB,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI;AAAA,MACzD,iBAAiB,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI;AAAA,MACtD,GAAI,UAAU,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,MAEtC;AAAA,oDAAC,6BAAY,WAAU,WAAW,oBAAU,eAAe,OAAM;AAAA,QAEhE,WACC,6CAAC,SAAI,WAAU,yCACb;AAAA,sDAAC,SAAI,WAAU,yEACb,sDAAC,+BAAQ,WAAU,qCAAoC,GACzD;AAAA,UACA,6CAAC,SAAI,WAAU,yBACb;AAAA,wDAAC,OAAE,WAAU,yBAAyB,wBAAa;AAAA,YACnD,4CAAC,OAAE,WAAU,iCACV,oBAAU,eAAe,mCAAmC,0BAC/D;AAAA,aACF;AAAA,UACA,4CAAC,QAAG,WAAU,uEACX,gBAAM,IAAI,CAAC,OAAO,MAAM;AACvB,kBAAM,SAAS,MAAM,YAAY,KAAK;AACtC,kBAAM,OAAO,IAAI,YAAY,KAAK;AAClC,mBACE,6CAAC,QAAe,aAAS,MAAC,gBAAc,SAAS,SAAS,QAAW,WAAU,2BAC5E;AAAA,qBACC,4CAAC,oCAAa,WAAU,qCAAoC,IAC1D,SACF,4CAAC,+BAAQ,WAAU,8CAA6C,IAEhE,4CAAC,SAAI,WAAU,qEAAoE;AAAA,cAErF,4CAAC,UAAK,WAAW,OAAO,4BAA4B,SAAS,qCAAqC,iCAC/F,iBACH;AAAA,iBAVO,KAWT;AAAA,UAEJ,CAAC,GACH;AAAA,UACA,4CAAC,OAAE,WAAU,6CAA4C,8EAA2D;AAAA,WACtH;AAAA,QAGD,WAAW;AAAA,QAEX,UACC,6CAAC,SAAI,WAAU,yCACb;AAAA,sDAAC,SAAI,WAAU,6EACb,sDAAC,+BAAQ,WAAU,4BAA2B,GAChD;AAAA,UACA,6CAAC,SAAI,WAAU,yBACb;AAAA,wDAAC,OAAE,WAAU,qBAAqB,iBAAM;AAAA,YACxC,4CAAC,OAAE,WAAU,kDAAkD,iBAAM;AAAA,aACvE;AAAA,UACA,4CAAC,wBAAO,SAAQ,WAAU,WAAU,UAAS,SAAS,OACnD,sBAAY,cAAc,SAC7B;AAAA,WACF;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;","names":[]}
|
|
@@ -7,7 +7,9 @@ import 'starknet';
|
|
|
7
7
|
import '@medialane/sdk';
|
|
8
8
|
|
|
9
9
|
interface TransactionDialogProps {
|
|
10
|
-
tx: Pick<ReturnType<typeof useTransaction>, "phase" | "error" | "reset"
|
|
10
|
+
tx: Pick<ReturnType<typeof useTransaction>, "phase" | "error" | "reset"> & {
|
|
11
|
+
retryable?: boolean;
|
|
12
|
+
};
|
|
11
13
|
title: string;
|
|
12
14
|
workingLabel: string;
|
|
13
15
|
firstStepLabel?: string;
|
|
@@ -7,7 +7,9 @@ import 'starknet';
|
|
|
7
7
|
import '@medialane/sdk';
|
|
8
8
|
|
|
9
9
|
interface TransactionDialogProps {
|
|
10
|
-
tx: Pick<ReturnType<typeof useTransaction>, "phase" | "error" | "reset"
|
|
10
|
+
tx: Pick<ReturnType<typeof useTransaction>, "phase" | "error" | "reset"> & {
|
|
11
|
+
retryable?: boolean;
|
|
12
|
+
};
|
|
11
13
|
title: string;
|
|
12
14
|
workingLabel: string;
|
|
13
15
|
firstStepLabel?: string;
|
|
@@ -7,7 +7,7 @@ import { Button } from "./button.js";
|
|
|
7
7
|
import { fireConfetti } from "../utils/media-wallet/confetti.js";
|
|
8
8
|
const ACTIVE_STEP = { preparing: 0, submitting: 1, confirming: 2 };
|
|
9
9
|
function TransactionDialog({ tx, title, workingLabel, firstStepLabel = "Prepare", children }) {
|
|
10
|
-
const { phase, error, reset } = tx;
|
|
10
|
+
const { phase, error, reset, retryable = true } = tx;
|
|
11
11
|
const working = phase === "preparing" || phase === "submitting" || phase === "confirming";
|
|
12
12
|
const success = phase === "success";
|
|
13
13
|
const failed = phase === "error";
|
|
@@ -51,10 +51,10 @@ function TransactionDialog({ tx, title, workingLabel, firstStepLabel = "Prepare"
|
|
|
51
51
|
failed && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-5 py-2", children: [
|
|
52
52
|
/* @__PURE__ */ jsx("div", { className: "flex h-16 w-16 items-center justify-center rounded-full bg-destructive/10", children: /* @__PURE__ */ jsx(XCircle, { className: "h-9 w-9 text-destructive" }) }),
|
|
53
53
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1 text-center", children: [
|
|
54
|
-
/* @__PURE__ */ jsx("p", { className: "text-xl font-bold", children:
|
|
55
|
-
/* @__PURE__ */ jsx("p", { className: "mx-auto max-w-xs text-sm text-muted-foreground", children: error
|
|
54
|
+
/* @__PURE__ */ jsx("p", { className: "text-xl font-bold", children: title }),
|
|
55
|
+
/* @__PURE__ */ jsx("p", { className: "mx-auto max-w-xs text-sm text-muted-foreground", children: error })
|
|
56
56
|
] }),
|
|
57
|
-
/* @__PURE__ */ jsx(Button, { variant: "outline", className: "w-full", onClick: reset, children: "Try again" })
|
|
57
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", className: "w-full", onClick: reset, children: retryable ? "Try again" : "Close" })
|
|
58
58
|
] })
|
|
59
59
|
]
|
|
60
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/transaction-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type ReactNode } from \"react\";\nimport { CheckCircle2, Loader2, XCircle } from \"lucide-react\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Button } from \"./button.js\";\nimport { fireConfetti } from \"../utils/media-wallet/confetti.js\";\nimport type { useTransaction } from \"../utils/use-transaction.js\";\n\nexport interface TransactionDialogProps {\n tx: Pick<ReturnType<typeof useTransaction>, \"phase\" | \"error\" | \"reset\"
|
|
1
|
+
{"version":3,"sources":["../../src/components/transaction-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, type ReactNode } from \"react\";\nimport { CheckCircle2, Loader2, XCircle } from \"lucide-react\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Button } from \"./button.js\";\nimport { fireConfetti } from \"../utils/media-wallet/confetti.js\";\nimport type { useTransaction } from \"../utils/use-transaction.js\";\n\nexport interface TransactionDialogProps {\n tx: Pick<ReturnType<typeof useTransaction>, \"phase\" | \"error\" | \"reset\"> & { retryable?: boolean };\n title: string;\n workingLabel: string;\n firstStepLabel?: string;\n children?: ReactNode;\n}\n\nconst ACTIVE_STEP = { preparing: 0, submitting: 1, confirming: 2 } as const;\n\nexport function TransactionDialog({ tx, title, workingLabel, firstStepLabel = \"Prepare\", children }: TransactionDialogProps) {\n const { phase, error, reset, retryable = true } = tx;\n const working = phase === \"preparing\" || phase === \"submitting\" || phase === \"confirming\";\n const success = phase === \"success\";\n const failed = phase === \"error\";\n const steps = [firstStepLabel, \"Submit transaction\", \"Confirm transaction\"];\n\n const confettiFired = useRef(false);\n useEffect(() => {\n if (success && !confettiFired.current) {\n confettiFired.current = true;\n fireConfetti();\n }\n if (!success) confettiFired.current = false;\n }, [success]);\n\n return (\n <Dialog open={phase !== \"idle\"} modal onOpenChange={(open) => { if (!open && !working) reset(); }}>\n <DialogContent\n className=\"sm:max-w-md\"\n onInteractOutside={working ? (e) => e.preventDefault() : undefined}\n onEscapeKeyDown={working ? (e) => e.preventDefault() : undefined}\n {...(working ? { hideClose: true } : {})}\n >\n <DialogTitle className=\"sr-only\">{working ? workingLabel : title}</DialogTitle>\n\n {working && (\n <div className=\"flex flex-col items-center gap-6 py-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-primary/10\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n <div className=\"space-y-1 text-center\">\n <p className=\"text-lg font-semibold\">{workingLabel}</p>\n <p className=\"text-sm text-muted-foreground\">\n {phase === \"confirming\" ? \"Waiting for block confirmation\" : \"Submitting transaction\"}\n </p>\n </div>\n <ol className=\"w-full space-y-2 rounded-xl border border-border/60 bg-muted/30 p-4\">\n {steps.map((label, i) => {\n const active = i === ACTIVE_STEP[phase];\n const done = i < ACTIVE_STEP[phase];\n return (\n <li key={label} data-step aria-current={active ? \"step\" : undefined} className=\"flex items-center gap-3\">\n {done ? (\n <CheckCircle2 className=\"h-4 w-4 shrink-0 text-emerald-500\" />\n ) : active ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin text-primary\" />\n ) : (\n <div className=\"h-4 w-4 shrink-0 rounded-full border-2 border-muted-foreground/30\" />\n )}\n <span className={done ? \"text-sm text-foreground\" : active ? \"text-sm font-medium text-primary\" : \"text-sm text-muted-foreground\"}>\n {label}\n </span>\n </li>\n );\n })}\n </ol>\n <p className=\"text-center text-xs text-muted-foreground\">This usually takes 10–30 seconds. Do not close this window.</p>\n </div>\n )}\n\n {success && children}\n\n {failed && (\n <div className=\"flex flex-col items-center gap-5 py-2\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-destructive/10\">\n <XCircle className=\"h-9 w-9 text-destructive\" />\n </div>\n <div className=\"space-y-1 text-center\">\n <p className=\"text-xl font-bold\">{title}</p>\n <p className=\"mx-auto max-w-xs text-sm text-muted-foreground\">{error}</p>\n </div>\n <Button variant=\"outline\" className=\"w-full\" onClick={reset}>\n {retryable ? \"Try again\" : \"Close\"}\n </Button>\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";AA2CQ,cAOI,YAPJ;AAzCR,SAAS,WAAW,cAA8B;AAClD,SAAS,cAAc,SAAS,eAAe;AAC/C,SAAS,QAAQ,eAAe,mBAAmB;AACnD,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAW7B,MAAM,cAAc,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,EAAE;AAE1D,SAAS,kBAAkB,EAAE,IAAI,OAAO,cAAc,iBAAiB,WAAW,SAAS,GAA2B;AAC3H,QAAM,EAAE,OAAO,OAAO,OAAO,YAAY,KAAK,IAAI;AAClD,QAAM,UAAU,UAAU,eAAe,UAAU,gBAAgB,UAAU;AAC7E,QAAM,UAAU,UAAU;AAC1B,QAAM,SAAS,UAAU;AACzB,QAAM,QAAQ,CAAC,gBAAgB,sBAAsB,qBAAqB;AAE1E,QAAM,gBAAgB,OAAO,KAAK;AAClC,YAAU,MAAM;AACd,QAAI,WAAW,CAAC,cAAc,SAAS;AACrC,oBAAc,UAAU;AACxB,mBAAa;AAAA,IACf;AACA,QAAI,CAAC,QAAS,eAAc,UAAU;AAAA,EACxC,GAAG,CAAC,OAAO,CAAC;AAEZ,SACE,oBAAC,UAAO,MAAM,UAAU,QAAQ,OAAK,MAAC,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,QAAQ,CAAC,QAAS,OAAM;AAAA,EAAG,GAC9F;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,mBAAmB,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI;AAAA,MACzD,iBAAiB,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI;AAAA,MACtD,GAAI,UAAU,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,MAEtC;AAAA,4BAAC,eAAY,WAAU,WAAW,oBAAU,eAAe,OAAM;AAAA,QAEhE,WACC,qBAAC,SAAI,WAAU,yCACb;AAAA,8BAAC,SAAI,WAAU,yEACb,8BAAC,WAAQ,WAAU,qCAAoC,GACzD;AAAA,UACA,qBAAC,SAAI,WAAU,yBACb;AAAA,gCAAC,OAAE,WAAU,yBAAyB,wBAAa;AAAA,YACnD,oBAAC,OAAE,WAAU,iCACV,oBAAU,eAAe,mCAAmC,0BAC/D;AAAA,aACF;AAAA,UACA,oBAAC,QAAG,WAAU,uEACX,gBAAM,IAAI,CAAC,OAAO,MAAM;AACvB,kBAAM,SAAS,MAAM,YAAY,KAAK;AACtC,kBAAM,OAAO,IAAI,YAAY,KAAK;AAClC,mBACE,qBAAC,QAAe,aAAS,MAAC,gBAAc,SAAS,SAAS,QAAW,WAAU,2BAC5E;AAAA,qBACC,oBAAC,gBAAa,WAAU,qCAAoC,IAC1D,SACF,oBAAC,WAAQ,WAAU,8CAA6C,IAEhE,oBAAC,SAAI,WAAU,qEAAoE;AAAA,cAErF,oBAAC,UAAK,WAAW,OAAO,4BAA4B,SAAS,qCAAqC,iCAC/F,iBACH;AAAA,iBAVO,KAWT;AAAA,UAEJ,CAAC,GACH;AAAA,UACA,oBAAC,OAAE,WAAU,6CAA4C,8EAA2D;AAAA,WACtH;AAAA,QAGD,WAAW;AAAA,QAEX,UACC,qBAAC,SAAI,WAAU,yCACb;AAAA,8BAAC,SAAI,WAAU,6EACb,8BAAC,WAAQ,WAAU,4BAA2B,GAChD;AAAA,UACA,qBAAC,SAAI,WAAU,yBACb;AAAA,gCAAC,OAAE,WAAU,qBAAqB,iBAAM;AAAA,YACxC,oBAAC,OAAE,WAAU,kDAAkD,iBAAM;AAAA,aACvE;AAAA,UACA,oBAAC,UAAO,SAAQ,WAAU,WAAU,UAAS,SAAS,OACnD,sBAAY,cAAc,SAC7B;AAAA,WACF;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;","names":[]}
|
|
@@ -26,9 +26,10 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
26
26
|
var import_react = require("react");
|
|
27
27
|
var import_lucide_react = require("lucide-react");
|
|
28
28
|
var import_starknet = require("@medialane/sdk/starknet");
|
|
29
|
+
var import_describe_error = require("../../utils/describe-error.js");
|
|
29
30
|
var import_button = require("../button.js");
|
|
30
31
|
var import_alert = require("../alert.js");
|
|
31
|
-
function ExportKeySection({ loadSealed, unlock
|
|
32
|
+
function ExportKeySection({ loadSealed, unlock }) {
|
|
32
33
|
const [recoveryKey, setRecoveryKey] = (0, import_react.useState)(null);
|
|
33
34
|
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
34
35
|
const [error, setError] = (0, import_react.useState)(null);
|
|
@@ -44,8 +45,7 @@ function ExportKeySection({ loadSealed, unlock, describeError }) {
|
|
|
44
45
|
}
|
|
45
46
|
setRecoveryKey((0, import_starknet.encodeRecoveryKey)({ walletAddress: sealed.address, privateKey: await unlock(sealed) }));
|
|
46
47
|
} catch (err) {
|
|
47
|
-
|
|
48
|
-
setError(describeError ? describeError(err, fallback) : fallback);
|
|
48
|
+
setError((0, import_describe_error.describeError)(err).message);
|
|
49
49
|
} finally {
|
|
50
50
|
setBusy(false);
|
|
51
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/wallet/export-key-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { KeyRound, Copy, Check, EyeOff, Loader2, ShieldAlert } from \"lucide-react\";\nimport { encodeRecoveryKey, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\n\nexport interface ExportKeySectionProps {\n loadSealed: () => SealedOwner | null;\n unlock: (sealed: SealedOwner) => Promise<string>;\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/wallet/export-key-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { KeyRound, Copy, Check, EyeOff, Loader2, ShieldAlert } from \"lucide-react\";\nimport { encodeRecoveryKey, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { Button } from \"../button.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\n\nexport interface ExportKeySectionProps {\n loadSealed: () => SealedOwner | null;\n unlock: (sealed: SealedOwner) => Promise<string>;\n}\n\nexport function ExportKeySection({ loadSealed, unlock }: ExportKeySectionProps) {\n const [recoveryKey, setRecoveryKey] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [copied, setCopied] = useState(false);\n\n const reveal = async () => {\n setBusy(true);\n setError(null);\n try {\n const sealed = loadSealed();\n if (!sealed) {\n setError(\"This browser has no wallet key stored.\");\n return;\n }\n setRecoveryKey(encodeRecoveryKey({ walletAddress: sealed.address, privateKey: await unlock(sealed) }));\n } catch (err) {\n setError(describeError(err).message);\n } finally {\n setBusy(false);\n }\n };\n\n const copy = async () => {\n if (!recoveryKey) return;\n await navigator.clipboard.writeText(recoveryKey);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const hide = () => {\n setRecoveryKey(null);\n setCopied(false);\n };\n\n return (\n <div className=\"flex flex-col gap-3\">\n <div>\n <p className=\"text-sm font-semibold\">Recovery key</p>\n <p className=\"mt-1 text-xs text-muted-foreground leading-relaxed\">\n Save this somewhere private, such as a password manager. Paste it when you sign in on a\n new phone or browser, or if you lose access to every device you use.\n </p>\n </div>\n\n {recoveryKey ? (\n <>\n <Alert variant=\"destructive\">\n <ShieldAlert className=\"h-4 w-4\" />\n <AlertDescription className=\"text-xs leading-relaxed\">\n <span className=\"font-semibold\">Anyone with this key controls your wallet.</span>{\" \"}\n Medialane will never ask you for it. Treat any message requesting it as an attempt to\n take your assets.\n </AlertDescription>\n </Alert>\n <code className=\"block break-all rounded-xl bg-muted px-3 py-2.5 font-mono text-xs select-all\">\n {recoveryKey}\n </code>\n <div className=\"flex items-center gap-2\">\n <Button onClick={copy} variant=\"outline\" size=\"sm\">\n {copied ? <Check className=\"mr-1.5 h-3.5 w-3.5\" /> : <Copy className=\"mr-1.5 h-3.5 w-3.5\" />}\n {copied ? \"Copied\" : \"Copy key\"}\n </Button>\n <Button onClick={hide} variant=\"ghost\" size=\"sm\">\n <EyeOff className=\"mr-1.5 h-3.5 w-3.5\" />\n Hide\n </Button>\n </div>\n </>\n ) : (\n <>\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <Button onClick={reveal} disabled={busy} variant=\"outline\" size=\"sm\" className=\"self-start\">\n {busy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : <KeyRound className=\"mr-1.5 h-3.5 w-3.5\" />}\n Show recovery key\n </Button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmDM;AAjDN,mBAAyB;AACzB,0BAAoE;AACpE,sBAAoD;AACpD,4BAA8B;AAC9B,oBAAuB;AACvB,mBAAwC;AAOjC,SAAS,iBAAiB,EAAE,YAAY,OAAO,GAA0B;AAC9E,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAwB,IAAI;AAClE,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AACtD,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAE1C,QAAM,SAAS,YAAY;AACzB,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,WAAW;AAC1B,UAAI,CAAC,QAAQ;AACX,iBAAS,wCAAwC;AACjD;AAAA,MACF;AACA,yBAAe,mCAAkB,EAAE,eAAe,OAAO,SAAS,YAAY,MAAM,OAAO,MAAM,EAAE,CAAC,CAAC;AAAA,IACvG,SAAS,KAAK;AACZ,mBAAS,qCAAc,GAAG,EAAE,OAAO;AAAA,IACrC,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,QAAM,OAAO,YAAY;AACvB,QAAI,CAAC,YAAa;AAClB,UAAM,UAAU,UAAU,UAAU,WAAW;AAC/C,cAAU,IAAI;AACd,eAAW,MAAM,UAAU,KAAK,GAAG,GAAI;AAAA,EACzC;AAEA,QAAM,OAAO,MAAM;AACjB,mBAAe,IAAI;AACnB,cAAU,KAAK;AAAA,EACjB;AAEA,SACE,6CAAC,SAAI,WAAU,uBACb;AAAA,iDAAC,SACC;AAAA,kDAAC,OAAE,WAAU,yBAAwB,0BAAY;AAAA,MACjD,4CAAC,OAAE,WAAU,sDAAqD,0KAGlE;AAAA,OACF;AAAA,IAEC,cACC,4EACE;AAAA,mDAAC,sBAAM,SAAQ,eACb;AAAA,oDAAC,mCAAY,WAAU,WAAU;AAAA,QACjC,6CAAC,iCAAiB,WAAU,2BAC1B;AAAA,sDAAC,UAAK,WAAU,iBAAgB,wDAA0C;AAAA,UAAQ;AAAA,UAAI;AAAA,WAGxF;AAAA,SACF;AAAA,MACA,4CAAC,UAAK,WAAU,gFACb,uBACH;AAAA,MACA,6CAAC,SAAI,WAAU,2BACb;AAAA,qDAAC,wBAAO,SAAS,MAAM,SAAQ,WAAU,MAAK,MAC3C;AAAA,mBAAS,4CAAC,6BAAM,WAAU,sBAAqB,IAAK,4CAAC,4BAAK,WAAU,sBAAqB;AAAA,UACzF,SAAS,WAAW;AAAA,WACvB;AAAA,QACA,6CAAC,wBAAO,SAAS,MAAM,SAAQ,SAAQ,MAAK,MAC1C;AAAA,sDAAC,8BAAO,WAAU,sBAAqB;AAAA,UAAE;AAAA,WAE3C;AAAA,SACF;AAAA,OACF,IAEA,4EACG;AAAA,eAAS,4CAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MACzD,6CAAC,wBAAO,SAAS,QAAQ,UAAU,MAAM,SAAQ,WAAU,MAAK,MAAK,WAAU,cAC5E;AAAA,eAAO,4CAAC,+BAAQ,WAAU,mCAAkC,IAAK,4CAAC,gCAAS,WAAU,sBAAqB;AAAA,QAAG;AAAA,SAEhH;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -4,8 +4,7 @@ import { SealedOwner } from '@medialane/sdk/starknet';
|
|
|
4
4
|
interface ExportKeySectionProps {
|
|
5
5
|
loadSealed: () => SealedOwner | null;
|
|
6
6
|
unlock: (sealed: SealedOwner) => Promise<string>;
|
|
7
|
-
describeError?: (err: unknown, fallback: string) => string;
|
|
8
7
|
}
|
|
9
|
-
declare function ExportKeySection({ loadSealed, unlock
|
|
8
|
+
declare function ExportKeySection({ loadSealed, unlock }: ExportKeySectionProps): react_jsx_runtime.JSX.Element;
|
|
10
9
|
|
|
11
10
|
export { ExportKeySection, type ExportKeySectionProps };
|
|
@@ -4,8 +4,7 @@ import { SealedOwner } from '@medialane/sdk/starknet';
|
|
|
4
4
|
interface ExportKeySectionProps {
|
|
5
5
|
loadSealed: () => SealedOwner | null;
|
|
6
6
|
unlock: (sealed: SealedOwner) => Promise<string>;
|
|
7
|
-
describeError?: (err: unknown, fallback: string) => string;
|
|
8
7
|
}
|
|
9
|
-
declare function ExportKeySection({ loadSealed, unlock
|
|
8
|
+
declare function ExportKeySection({ loadSealed, unlock }: ExportKeySectionProps): react_jsx_runtime.JSX.Element;
|
|
10
9
|
|
|
11
10
|
export { ExportKeySection, type ExportKeySectionProps };
|
|
@@ -3,9 +3,10 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { KeyRound, Copy, Check, EyeOff, Loader2, ShieldAlert } from "lucide-react";
|
|
5
5
|
import { encodeRecoveryKey } from "@medialane/sdk/starknet";
|
|
6
|
+
import { describeError } from "../../utils/describe-error.js";
|
|
6
7
|
import { Button } from "../button.js";
|
|
7
8
|
import { Alert, AlertDescription } from "../alert.js";
|
|
8
|
-
function ExportKeySection({ loadSealed, unlock
|
|
9
|
+
function ExportKeySection({ loadSealed, unlock }) {
|
|
9
10
|
const [recoveryKey, setRecoveryKey] = useState(null);
|
|
10
11
|
const [busy, setBusy] = useState(false);
|
|
11
12
|
const [error, setError] = useState(null);
|
|
@@ -21,8 +22,7 @@ function ExportKeySection({ loadSealed, unlock, describeError }) {
|
|
|
21
22
|
}
|
|
22
23
|
setRecoveryKey(encodeRecoveryKey({ walletAddress: sealed.address, privateKey: await unlock(sealed) }));
|
|
23
24
|
} catch (err) {
|
|
24
|
-
|
|
25
|
-
setError(describeError ? describeError(err, fallback) : fallback);
|
|
25
|
+
setError(describeError(err).message);
|
|
26
26
|
} finally {
|
|
27
27
|
setBusy(false);
|
|
28
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/wallet/export-key-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { KeyRound, Copy, Check, EyeOff, Loader2, ShieldAlert } from \"lucide-react\";\nimport { encodeRecoveryKey, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\n\nexport interface ExportKeySectionProps {\n loadSealed: () => SealedOwner | null;\n unlock: (sealed: SealedOwner) => Promise<string>;\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/wallet/export-key-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { KeyRound, Copy, Check, EyeOff, Loader2, ShieldAlert } from \"lucide-react\";\nimport { encodeRecoveryKey, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { Button } from \"../button.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\n\nexport interface ExportKeySectionProps {\n loadSealed: () => SealedOwner | null;\n unlock: (sealed: SealedOwner) => Promise<string>;\n}\n\nexport function ExportKeySection({ loadSealed, unlock }: ExportKeySectionProps) {\n const [recoveryKey, setRecoveryKey] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [copied, setCopied] = useState(false);\n\n const reveal = async () => {\n setBusy(true);\n setError(null);\n try {\n const sealed = loadSealed();\n if (!sealed) {\n setError(\"This browser has no wallet key stored.\");\n return;\n }\n setRecoveryKey(encodeRecoveryKey({ walletAddress: sealed.address, privateKey: await unlock(sealed) }));\n } catch (err) {\n setError(describeError(err).message);\n } finally {\n setBusy(false);\n }\n };\n\n const copy = async () => {\n if (!recoveryKey) return;\n await navigator.clipboard.writeText(recoveryKey);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const hide = () => {\n setRecoveryKey(null);\n setCopied(false);\n };\n\n return (\n <div className=\"flex flex-col gap-3\">\n <div>\n <p className=\"text-sm font-semibold\">Recovery key</p>\n <p className=\"mt-1 text-xs text-muted-foreground leading-relaxed\">\n Save this somewhere private, such as a password manager. Paste it when you sign in on a\n new phone or browser, or if you lose access to every device you use.\n </p>\n </div>\n\n {recoveryKey ? (\n <>\n <Alert variant=\"destructive\">\n <ShieldAlert className=\"h-4 w-4\" />\n <AlertDescription className=\"text-xs leading-relaxed\">\n <span className=\"font-semibold\">Anyone with this key controls your wallet.</span>{\" \"}\n Medialane will never ask you for it. Treat any message requesting it as an attempt to\n take your assets.\n </AlertDescription>\n </Alert>\n <code className=\"block break-all rounded-xl bg-muted px-3 py-2.5 font-mono text-xs select-all\">\n {recoveryKey}\n </code>\n <div className=\"flex items-center gap-2\">\n <Button onClick={copy} variant=\"outline\" size=\"sm\">\n {copied ? <Check className=\"mr-1.5 h-3.5 w-3.5\" /> : <Copy className=\"mr-1.5 h-3.5 w-3.5\" />}\n {copied ? \"Copied\" : \"Copy key\"}\n </Button>\n <Button onClick={hide} variant=\"ghost\" size=\"sm\">\n <EyeOff className=\"mr-1.5 h-3.5 w-3.5\" />\n Hide\n </Button>\n </div>\n </>\n ) : (\n <>\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <Button onClick={reveal} disabled={busy} variant=\"outline\" size=\"sm\" className=\"self-start\">\n {busy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : <KeyRound className=\"mr-1.5 h-3.5 w-3.5\" />}\n Show recovery key\n </Button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";AAmDM,SASE,UARA,KADF;AAjDN,SAAS,gBAAgB;AACzB,SAAS,UAAU,MAAM,OAAO,QAAQ,SAAS,mBAAmB;AACpE,SAAS,yBAA2C;AACpD,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AACvB,SAAS,OAAO,wBAAwB;AAOjC,SAAS,iBAAiB,EAAE,YAAY,OAAO,GAA0B;AAC9E,QAAM,CAAC,aAAa,cAAc,IAAI,SAAwB,IAAI;AAClE,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAE1C,QAAM,SAAS,YAAY;AACzB,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,WAAW;AAC1B,UAAI,CAAC,QAAQ;AACX,iBAAS,wCAAwC;AACjD;AAAA,MACF;AACA,qBAAe,kBAAkB,EAAE,eAAe,OAAO,SAAS,YAAY,MAAM,OAAO,MAAM,EAAE,CAAC,CAAC;AAAA,IACvG,SAAS,KAAK;AACZ,eAAS,cAAc,GAAG,EAAE,OAAO;AAAA,IACrC,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,QAAM,OAAO,YAAY;AACvB,QAAI,CAAC,YAAa;AAClB,UAAM,UAAU,UAAU,UAAU,WAAW;AAC/C,cAAU,IAAI;AACd,eAAW,MAAM,UAAU,KAAK,GAAG,GAAI;AAAA,EACzC;AAEA,QAAM,OAAO,MAAM;AACjB,mBAAe,IAAI;AACnB,cAAU,KAAK;AAAA,EACjB;AAEA,SACE,qBAAC,SAAI,WAAU,uBACb;AAAA,yBAAC,SACC;AAAA,0BAAC,OAAE,WAAU,yBAAwB,0BAAY;AAAA,MACjD,oBAAC,OAAE,WAAU,sDAAqD,0KAGlE;AAAA,OACF;AAAA,IAEC,cACC,iCACE;AAAA,2BAAC,SAAM,SAAQ,eACb;AAAA,4BAAC,eAAY,WAAU,WAAU;AAAA,QACjC,qBAAC,oBAAiB,WAAU,2BAC1B;AAAA,8BAAC,UAAK,WAAU,iBAAgB,wDAA0C;AAAA,UAAQ;AAAA,UAAI;AAAA,WAGxF;AAAA,SACF;AAAA,MACA,oBAAC,UAAK,WAAU,gFACb,uBACH;AAAA,MACA,qBAAC,SAAI,WAAU,2BACb;AAAA,6BAAC,UAAO,SAAS,MAAM,SAAQ,WAAU,MAAK,MAC3C;AAAA,mBAAS,oBAAC,SAAM,WAAU,sBAAqB,IAAK,oBAAC,QAAK,WAAU,sBAAqB;AAAA,UACzF,SAAS,WAAW;AAAA,WACvB;AAAA,QACA,qBAAC,UAAO,SAAS,MAAM,SAAQ,SAAQ,MAAK,MAC1C;AAAA,8BAAC,UAAO,WAAU,sBAAqB;AAAA,UAAE;AAAA,WAE3C;AAAA,SACF;AAAA,OACF,IAEA,iCACG;AAAA,eAAS,oBAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MACzD,qBAAC,UAAO,SAAS,QAAQ,UAAU,MAAM,SAAQ,WAAU,MAAK,MAAK,WAAU,cAC5E;AAAA,eAAO,oBAAC,WAAQ,WAAU,mCAAkC,IAAK,oBAAC,YAAS,WAAU,sBAAqB;AAAA,QAAG;AAAA,SAEhH;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -200,7 +200,6 @@ __export(index_exports, {
|
|
|
200
200
|
FormMessage: () => import_form.FormMessage,
|
|
201
201
|
GATED_CONTENT_TYPES: () => import_gated_content_types.GATED_CONTENT_TYPES,
|
|
202
202
|
GATED_CONTENT_TYPE_FALLBACK: () => import_gated_content_types.GATED_CONTENT_TYPE_FALLBACK,
|
|
203
|
-
GENERIC: () => import_describe_error.GENERIC,
|
|
204
203
|
GEOGRAPHIC_SCOPES: () => import_ip.GEOGRAPHIC_SCOPES,
|
|
205
204
|
GatedContentHero: () => import_gated_content.GatedContentHero,
|
|
206
205
|
GatedContentPanel: () => import_gated_content.GatedContentPanel,
|
|
@@ -1032,7 +1031,6 @@ var import_asset_accents = require("./utils/asset-accents.js");
|
|
|
1032
1031
|
FormMessage,
|
|
1033
1032
|
GATED_CONTENT_TYPES,
|
|
1034
1033
|
GATED_CONTENT_TYPE_FALLBACK,
|
|
1035
|
-
GENERIC,
|
|
1036
1034
|
GEOGRAPHIC_SCOPES,
|
|
1037
1035
|
GatedContentHero,
|
|
1038
1036
|
GatedContentPanel,
|