npm package: @stableyard/widget
Description: Drop-in payment widget for accepting stablecoins
Latest version: 0.2.0

# @stableyard/widget

Drop-in widget for accepting stablecoin payments. Users pay with any token from any chain — you receive USDC instantly.

Built by [Stableyard](https://stableyard.fi) — powered by [Gasyard](https://gasyard.fi).

## Two Ways to Integrate

| Version | Best For | Features |
|---------|----------|----------|
| **React** | React/Next.js apps | Full wallet connection, token selection, real-time balances |
| **Standalone** | Any website (HTML/JS) | No framework needed, QR code payments, address-based flow |

---

## React Integration

Full-featured widget with wallet connection, multi-chain support, and real-time token balances.

### Installation

```bash
npm install @stableyard/widget
```

**Peer Dependencies:**

```bash
npm install react react-dom @tanstack/react-query wagmi viem @privy-io/react-auth
```

For Solana support:

```bash
npm install @solana/web3.js @solana/spl-token @solana/kit @solana-program/system @solana-program/token @solana-program/memo
```

### Quick Start

```tsx
import { StableyardProvider, StableyardWidget } from '@stableyard/widget'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider, createConfig, http } from 'wagmi'
import { base, arbitrum, polygon } from 'wagmi/chains'
import { PrivyProvider } from '@privy-io/react-auth'

const queryClient = new QueryClient()
const wagmiConfig = createConfig({
  chains: [base, arbitrum, polygon],
  transports: {
    [base.id]: http(),
    [arbitrum.id]: http(),
    [polygon.id]: http(),
  },
})

function App() {
  return (
    <PrivyProvider appId="your-privy-app-id">
      <WagmiProvider config={wagmiConfig}>
        <QueryClientProvider client={queryClient}>
          <StableyardProvider apiKey="your-api-key">
            <StableyardWidget
              to="merchant@example.com"
              amount={29.99}
              onSuccess={(payment) => console.log('Paid!', payment)}
            />
          </StableyardProvider>
        </QueryClientProvider>
      </WagmiProvider>
    </PrivyProvider>
  )
}
```

### Provider Props

```tsx
<StableyardProvider
  apiKey="your-api-key"        // Required
  apiUrl="https://api.stableyard.fi"  // Optional: custom API endpoint
  theme="light"                // 'light' | 'dark' | 'auto'
  accentColor="#0066FF"        // Primary brand color
>
  <App />
</StableyardProvider>
```

### Widget Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `to` | `string` | required | Recipient identity or wallet address |
| `amount` | `number` | - | Amount in USD (omit for user-entered) |
| `buttonText` | `string` | `"Pay"` | Custom button text |
| `buttonVariant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` | `'primary'` | Button style |
| `buttonSize` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
| `disabled` | `boolean` | `false` | Disable the button |
| `renderInline` | `boolean` | `false` | Render inline instead of modal |
| `containerStyle` | `CSSProperties` | - | Style for inline container |
| `onSuccess` | `(payment) => void` | - | Called when payment succeeds |
| `onError` | `(error) => void` | - | Called on error |
| `onClose` | `() => void` | - | Called when modal closes |
| `onStatusChange` | `(status) => void` | - | Called on status change |
| `onTransactionSubmitted` | `(hash, chainId) => void` | - | Called when TX is signed |
| `onTransactionConfirmed` | `(hash, chainId) => void` | - | Called when TX confirms |

### Inline Mode

Embed the widget directly in your page:

```tsx
<StableyardWidget
  to="merchant@example"
  amount={25}
  renderInline={true}
  containerStyle={{ maxWidth: 420 }}
/>
```

### Theming

Customize with the `accentColor` prop:

```tsx
<StableyardProvider
  apiKey="your-key"
  accentColor="#8B5CF6"  // Your brand color
  theme="light"
>
  <App />
</StableyardProvider>
```

### Status Callbacks

Track the payment lifecycle:

```tsx
<StableyardWidget
  to="merchant@example"
  amount={10}
  onStatusChange={(status) => {
    // 'idle' | 'intro' | 'connecting' | 'loading_balances' |
    // 'selecting_token' | 'loading_quote' | 'reviewing' |
    // 'signing' | 'confirming' | 'processing' | 'success' | 'error'
    console.log('Status:', status)
  }}
  onTransactionSubmitted={(hash, chainId) => {
    console.log('TX signed:', hash)
  }}
  onSuccess={(payment) => {
    console.log('Payment complete:', payment.id)
  }}
/>
```

---

## Standalone Integration (Vanilla JS)

For non-React websites. Uses QR code / address-based payments — no wallet connection required on your site.

### Option 1: Script Tag

```html
<!DOCTYPE html>
<html>
<head>
  <title>Checkout</title>
</head>
<body>
  <h1>Complete Your Purchase</h1>
  <p>Total: $29.99</p>

  <button id="pay-button">Pay with Crypto</button>

  <!-- Include the standalone bundle -->
  <script src="https://unpkg.com/@stableyard/widget/dist/standalone.js"></script>

  <script>
    // Initialize with your API key
    Stableyard.init({
      apiKey: 'your-api-key',
      theme: 'light',           // optional: 'light' | 'dark'
      accentColor: '#0066FF'    // optional: brand color
    })

    // Open payment modal on button click
    document.getElementById('pay-button').addEventListener('click', function() {
      Stableyard.pay({
        to: 'merchant@stableyard',
        amount: 29.99,
        onSuccess: function(payment) {
          alert('Payment successful!')
          console.log('Payment:', payment)
          // Redirect to success page, update UI, etc.
        },
        onError: function(error) {
          console.error('Payment failed:', error)
        },
        onClose: function() {
          console.log('Modal closed')
        }
      })
    })
  </script>
</body>
</html>
```

### Option 2: ES Module Import

```html
<script type="module">
  import { init, pay } from 'https://unpkg.com/@stableyard/widget/dist/standalone.js'

  init({ apiKey: 'your-api-key' })

  document.getElementById('pay-button').onclick = () => {
    pay({
      to: 'merchant@stableyard',
      amount: 29.99,
      onSuccess: (payment) => console.log('Paid!', payment)
    })
  }
</script>
```

### Option 3: Self-Hosted

Download and host the standalone bundle yourself:

```bash
# Download from npm
npm pack @stableyard/widget
tar -xzf stableyard-widget-*.tgz
cp package/dist/standalone.js ./public/js/
```

```html
<script src="/js/standalone.js"></script>
```

### Standalone API

#### `Stableyard.init(options)`

Initialize the widget. Call once on page load.

```js
Stableyard.init({
  apiKey: 'your-api-key',    // Required
  theme: 'light',            // Optional: 'light' | 'dark' | 'auto'
  accentColor: '#0066FF',    // Optional: hex color
})
```

#### `Stableyard.pay(options)`

Open the payment modal.

```js
Stableyard.pay({
  to: 'merchant@stableyard',  // Required: recipient
  amount: 29.99,              // Optional: USD amount (user can enter if omitted)
  onSuccess: (payment) => {}, // Called on successful payment
  onError: (error) => {},     // Called on error
  onClose: () => {},          // Called when modal closes
})
```

#### Payment Object

The `onSuccess` callback receives a payment object:

```js
{
  quoteId: 'quote_abc123',
  status: 'completed',
  inputTxHash: '0x...',
  outputTxHash: '0x...',
  from: {
    chainId: 137,
    token: 'USDC',
    amount: '29.99'
  },
  to: {
    identity: 'merchant@stableyard',
    chainId: 1,
    token: 'USDC',
    amount: '29.99'
  }
}
```

### Standalone Flow

The standalone version uses an **address-based payment flow**:

1. User clicks your pay button
2. Modal opens showing amount and network selection
3. User selects their preferred network (Ethereum, Base, Polygon, etc.)
4. A deposit address and QR code are displayed
5. User sends payment from their wallet or exchange
6. Payment is detected and confirmed
7. `onSuccess` callback fires

This flow works without any wallet connection on your website — users can pay from any wallet, exchange, or app that supports sending crypto.

---

## Supported Chains

| Chain | Tokens |
|-------|--------|
| Ethereum | USDC, USDT |
| Base | USDC, USDT |
| Arbitrum | USDC, USDT |
| Polygon | USDC, USDT |
| Optimism | USDC, USDT |
| BSC | USDC, USDT |
| Solana | USDC |

---

## React Hooks

For building custom payment UIs:

### `useWalletConnection`

```tsx
import { useWalletConnection } from '@stableyard/widget'

const {
  isConnected,
  isReady,
  evmAddress,
  solanaAddress,
  login,
  logout
} = useWalletConnection()
```

### `useBalances`

```tsx
import { useBalances } from '@stableyard/widget'

const { balances, isLoading, error } = useBalances({
  address: '0x...',
  enabled: true,
})
```

### `useQuote`

```tsx
import { useQuote } from '@stableyard/widget'

const { getQuote, isLoading, error } = useQuote()

const quote = await getQuote({
  amount: 2500000, // in token decimals
  destinationPaymentAddress: 'merchant@stableyard',
  sourceChainId: 137,
  sourceChainToken: 'USDC',
})
```

---

## TypeScript

All types are exported:

```tsx
import type {
  StableyardWidgetProps,
  StableyardProviderProps,
  Payment,
  TokenBalance,
  QuoteResponseData,
  WidgetPaymentStatus,
} from '@stableyard/widget'
```

---

## License

MIT