npm package: @meridial/react
Description: React components for embedding the Meridial in-app assistant UI (Voicebox) and workflow recorder UI (Recorder).
Author: Meridial
Latest version: 0.2.7

# `@meridial/react`

React components for embedding the Meridial in-app assistant UI (`Voicebox`) and workflow recorder UI (`Recorder`).

## Exports

- **`Voicebox`**: embedded assistant widget (badge + draggable conversation bar).
- **`Recorder`**: draggable recorder UI that captures click-steps + microphone narration and stores workflows locally (and can read server workflows when authenticated).

## Installation

```
npm i @meridial/react
```

## `Voicebox`

### Props

```ts
interface VoiceboxProps {
  firstMessage?: string
  instructions?: string
  baseUrl?: string
  publishableKey?: string
  identifier?: string | null
  tools?: VoiceboxTool[]
  triggerIcon?: React.ReactNode
  cursor?: React.ReactNode
  metadata?: Record<string, string>
  onError?: (error: string) => void
}
```

### Minimal example (Next.js / React)

```tsx
"use client"

import { z } from "zod"
import { Voicebox, defineTool, type VoiceboxTool } from "@meridial/react"

const tools: VoiceboxTool[] = [
  defineTool({
    name: "current_weather",
    description: "Get the current weather for a given location.",
    parameters: z.object({
      location: z.string(),
    }),
    execute: async ({ location }) => {
      // Runs in the browser/client.
      return { location, weather: "sunny", temperature: "24°C" }
    },
  }),
]

export function VoiceboxWidget({
  publishableKey,
  identifier,
}: {
  publishableKey: string
  identifier: string | null
}) {
  return (
    <Voicebox
      baseUrl="https://app.meridial.dev" 
      publishableKey={publishableKey}
      identifier={identifier}
      firstMessage="Hi, I am a meridial agent. How can I help you today ?"
      instructions="You are a helpful assistant that can answer questions and help with tasks."
      tools={tools}
      metadata={{ orgId: "org_123..." }}
      onError={(err) => console.error("[Voicebox]", err)}
    />
  )
}
```

## `Recorder`

### Props

```ts
interface RecorderProps {
  baseUrl?: string
  publishableKey?: string
  attribute?: string
  cursor?: React.ReactNode
  onNavigate?: (path: string) => void
  onError?: (error: string) => void
}
```

| Prop | Description |
|------|-------------|
| `onNavigate` | Optional callback for auto-navigation during workflow editing. When provided, the editor will call this with the step's `urlPath` whenever the active step changes. If omitted, no navigation occurs. |

### Minimal example

```tsx
"use client"

import { Recorder } from "@meridial/react"

export function RecorderWidget({ publishableKey }: { publishableKey?: string }) {
  return (
    <Recorder
      baseUrl=""
      publishableKey={publishableKey}
      onError={(err) => console.error("[Recorder]", err)}
    />
  )
}
```

### With auto-navigation (Next.js)

```tsx
"use client"

import { useRouter } from "next/navigation"
import { Recorder } from "@meridial/react"

export function RecorderWidget({ publishableKey }: { publishableKey?: string }) {
  const router = useRouter()

  return (
    <Recorder
      baseUrl=""
      publishableKey={publishableKey}
      onNavigate={(path) => router.push(path)}
      onError={(err) => console.error("[Recorder]", err)}
    />
  )
}
```

## Styling / UI

These components use Tailwind CSS classes and are designed to work with your existing Tailwind / shadcn setup.

You can integrate styles in either of these ways:

### Option 1: include `@meridial/react` in your Tailwind sources

If your app compiles Tailwind itself, make sure your global stylesheet scans the React package too.

```css
@source "../node_modules/@meridial/react/dist/**/*.{js,mjs}";
```

Adjust the relative path so it is correct from your own global stylesheet location.

### Option 2: import the built CSS directly

If you do not want Tailwind to scan the package, import the package CSS in your global stylesheet instead:

```css
@import "@meridial/react/dist/styles.css";
```

Use this approach when you want the package to provide its own prebuilt styles instead of relying on your app's Tailwind build to generate them.