@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.
Files changed (107) hide show
  1. package/dist/components/account/add-guardian-dialog.cjs +1 -1
  2. package/dist/components/account/add-guardian-dialog.cjs.map +1 -1
  3. package/dist/components/account/add-guardian-dialog.js +1 -1
  4. package/dist/components/account/add-guardian-dialog.js.map +1 -1
  5. package/dist/components/account/device-approval-dialog.cjs +2 -2
  6. package/dist/components/account/device-approval-dialog.cjs.map +1 -1
  7. package/dist/components/account/device-approval-dialog.js +2 -2
  8. package/dist/components/account/device-approval-dialog.js.map +1 -1
  9. package/dist/components/account/devices-section.cjs +1 -1
  10. package/dist/components/account/devices-section.cjs.map +1 -1
  11. package/dist/components/account/devices-section.js +1 -1
  12. package/dist/components/account/devices-section.js.map +1 -1
  13. package/dist/components/account/guardian-recovery-section.cjs +1 -1
  14. package/dist/components/account/guardian-recovery-section.cjs.map +1 -1
  15. package/dist/components/account/guardian-recovery-section.js +1 -1
  16. package/dist/components/account/guardian-recovery-section.js.map +1 -1
  17. package/dist/components/account/input-otp.d.cts +2 -2
  18. package/dist/components/account/input-otp.d.ts +2 -2
  19. package/dist/components/asset-page.cjs +8 -7
  20. package/dist/components/asset-page.cjs.map +1 -1
  21. package/dist/components/asset-page.js +8 -7
  22. package/dist/components/asset-page.js.map +1 -1
  23. package/dist/components/asset-publication.cjs +1 -3
  24. package/dist/components/asset-publication.cjs.map +1 -1
  25. package/dist/components/asset-publication.js +1 -3
  26. package/dist/components/asset-publication.js.map +1 -1
  27. package/dist/components/button.d.cts +2 -2
  28. package/dist/components/button.d.ts +2 -2
  29. package/dist/components/drop/create/launch-dialog.cjs +1 -1
  30. package/dist/components/drop/create/launch-dialog.cjs.map +1 -1
  31. package/dist/components/drop/create/launch-dialog.js +1 -1
  32. package/dist/components/drop/create/launch-dialog.js.map +1 -1
  33. package/dist/components/drop/page/drop-manage.cjs +1 -1
  34. package/dist/components/drop/page/drop-manage.cjs.map +1 -1
  35. package/dist/components/drop/page/drop-manage.js +1 -1
  36. package/dist/components/drop/page/drop-manage.js.map +1 -1
  37. package/dist/components/drop/page/drop-mint-dialog.cjs +1 -1
  38. package/dist/components/drop/page/drop-mint-dialog.cjs.map +1 -1
  39. package/dist/components/drop/page/drop-mint-dialog.js +1 -1
  40. package/dist/components/drop/page/drop-mint-dialog.js.map +1 -1
  41. package/dist/components/empty-or-error.cjs +2 -2
  42. package/dist/components/empty-or-error.cjs.map +1 -1
  43. package/dist/components/empty-or-error.js +2 -2
  44. package/dist/components/empty-or-error.js.map +1 -1
  45. package/dist/components/fast-mint/fast-mint.cjs +2 -1
  46. package/dist/components/fast-mint/fast-mint.cjs.map +1 -1
  47. package/dist/components/fast-mint/fast-mint.d.cts +2 -2
  48. package/dist/components/fast-mint/fast-mint.d.ts +2 -2
  49. package/dist/components/fast-mint/fast-mint.js +2 -1
  50. package/dist/components/fast-mint/fast-mint.js.map +1 -1
  51. package/dist/components/launchpad/edition-mint-schema.d.cts +2 -2
  52. package/dist/components/launchpad/edition-mint-schema.d.ts +2 -2
  53. package/dist/components/license-request-page.cjs +1 -1
  54. package/dist/components/license-request-page.cjs.map +1 -1
  55. package/dist/components/license-request-page.js +1 -1
  56. package/dist/components/license-request-page.js.map +1 -1
  57. package/dist/components/media-wallet/activate-card.cjs +1 -1
  58. package/dist/components/media-wallet/activate-card.cjs.map +1 -1
  59. package/dist/components/media-wallet/activate-card.js +1 -1
  60. package/dist/components/media-wallet/activate-card.js.map +1 -1
  61. package/dist/components/media-wallet/media-wallet-activity.cjs +1 -1
  62. package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -1
  63. package/dist/components/media-wallet/media-wallet-activity.js +1 -1
  64. package/dist/components/media-wallet/media-wallet-activity.js.map +1 -1
  65. package/dist/components/media-wallet/media-wallet-send.cjs +2 -6
  66. package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
  67. package/dist/components/media-wallet/media-wallet-send.js +2 -6
  68. package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
  69. package/dist/components/sheet.d.cts +1 -1
  70. package/dist/components/sheet.d.ts +1 -1
  71. package/dist/components/transaction-dialog.cjs +4 -4
  72. package/dist/components/transaction-dialog.cjs.map +1 -1
  73. package/dist/components/transaction-dialog.d.cts +3 -1
  74. package/dist/components/transaction-dialog.d.ts +3 -1
  75. package/dist/components/transaction-dialog.js +4 -4
  76. package/dist/components/transaction-dialog.js.map +1 -1
  77. package/dist/components/wallet/export-key-section.cjs +3 -3
  78. package/dist/components/wallet/export-key-section.cjs.map +1 -1
  79. package/dist/components/wallet/export-key-section.d.cts +1 -2
  80. package/dist/components/wallet/export-key-section.d.ts +1 -2
  81. package/dist/components/wallet/export-key-section.js +3 -3
  82. package/dist/components/wallet/export-key-section.js.map +1 -1
  83. package/dist/index.cjs +0 -2
  84. package/dist/index.cjs.map +1 -1
  85. package/dist/index.d.cts +1 -1
  86. package/dist/index.d.ts +1 -1
  87. package/dist/index.js +0 -2
  88. package/dist/index.js.map +1 -1
  89. package/dist/utils/describe-error.cjs +16 -11
  90. package/dist/utils/describe-error.cjs.map +1 -1
  91. package/dist/utils/describe-error.d.cts +4 -4
  92. package/dist/utils/describe-error.d.ts +4 -4
  93. package/dist/utils/describe-error.js +16 -10
  94. package/dist/utils/describe-error.js.map +1 -1
  95. package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
  96. package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
  97. package/dist/utils/use-email-code.cjs +2 -2
  98. package/dist/utils/use-email-code.cjs.map +1 -1
  99. package/dist/utils/use-email-code.js +2 -2
  100. package/dist/utils/use-email-code.js.map +1 -1
  101. package/dist/utils/use-transaction.cjs +16 -2
  102. package/dist/utils/use-transaction.cjs.map +1 -1
  103. package/dist/utils/use-transaction.d.cts +1 -0
  104. package/dist/utils/use-transaction.d.ts +1 -0
  105. package/dist/utils/use-transaction.js +17 -3
  106. package/dist/utils/use-transaction.js.map +1 -1
  107. 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?: "left" | "right" | "bottom" | "top" | null | undefined;
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?: "left" | "right" | "bottom" | "top" | null | undefined;
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: "Something went wrong" }),
78
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mx-auto max-w-xs text-sm text-muted-foreground", children: error ?? "We couldn't complete that. Please try again." })
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\">;\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 } = 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\">Something went wrong</p>\n <p className=\"mx-auto max-w-xs text-sm text-muted-foreground\">{error ?? \"We couldn't complete that. Please try again.\"}</p>\n </div>\n <Button variant=\"outline\" className=\"w-full\" onClick={reset}>\n Try again\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,MAAM,IAAI;AAChC,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,qBAAoB,kCAAoB;AAAA,YACrD,4CAAC,OAAE,WAAU,kDAAkD,mBAAS,gDAA+C;AAAA,aACzH;AAAA,UACA,4CAAC,wBAAO,SAAQ,WAAU,WAAU,UAAS,SAAS,OAAO,uBAE7D;AAAA,WACF;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;","names":[]}
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: "Something went wrong" }),
55
- /* @__PURE__ */ jsx("p", { className: "mx-auto max-w-xs text-sm text-muted-foreground", children: error ?? "We couldn't complete that. Please try again." })
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\">;\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 } = 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\">Something went wrong</p>\n <p className=\"mx-auto max-w-xs text-sm text-muted-foreground\">{error ?? \"We couldn't complete that. Please try again.\"}</p>\n </div>\n <Button variant=\"outline\" className=\"w-full\" onClick={reset}>\n Try again\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,MAAM,IAAI;AAChC,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,qBAAoB,kCAAoB;AAAA,YACrD,oBAAC,OAAE,WAAU,kDAAkD,mBAAS,gDAA+C;AAAA,aACzH;AAAA,UACA,oBAAC,UAAO,SAAQ,WAAU,WAAU,UAAS,SAAS,OAAO,uBAE7D;AAAA,WACF;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;","names":[]}
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, describeError }) {
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
- const fallback = "Could not unlock your key. Please try again.";
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 describeError?: (err: unknown, fallback: string) => string;\n}\n\nexport function ExportKeySection({ loadSealed, unlock, describeError }: 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 const fallback = \"Could not unlock your key. Please try again.\";\n setError(describeError ? describeError(err, fallback) : fallback);\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;AAoDM;AAlDN,mBAAyB;AACzB,0BAAoE;AACpE,sBAAoD;AACpD,oBAAuB;AACvB,mBAAwC;AAQjC,SAAS,iBAAiB,EAAE,YAAY,QAAQ,cAAc,GAA0B;AAC7F,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,YAAM,WAAW;AACjB,eAAS,gBAAgB,cAAc,KAAK,QAAQ,IAAI,QAAQ;AAAA,IAClE,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":[]}
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, describeError }: ExportKeySectionProps): react_jsx_runtime.JSX.Element;
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, describeError }: ExportKeySectionProps): react_jsx_runtime.JSX.Element;
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, describeError }) {
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
- const fallback = "Could not unlock your key. Please try again.";
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 describeError?: (err: unknown, fallback: string) => string;\n}\n\nexport function ExportKeySection({ loadSealed, unlock, describeError }: 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 const fallback = \"Could not unlock your key. Please try again.\";\n setError(describeError ? describeError(err, fallback) : fallback);\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":";AAoDM,SASE,UARA,KADF;AAlDN,SAAS,gBAAgB;AACzB,SAAS,UAAU,MAAM,OAAO,QAAQ,SAAS,mBAAmB;AACpE,SAAS,yBAA2C;AACpD,SAAS,cAAc;AACvB,SAAS,OAAO,wBAAwB;AAQjC,SAAS,iBAAiB,EAAE,YAAY,QAAQ,cAAc,GAA0B;AAC7F,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,YAAM,WAAW;AACjB,eAAS,gBAAgB,cAAc,KAAK,QAAQ,IAAI,QAAQ;AAAA,IAClE,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":[]}
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,