npm package: @metalayer/widget
Description: React component for cross-chain token bridging powered by Caldera's Metalayer
Author: Constellation Labs
Latest version: 1.0.7

# Metalayer Bridge Widget

React component for cross-chain token bridging powered by Caldera's Bridge Aggregator.

## Features

- Cross-chain token bridging
- Multi-wallet support (Ethereum + Solana beta)
- Responsive design
- TypeScript support
- Framework agnostic

📚 **[Full Documentation](https://docs.caldera.xyz/metalayer/widget/getting-started)**

## Installation

```bash
pnpm add @metalayer/widget @metalayer/sdk viem wagmi @tanstack/react-query
```

For **Solana bridging support** (beta — testnet only, contact team to enable):

```bash
pnpm add @solana/web3.js @solana/spl-token
```

**Requirements:** React 16.8+, TypeScript 5.0+ (recommended)

Get your API key by contacting Caldera's team.

## Quick Start

```tsx
import '@metalayer/widget/styles.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { WidgetProvider, Widget } from '@metalayer/widget';
import { WagmiProvider, createConfig, http } from 'wagmi';
import { mainnet } from 'wagmi/chains';

const queryClient = new QueryClient();

const wagmiConfig = createConfig({
  chains: [mainnet],
  transports: { [mainnet.id]: http() },
});

function App() {
  return (
    <WagmiProvider config={wagmiConfig}>
      <QueryClientProvider client={queryClient}>
        <WidgetProvider
          sdkConfig={{
            apiKey: 'your-api-key',
            environment: 'mainnet',
          }}
          theme={{
            colors: { primary: '#6750A4' },
            corners: 'soft',
          }}
          onSupportedChainsLoad={(chains) => {
            // Update your wagmi config with the widget's supported chains
          }}
        >
          <Widget
            onConnectClick={() => openWalletModal()}
          />
        </WidgetProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
}
```

> **Note:** The widget requires a `WagmiProvider` from your application. Use
> `onSupportedChainsLoad` to update your wagmi config with the chains the widget supports.

## Theming

Customize the widget's appearance with the flexible theme system. The widget supports both predefined themes and custom color configurations with automatic palette generation.

### Theme Configuration Options

The theme system offers three approaches to customize your widget:

1. **Predefined Themes** - Ready-made themes with carefully crafted color palettes
2. **Custom Colors** - Provide a primary color to generate a complete, harmonious palette
3. **Advanced Overrides** - Fine-tune specific colors and properties

### Using Predefined Themes

Choose from built-in themes optimized for different aesthetics. Predefined themes automatically use default colors and styling - no need to specify colors separately.

```tsx
// Modern theme with default colors
<WidgetProvider
  sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
  theme={{ predefined: 'modern' }}
>
  <Widget onConnectClick={() => openWalletModal()} />
</WidgetProvider>

// Modern theme with custom brand color
<WidgetProvider
  sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
  theme={{
    predefined: 'modern',
    colors: { primary: '#6750A4' }
  }}
>
  <Widget onConnectClick={() => openWalletModal()} />
</WidgetProvider>
```

### Custom Color Configuration

Generate a complete theme from your brand colors:

```tsx
<WidgetProvider
  sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
  theme={{
    colors: {
      primary: '#6750A4',    // Required: Your brand color
      neutral: '#5E5E5E',    // Optional: Grayscale palette
      success: '#00C853',    // Optional: Success state
      warning: '#FFB300',    // Optional: Warning state
      info: '#2196F3',       // Optional: Info state
      failure: '#F44336'     // Optional: Error state
    },
    corners: 'rounded',      // 'none' | 'minimal' | 'soft' | 'rounded'
    shadow: 'light'          // 'none' | 'sharp' | 'light' | 'heavy'
  }}
>
  <Widget onConnectClick={() => openWalletModal()} />
</WidgetProvider>
```

### Styling Options

Control visual aspects like corner radius and shadows:

```tsx
<WidgetProvider
  sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
  theme={{
    colors: { primary: '#6750A4' },
    corners: 'minimal',     // Sharp corners
    shadow: 'heavy',        // Pronounced shadows
    features: {
      headerIcons: true,    // Show/hide header icons
      background: true      // Show/hide widget background
    }
  }}
>
  <Widget onConnectClick={() => openWalletModal()} />
</WidgetProvider>
```

### Advanced Theme Overrides

For granular control, override specific theme properties:

```tsx
<WidgetProvider
  sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
  theme={{
    colors: { primary: '#6750A4' },
    overrides: {
      background: {
        main: '#FFFFFF',
        layer1: '#F5F5F5',
        layer2: '#EEEEEE'
      },
      text: {
        primary: '#1A1A1A',
        secondary: '#666666'
      },
      interactive: {
        primary: {
          active: '#6750A4',
          hover: '#7B5FB2',
          inactive: '#E8DEF8'
        }
      }
    }
  }}
>
  <Widget onConnectClick={() => openWalletModal()} />
</WidgetProvider>
```

### Theme Reference

#### Predefined Themes
- **`comfy`** (default) - Warm, rounded standard appearance with neutral-based shadows
- **`modern`** - Clean, contemporary design with:
  - Component outlines for definition
  - Header background enabled
  - Black-based shadows for sharper contrast
  - Inverted background layer hierarchy
  - Consistent text tones across light/dark modes

#### Corner Styles
- `none` - Sharp, 90-degree corners
- `minimal` - Subtle rounding (2px)
- `soft` - Moderate rounding (8px) - Default
- `rounded` - Fully rounded corners

#### Shadow Styles
- `none` - No shadows
- `sharp` - Crisp, defined shadows
- `light` - Subtle elevation - Default
- `heavy` - Pronounced depth effect

#### Feature Toggles
- `headerIcons` - Display icons in headers (default: `true`)
- `background` - Show widget background and padding (default: `true`)
- `headerBackground` - Display header background (default: `false`, enabled in modern theme)
- `outlineComponents` - Show component outlines/borders (default: `false`, enabled in modern theme)

## Components

### WidgetProvider

Sets up the widget context and configuration. Must be rendered inside an external `WagmiProvider` — the widget does not create its own.

**Key Props:**
- **`sdkConfig`** (required) - API key and environment configuration
- **`defaultSource`** - Default source chain and token
- **`defaultDestination`** - Default destination chain and token
- **`theme`** - Theme configuration for customizing appearance (colors, corners, shadows, features)
- **`enabledChains`** - Optional pre-loaded chains validated against supported chains
- **`includeTokens`** - Optional tokens to force-include in token fetch results
- **`onSupportedChainsLoad`** - Callback when chains load (use to update your external wagmi config with supported chains)
- **`onError`** - Error handling callback
- **`debugEnabled`** - Enable debug logging

```tsx
<WidgetProvider
  sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
  defaultSource={{ chainId: 1, tokenAddress: '0x...' }}
  defaultDestination={{ chainId: 42161, tokenAddress: '0x...' }}
  onSupportedChainsLoad={(chains) => updateWalletConfig(chains)}
>
```

`WidgetProvider` always loads supported chains immediately so wallet configuration callbacks still work. Token lists load lazily when a `Widget` mounts.

### Widget

Main UI component that renders the bridge interface.

**Key Props:**
- **`onConnectClick`** (required) - Handler to open wallet connection modal
- **`onDisconnectClick`** (optional) - Handler to disconnect wallet
- **`solanaSigner`** - Solana wallet signer (requires optional `@solana/web3.js` and `@solana/spl-token` packages)

```tsx
<Widget
  onConnectClick={() => openWalletModal()}
  onDisconnectClick={() => disconnectWallet()}
  solanaSigner={solanaSigner}
/>
```

📖 **[Components Reference](https://docs.caldera.xyz/metalayer/widget/components)**

## Integration Examples

### With Dynamic.xyz

```tsx
import { DynamicContextProvider, DynamicWagmiConnector, useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { WidgetProvider, Widget } from '@metalayer/widget';
import { WagmiProvider } from 'wagmi';

function App() {
  const [wagmiConfig, setWagmiConfig] = useState(() => createWagmiConfig());

  return (
    <DynamicContextProvider settings={{ environmentId: 'your-id' }}>
      <WagmiProvider config={wagmiConfig}>
        <WidgetProvider
          sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
          onSupportedChainsLoad={(chains) => {
            // Update wagmi config with supported chains
          }}
        >
          <DynamicWagmiConnector>
            <BridgePage />
          </DynamicWagmiConnector>
        </WidgetProvider>
      </WagmiProvider>
    </DynamicContextProvider>
  );
}

function BridgePage() {
  const { setShowAuthFlow } = useDynamicContext();
  return <Widget onConnectClick={() => setShowAuthFlow(true)} />;
}
```

### With RainbowKit

```tsx
import { RainbowKitProvider, getDefaultConfig, useConnectModal } from '@rainbow-me/rainbowkit';
import { WidgetProvider, Widget } from '@metalayer/widget';
import { WagmiProvider } from 'wagmi';
import { mainnet } from 'wagmi/chains';

const wagmiConfig = getDefaultConfig({
  appName: 'My App',
  projectId: 'your-walletconnect-project-id',
  chains: [mainnet],
});

function App() {
  return (
    <WagmiProvider config={wagmiConfig}>
      <WidgetProvider
        sdkConfig={{ apiKey: 'your-api-key', environment: 'mainnet' }}
        onSupportedChainsLoad={(chains) => {
          // Update wagmi config with supported chains
        }}
      >
        <RainbowKitProvider>
          <BridgePage />
        </RainbowKitProvider>
      </WidgetProvider>
    </WagmiProvider>
  );
}

function BridgePage() {
  const { openConnectModal } = useConnectModal();
  const { disconnect } = useDisconnect();
  return <Widget onConnectClick={openConnectModal} onDisconnectClick={disconnect} />;
}
```

### Next.js

Import styles in your layout or `_app`:

```tsx
import '@metalayer/widget/styles.css';
```

📖 **[Full Examples](https://docs.caldera.xyz/metalayer/widget/examples)** - Includes Solana integration, advanced configuration, and more.