{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "send-bsv",
  "title": "Send BSV",
  "author": "Satchmo",
  "description": "Complete send BSV block with trigger variants (default, compact, quick) and a dialog form with sats/BSV toggle, fee estimate, and confirmation flow",
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "badge",
    "button",
    "dialog",
    "input",
    "label",
    "separator"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/send-bsv/index.tsx",
      "content": "\"use client\"\n\nimport { useCallback, useState } from \"react\"\nimport {\n  SendBsvTrigger,\n  type SendBsvTriggerProps,\n  type SendBsvTriggerVariant,\n} from \"./send-bsv-trigger\"\nimport {\n  SendBsvDialog,\n  type SendBsvDialogProps,\n  type SendBsvParams,\n  type SendBsvResult,\n} from \"./send-bsv-dialog\"\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport {\n  SendBsvTrigger,\n  type SendBsvTriggerProps,\n  type SendBsvTriggerVariant,\n} from \"./send-bsv-trigger\"\nexport {\n  SendBsvDialog,\n  type SendBsvDialogProps,\n  type SendBsvParams,\n  type SendBsvResult,\n} from \"./send-bsv-dialog\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SendBsvProps {\n  /** Trigger variant */\n  variant?: SendBsvTriggerVariant\n  /** Dialog size variant */\n  dialogSize?: \"full\" | \"compact\"\n  /** Callback to execute the send action */\n  onSend: (params: SendBsvParams) => Promise<SendBsvResult>\n  /** Callback on successful send */\n  onSuccess?: (result: SendBsvResult) => void\n  /** Callback on error */\n  onError?: (error: Error) => void\n  /** Pre-filled destination address */\n  defaultAddress?: string\n  /** Pre-filled amount in satoshis */\n  defaultSatoshis?: number\n  /** Estimated fee in satoshis (default: 50) */\n  estimatedFee?: number\n  /** Label for the trigger button */\n  triggerLabel?: string\n  /** Whether the trigger is disabled */\n  disabled?: boolean\n  /** Optional CSS class for the trigger */\n  className?: string\n  /** Optional CSS class for the dialog content */\n  dialogClassName?: string\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * Full Send BSV block: a trigger button that opens a send dialog.\n *\n * Wraps `SendBsvTrigger` and `SendBsvDialog` into one component.\n * The `onSend` callback receives `{ address, satoshis }` and should\n * call `@1sat/actions` `sendBsv.execute(ctx, { requests: [{ address, satoshis }] })`.\n *\n * @example\n * ```tsx\n * import { SendBsv } from \"@/components/blocks/send-bsv\"\n *\n * <SendBsv\n *   onSend={async ({ address, satoshis }) => {\n *     const result = await sendBsv.execute(ctx, {\n *       requests: [{ address, satoshis }],\n *     })\n *     return result\n *   }}\n * />\n * ```\n */\nexport function SendBsv({\n  variant = \"default\",\n  dialogSize = \"full\",\n  onSend,\n  onSuccess,\n  onError,\n  defaultAddress = \"\",\n  defaultSatoshis,\n  estimatedFee,\n  triggerLabel,\n  disabled = false,\n  className,\n  dialogClassName,\n}: SendBsvProps) {\n  const [dialogOpen, setDialogOpen] = useState(false)\n  const [isSending, setIsSending] = useState(false)\n\n  // Quick-send state for the \"quick\" variant\n  const [quickAmount, setQuickAmount] = useState(\"\")\n\n  const handleOpenDialog = useCallback(() => {\n    setDialogOpen(true)\n  }, [])\n\n  const wrappedOnSend = useCallback(\n    async (params: SendBsvParams): Promise<SendBsvResult> => {\n      setIsSending(true)\n      try {\n        const result = await onSend(params)\n        return result\n      } finally {\n        setIsSending(false)\n      }\n    },\n    [onSend],\n  )\n\n  const handleQuickSend = useCallback(() => {\n    const sats = Number.parseInt(quickAmount, 10)\n    if (Number.isNaN(sats) || sats <= 0) return\n    // Open dialog with the quick amount pre-filled\n    setDialogOpen(true)\n  }, [quickAmount])\n\n  const quickSatoshis =\n    variant === \"quick\" && quickAmount\n      ? Number.parseInt(quickAmount, 10) || undefined\n      : defaultSatoshis\n\n  return (\n    <>\n      <SendBsvTrigger\n        variant={variant}\n        className={className}\n        label={triggerLabel}\n        disabled={disabled}\n        loading={isSending}\n        onClick={handleOpenDialog}\n        quickAmount={quickAmount}\n        onQuickAmountChange={setQuickAmount}\n        onQuickSend={handleQuickSend}\n      />\n\n      <SendBsvDialog\n        open={dialogOpen}\n        onOpenChange={setDialogOpen}\n        onSend={wrappedOnSend}\n        onSuccess={onSuccess}\n        onError={onError}\n        defaultAddress={defaultAddress}\n        defaultSatoshis={quickSatoshis}\n        estimatedFee={estimatedFee}\n        size={dialogSize}\n        className={dialogClassName}\n      />\n    </>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/send-bsv/index.tsx"
    },
    {
      "path": "registry/new-york/blocks/send-bsv/send-bsv-trigger.tsx",
      "content": "\"use client\"\n\nimport { forwardRef } from \"react\"\nimport { ArrowUpRight, Loader2, Send } from \"lucide-react\"\nimport { Button } from \"@/components/ui/button\"\nimport { Input } from \"@/components/ui/input\"\nimport { cn } from \"@/lib/utils\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type SendBsvTriggerVariant = \"default\" | \"compact\" | \"quick\"\n\nexport interface SendBsvTriggerProps {\n  /** Trigger style variant */\n  variant?: SendBsvTriggerVariant\n  /** Additional CSS classes */\n  className?: string\n  /** Label for the default variant button (default: \"Send BSV\") */\n  label?: string\n  /** Whether the trigger is disabled */\n  disabled?: boolean\n  /** Whether a send operation is in progress */\n  loading?: boolean\n  /** Click handler to open the dialog */\n  onClick?: () => void\n  /** For the quick variant: current amount input value */\n  quickAmount?: string\n  /** For the quick variant: handler when amount changes */\n  onQuickAmountChange?: (value: string) => void\n  /** For the quick variant: handler when inline send is triggered */\n  onQuickSend?: () => void\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * Trigger button for the Send BSV dialog.\n *\n * Three variants:\n * - **default**: Button with send icon and label\n * - **compact**: Icon-only square button\n * - **quick**: Inline amount input with send button\n */\nexport const SendBsvTrigger = forwardRef<HTMLButtonElement, SendBsvTriggerProps>(\n  function SendBsvTrigger(\n    {\n      variant = \"default\",\n      className,\n      label = \"Send BSV\",\n      disabled = false,\n      loading = false,\n      onClick,\n      quickAmount = \"\",\n      onQuickAmountChange,\n      onQuickSend,\n    },\n    ref,\n  ) {\n    if (variant === \"compact\") {\n      return (\n        <Button\n          ref={ref}\n          variant=\"outline\"\n          size=\"icon\"\n          className={cn(\"size-9\", className)}\n          disabled={disabled || loading}\n          onClick={onClick}\n          aria-label={label}\n          aria-busy={loading}\n        >\n          {loading ? (\n            <Loader2 className=\"animate-spin\" aria-hidden=\"true\" data-icon=\"inline-start\" />\n          ) : (\n            <ArrowUpRight aria-hidden=\"true\" data-icon=\"inline-start\" />\n          )}\n        </Button>\n      )\n    }\n\n    if (variant === \"quick\") {\n      return (\n        <div\n          className={cn(\n            \"flex items-center gap-2 rounded-md border bg-background p-1\",\n            className,\n          )}\n        >\n          <Input\n            type=\"text\"\n            inputMode=\"numeric\"\n            pattern=\"[0-9]*\"\n            placeholder=\"sats\"\n            value={quickAmount}\n            onChange={(e) =>\n              onQuickAmountChange?.(e.target.value.replace(/[^0-9]/g, \"\"))\n            }\n            disabled={disabled || loading}\n            className=\"h-7 w-24 border-0 bg-transparent px-2 text-sm shadow-none focus-visible:ring-0\"\n            aria-label=\"Amount in satoshis\"\n          />\n          <Button\n            ref={ref}\n            size=\"sm\"\n            className=\"h-7 gap-1.5 px-3 text-xs\"\n            disabled={disabled || loading || !quickAmount}\n            onClick={onQuickSend ?? onClick}\n            aria-busy={loading}\n          >\n            {loading ? (\n              <Loader2\n                className=\"animate-spin\"\n                aria-hidden=\"true\"\n                data-icon=\"inline-start\"\n              />\n            ) : (\n              <Send aria-hidden=\"true\" data-icon=\"inline-start\" />\n            )}\n            Send\n          </Button>\n        </div>\n      )\n    }\n\n    // Default variant\n    return (\n      <Button\n        ref={ref}\n        className={cn(\"gap-2\", className)}\n        disabled={disabled || loading}\n        onClick={onClick}\n        aria-busy={loading}\n      >\n        {loading ? (\n          <Loader2 className=\"animate-spin\" aria-hidden=\"true\" data-icon=\"inline-start\" />\n        ) : (\n          <Send aria-hidden=\"true\" data-icon=\"inline-start\" />\n        )}\n        {label}\n      </Button>\n    )\n  },\n)\n",
      "type": "registry:component",
      "target": "~/components/blocks/send-bsv/send-bsv-trigger.tsx"
    },
    {
      "path": "registry/new-york/blocks/send-bsv/send-bsv-dialog.tsx",
      "content": "\"use client\"\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\"\nimport {\n  AlertCircle,\n  ArrowDownUp,\n  CheckCircle2,\n  Loader2,\n} from \"lucide-react\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n} from \"@/components/ui/dialog\"\nimport { Input } from \"@/components/ui/input\"\nimport { Label } from \"@/components/ui/label\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { cn } from \"@/lib/utils\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SendBsvParams {\n  /** Destination BSV address */\n  address: string\n  /** Amount in satoshis */\n  satoshis: number\n}\n\nexport interface SendBsvResult {\n  /** Transaction ID on success */\n  txid?: string\n  /** Raw transaction hex */\n  rawtx?: string\n  /** Error message on failure */\n  error?: string\n}\n\ntype AmountUnit = \"sats\" | \"bsv\"\n\nexport interface SendBsvDialogProps {\n  /** Whether the dialog is open */\n  open: boolean\n  /** Callback when the open state changes */\n  onOpenChange: (open: boolean) => void\n  /** Callback to execute the send action */\n  onSend: (params: SendBsvParams) => Promise<SendBsvResult>\n  /** Callback on successful send */\n  onSuccess?: (result: SendBsvResult) => void\n  /** Callback on error */\n  onError?: (error: Error) => void\n  /** Pre-filled destination address */\n  defaultAddress?: string\n  /** Pre-filled amount in satoshis */\n  defaultSatoshis?: number\n  /** Estimated fee in satoshis (default: 50) */\n  estimatedFee?: number\n  /** Dialog size variant */\n  size?: \"full\" | \"compact\"\n  /** Optional CSS class for the dialog content */\n  className?: string\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst SATS_PER_BSV = 100_000_000\nconst MIN_AMOUNT_SATS = 1\nconst MAX_AMOUNT_SATS = 2100000000000000\nconst DEFAULT_FEE_SATS = 50\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction satsToBsvString(sats: number): string {\n  return (sats / SATS_PER_BSV).toFixed(8)\n}\n\nfunction bsvStringToSats(bsvStr: string): number {\n  const parsed = Number.parseFloat(bsvStr)\n  if (Number.isNaN(parsed) || parsed < 0) return 0\n  return Math.round(parsed * SATS_PER_BSV)\n}\n\n/** Validates a BSV address using base58check character set and length */\nconst BSV_ADDRESS_RE = /^[13][1-9A-HJ-NP-Za-km-z]{24,33}$/\n\nfunction isValidBsvAddress(address: string): boolean {\n  return BSV_ADDRESS_RE.test(address.trim())\n}\n\nfunction formatSatsDisplay(sats: number): string {\n  if (sats >= SATS_PER_BSV) {\n    return `${satsToBsvString(sats)} BSV`\n  }\n  return `${sats.toLocaleString()} sats`\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function SendBsvDialog({\n  open,\n  onOpenChange,\n  onSend,\n  onSuccess,\n  onError,\n  defaultAddress = \"\",\n  defaultSatoshis,\n  estimatedFee = DEFAULT_FEE_SATS,\n  size = \"full\",\n  className,\n}: SendBsvDialogProps) {\n  const [address, setAddress] = useState(defaultAddress)\n  const [amountInput, setAmountInput] = useState(\n    defaultSatoshis ? String(defaultSatoshis) : \"\",\n  )\n  const [unit, setUnit] = useState<AmountUnit>(\"sats\")\n  const [isSending, setIsSending] = useState(false)\n  const [result, setResult] = useState<SendBsvResult | null>(null)\n  const [error, setError] = useState<string | null>(null)\n\n  // Reset form when dialog opens\n  useEffect(() => {\n    if (open) {\n      setAddress(defaultAddress)\n      setAmountInput(defaultSatoshis ? String(defaultSatoshis) : \"\")\n      setUnit(\"sats\")\n      setResult(null)\n      setError(null)\n    }\n  }, [open, defaultAddress, defaultSatoshis])\n\n  // Parse amount to satoshis based on current unit\n  const satoshis = useMemo(() => {\n    if (!amountInput) return 0\n    if (unit === \"bsv\") {\n      return bsvStringToSats(amountInput)\n    }\n    const parsed = Number.parseInt(amountInput, 10)\n    if (Number.isNaN(parsed) || parsed < 0) return 0\n    return parsed\n  }, [amountInput, unit])\n\n  // Validation\n  const validationError = useMemo(() => {\n    if (!amountInput && !address) return null\n    if (address && address.trim().length > 0 && !isValidBsvAddress(address)) {\n      return \"Invalid BSV address\"\n    }\n    if (amountInput && satoshis < MIN_AMOUNT_SATS) {\n      return \"Amount must be at least 1 satoshi\"\n    }\n    if (satoshis > MAX_AMOUNT_SATS) {\n      return \"Amount exceeds maximum\"\n    }\n    return null\n  }, [address, amountInput, satoshis])\n\n  const canSend =\n    isValidBsvAddress(address) &&\n    satoshis >= MIN_AMOUNT_SATS &&\n    satoshis <= MAX_AMOUNT_SATS &&\n    !validationError\n\n  const totalSats = satoshis + estimatedFee\n\n  // Toggle between sats and BSV\n  const handleToggleUnit = useCallback(() => {\n    if (unit === \"sats\") {\n      // Convert current sats input to BSV\n      const currentSats = Number.parseInt(amountInput, 10)\n      if (!Number.isNaN(currentSats) && currentSats > 0) {\n        setAmountInput(satsToBsvString(currentSats))\n      } else {\n        setAmountInput(\"\")\n      }\n      setUnit(\"bsv\")\n    } else {\n      // Convert current BSV input to sats\n      const currentSats = bsvStringToSats(amountInput)\n      if (currentSats > 0) {\n        setAmountInput(String(currentSats))\n      } else {\n        setAmountInput(\"\")\n      }\n      setUnit(\"sats\")\n    }\n  }, [unit, amountInput])\n\n  const handleAmountChange = useCallback(\n    (value: string) => {\n      if (unit === \"sats\") {\n        setAmountInput(value.replace(/[^0-9]/g, \"\"))\n      } else {\n        // Allow digits and a single decimal point for BSV input\n        setAmountInput(value.replace(/[^0-9.]/g, \"\").replace(/(\\..*)\\./g, \"$1\"))\n      }\n    },\n    [unit],\n  )\n\n  const handleSend = useCallback(async () => {\n    if (!canSend) return\n\n    setIsSending(true)\n    setError(null)\n    setResult(null)\n\n    try {\n      const sendResult = await onSend({\n        address: address.trim(),\n        satoshis,\n      })\n\n      if (sendResult.error) {\n        setError(sendResult.error)\n        onError?.(new Error(sendResult.error))\n      } else {\n        setResult(sendResult)\n        onSuccess?.(sendResult)\n      }\n    } catch (err) {\n      const msg = err instanceof Error ? err.message : \"Failed to send BSV\"\n      setError(msg)\n      onError?.(err instanceof Error ? err : new Error(msg))\n    } finally {\n      setIsSending(false)\n    }\n  }, [canSend, address, satoshis, onSend, onSuccess, onError])\n\n  const handleOpenChange = useCallback(\n    (nextOpen: boolean) => {\n      if (!isSending) {\n        onOpenChange(nextOpen)\n      }\n    },\n    [isSending, onOpenChange],\n  )\n\n  const isCompact = size === \"compact\"\n\n  return (\n    <Dialog open={open} onOpenChange={handleOpenChange}>\n      <DialogContent\n        className={cn(\n          isCompact ? \"sm:max-w-sm\" : \"sm:max-w-md\",\n          className,\n        )}\n      >\n        <DialogHeader className={cn(isCompact && \"pb-0\")}>\n          <DialogTitle className={cn(isCompact && \"text-base\")}>\n            Send BSV\n          </DialogTitle>\n          {!isCompact && (\n            <DialogDescription>\n              Send Bitcoin SV to any address. Double-check the address and amount\n              before confirming.\n            </DialogDescription>\n          )}\n        </DialogHeader>\n\n        <div\n          className={cn(\n            \"flex flex-col gap-4\",\n            isCompact ? \"py-2\" : \"py-4\",\n          )}\n        >\n          {/* Address input */}\n          <div className={cn(\"flex flex-col gap-2\", isCompact && \"gap-1.5\")}>\n            <Label\n              htmlFor=\"send-bsv-address\"\n              className={cn(isCompact && \"text-xs\")}\n            >\n              Destination Address\n            </Label>\n            <Input\n              id=\"send-bsv-address\"\n              type=\"text\"\n              placeholder=\"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\"\n              value={address}\n              onChange={(e) => setAddress(e.target.value)}\n              disabled={isSending || !!result?.txid}\n              className={cn(\n                \"font-mono text-sm\",\n                isCompact && \"h-8 text-xs\",\n              )}\n              autoComplete=\"off\"\n              spellCheck={false}\n            />\n          </div>\n\n          {/* Amount input with unit toggle */}\n          <div className={cn(\"flex flex-col gap-2\", isCompact && \"gap-1.5\")}>\n            <Label\n              htmlFor=\"send-bsv-amount\"\n              className={cn(isCompact && \"text-xs\")}\n            >\n              Amount\n            </Label>\n            <div className=\"flex items-center gap-2\">\n              <div className=\"relative flex-1\">\n                <Input\n                  id=\"send-bsv-amount\"\n                  type=\"text\"\n                  inputMode={unit === \"sats\" ? \"numeric\" : \"decimal\"}\n                  pattern={unit === \"sats\" ? \"[0-9]*\" : \"[0-9.]*\"}\n                  placeholder={unit === \"sats\" ? \"100000\" : \"0.00100000\"}\n                  value={amountInput}\n                  onChange={(e) => handleAmountChange(e.target.value)}\n                  disabled={isSending || !!result?.txid}\n                  className={cn(\n                    \"pr-14\",\n                    isCompact && \"h-8 text-xs\",\n                  )}\n                  aria-describedby=\"send-bsv-amount-display\"\n                />\n                <span\n                  className={cn(\n                    \"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-xs font-medium text-muted-foreground\",\n                  )}\n                >\n                  {unit === \"sats\" ? \"sats\" : \"BSV\"}\n                </span>\n              </div>\n              <Button\n                type=\"button\"\n                variant=\"outline\"\n                size=\"icon\"\n                className={cn(\"flex-shrink-0\", isCompact && \"size-8\")}\n                onClick={handleToggleUnit}\n                disabled={isSending || !!result?.txid}\n                aria-label={`Switch to ${unit === \"sats\" ? \"BSV\" : \"satoshis\"}`}\n              >\n                <ArrowDownUp\n                  aria-hidden=\"true\"\n                  data-icon=\"inline-start\"\n                />\n              </Button>\n            </div>\n            {satoshis > 0 && (\n              <p\n                id=\"send-bsv-amount-display\"\n                className=\"text-xs text-muted-foreground\"\n              >\n                {unit === \"sats\"\n                  ? `${satsToBsvString(satoshis)} BSV`\n                  : `${satoshis.toLocaleString()} sats`}\n              </p>\n            )}\n          </div>\n\n          {/* Fee line */}\n          {satoshis > 0 && !result?.txid && (\n            <>\n            <Separator />\n            <div\n              className={cn(\n                \"flex items-center justify-between rounded-md border bg-muted/50 px-4 py-3\",\n                isCompact && \"px-3 py-2\",\n              )}\n            >\n              <div className=\"flex flex-col gap-0.5\">\n                <p\n                  className={cn(\n                    \"text-sm text-muted-foreground\",\n                    isCompact && \"text-xs\",\n                  )}\n                >\n                  Network fee\n                </p>\n                <p\n                  className={cn(\n                    \"text-sm font-medium\",\n                    isCompact && \"text-xs\",\n                  )}\n                >\n                  Total: {formatSatsDisplay(totalSats)}\n                </p>\n              </div>\n              <span\n                className={cn(\n                  \"text-sm text-muted-foreground\",\n                  isCompact && \"text-xs\",\n                )}\n              >\n                ~{estimatedFee} sats\n              </span>\n            </div>\n            </>\n          )}\n\n          {/* Validation error */}\n          {validationError && (\n            <p\n              className={cn(\n                \"text-sm text-destructive\",\n                isCompact && \"text-xs\",\n              )}\n              role=\"alert\"\n            >\n              {validationError}\n            </p>\n          )}\n\n          {/* Success */}\n          {result?.txid && (\n            <div\n              className={cn(\n                \"flex items-start gap-3 rounded-md border border-primary/20 bg-primary/5 p-3\",\n                isCompact && \"gap-2 p-2\",\n              )}\n            >\n              <CheckCircle2\n                className={cn(\n                  \"mt-0.5 size-4 flex-shrink-0 text-primary\",\n                  isCompact && \"size-3.5\",\n                )}\n              />\n              <div className=\"min-w-0 flex flex-col gap-1\">\n                <p\n                  className={cn(\n                    \"text-sm font-medium\",\n                    isCompact && \"text-xs\",\n                  )}\n                >\n                  Sent successfully\n                </p>\n                <Badge variant=\"outline\" className=\"max-w-full truncate text-xs font-mono\">\n                  {result.txid}\n                </Badge>\n              </div>\n            </div>\n          )}\n\n          {/* Error */}\n          {error && (\n            <div\n              className={cn(\n                \"flex items-start gap-3 rounded-md border border-destructive/20 bg-destructive/5 p-3\",\n                isCompact && \"gap-2 p-2\",\n              )}\n            >\n              <AlertCircle\n                className={cn(\n                  \"mt-0.5 size-4 flex-shrink-0 text-destructive\",\n                  isCompact && \"size-3.5\",\n                )}\n              />\n              <div className=\"flex flex-col gap-1\">\n                <p\n                  className={cn(\n                    \"text-sm font-medium\",\n                    isCompact && \"text-xs\",\n                  )}\n                >\n                  Send failed\n                </p>\n                <p className=\"text-xs text-muted-foreground\">{error}</p>\n              </div>\n            </div>\n          )}\n        </div>\n\n        <DialogFooter>\n          <Button\n            className=\"w-full\"\n            onClick={handleSend}\n            disabled={!canSend || isSending || !!result?.txid}\n            aria-busy={isSending}\n          >\n            {isSending ? (\n              <>\n                <Loader2 className=\"animate-spin\" data-icon=\"inline-start\" />\n                Sending...\n              </>\n            ) : result?.txid ? (\n              \"Sent\"\n            ) : (\n              `Confirm & Send${satoshis > 0 ? ` ${formatSatsDisplay(satoshis)}` : \"\"}`\n            )}\n          </Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  )\n}\n",
      "type": "registry:component",
      "target": "~/components/blocks/send-bsv/send-bsv-dialog.tsx"
    }
  ],
  "type": "registry:block"
}