npm package: @papermap/papermap
Description: Embeddable AI chat bar and UI components from the Papermap data analytics platform
Latest version: 1.0.4

# Papermap

Embeddable AI-powered components from the [Papermap](https://www.papermap.ai) data analytics platform. This is a standalone package — **independent** from the main Papermap app. Services, SSE streaming, and UI are self-contained; the repos do not depend on each other.

## Backend setup

For **server-side setup** (HMAC auth, dashboards per tenant, embed tokens, API endpoints), see the [Backend implementation guide](https://docs.papermap.ai/documentation/multi-tenancy/backend) in the Papermap docs.

## Main components

- **`PaperChat`** — Full AI chat assistant with streaming, conversation history, and chart generation.
- **`PaperCard`** — Standalone chart card with toolbar actions. Use `variant="streaming"` for an embedded chart + conversation dialog (without the floating assistant).
- **`PaperBoard`** — Responsive grid layout of chart cards, toolbar (screenshot, generate dashboard, theme), optional chat assistant, and controlled or uncontrolled layouts.

```tsx
import { PaperChat, PaperCard, PaperBoard } from '@papermap/papermap'

// AI chat assistant
<PaperChat
  token="your-base64-api-token"
  workspaceId="your-workspace-id"
  dashboardId="your-dashboard-id"
/>

// Standalone chart card
<PaperCard
  token="your-base64-api-token"
  workspaceId="your-workspace-id"
  dashboardId="your-dashboard-id"
  chartId="your-chart-id"
/>

// Streaming chart card (embedded dialog + chat)
<PaperCard
  token="your-base64-api-token"
  workspaceId="your-workspace-id"
  dashboardId="your-dashboard-id"
  variant="streaming"
  chartId="your-chart-id" // optional; card shows empty state if omitted
/>

// Full grid dashboard (wraps chart cards + optional PaperChat)
<PaperBoard
  token="..."
  workspaceId="..."
  dashboardId="..."
  showChatAssistant
/>
```

Each top-level component handles API calls, authentication, and UI internally unless you compose lower-level exports yourself.

---

## Quick start

### 1. Install

```bash
npm install @papermap/papermap
# or
pnpm add @papermap/papermap
```

**Requirements:** React 18+ and React DOM 18+ (peer dependencies).

### 2. Import styles once

```tsx
import '@papermap/papermap/styles.css'
```

### 3. Choose an integration pattern

#### A) Recommended: provider at app root

`PapermapConfigProvider` is an alias for `PapermapProvider` — same component, useful for naming consistency in app code.

```tsx
import { PapermapConfigProvider, PaperChat, PaperCard } from '@papermap/papermap'

function App() {
  return (
    <PapermapConfigProvider
      token="your-base64-api-token"
      workspaceId="your-workspace-id"
      dashboardId="your-dashboard-id"
      // optional: apiUrl="https://dataapi.papermap.ai"
    >
      <PaperChat />
      <PaperCard chartId="existing-chat-id" />
    </PapermapConfigProvider>
  )
}
```

#### B) Standalone components (no provider)

Pass `token`, `workspaceId`, and `dashboardId` on each component (or rely on an existing parent `PapermapProvider`).

```tsx
import { PaperChat, PaperCard } from '@papermap/papermap'

function App() {
  return (
    <>
      <PaperChat
        token="your-base64-api-token"
        workspaceId="your-workspace-id"
        dashboardId="your-dashboard-id"
      />

      <PaperCard
        token="your-base64-api-token"
        workspaceId="your-workspace-id"
        dashboardId="your-dashboard-id"
        chartId="existing-chat-id"
      />
    </>
  )
}
```

### 4. Props

#### `PaperChat` props

| Prop          | Type                | Required | Default                       | Description                          |
| ------------- | ------------------- | -------- | ----------------------------- | ------------------------------------ |
| `token`       | `string`            | Yes\*    | --                            | Base64-encoded API key token         |
| `workspaceId` | `string`            | Yes\*    | --                            | Workspace ID                         |
| `dashboardId` | `string`            | Yes\*    | --                            | Dashboard ID                         |
| `apiUrl`      | `string`            | No       | `https://dataapi.papermap.ai` | API base URL                         |
| `theme`       | `'light' \| 'dark'` | No       | --                            | Force light or dark theme            |
| `placeholder` | `string`            | No       | `"Ask anything..."`           | Input placeholder text               |
| `shortcutKey` | `string`            | No       | `"k"`                         | Keyboard shortcut (Cmd/Ctrl + key)   |
| `autoFade`    | `boolean`           | No       | `false`                       | Fade toolbar after inactivity        |
| `fadeDelay`   | `number`            | No       | `5000`                        | Milliseconds before auto-fade        |
| `className`   | `string`            | No       | --                            | Extra CSS class on toolbar container |

\*Omit on the component when values come from `PapermapConfigProvider` / `PapermapProvider`.

#### `PaperCard` props

| Prop           | Type                                         | Required | Default                       | Description                                      |
| -------------- | -------------------------------------------- | -------- | ----------------------------- | ------------------------------------------------ |
| `token`        | `string`                                     | Yes\*    | --                            | Base64-encoded API key token                     |
| `workspaceId`  | `string`                                     | Yes\*    | --                            | Workspace ID                                     |
| `dashboardId`  | `string`                                     | Yes\*    | --                            | Dashboard ID                                     |
| `apiUrl`       | `string`                                     | No       | `https://dataapi.papermap.ai` | API base URL                                     |
| `chartId`      | `string`                                     | No       | --                            | Backend chat id to load the latest chart for     |
| `chart`        | `TChartResponse`                             | No       | --                            | Pre-loaded chart data (skips API fetch)          |
| `theme`        | `'light' \| 'dark'`                          | No       | --                            | Force light or dark theme                        |
| `onEditClick`  | `(chartId: string) => void`                  | No       | --                            | Called when the edit button is clicked           |
| `onDelete`     | `(chartId: string) => void`                  | No       | --                            | Called when chart deletion is confirmed          |
| `onPinChange`  | `(chartId: string, pinned: boolean) => void` | No       | --                            | Called when pin state changes                    |
| `wide`         | `boolean`                                    | No       | `false`                       | Wide mode for table charts                       |
| `hideVariants` | `boolean`                                    | No       | `true`                        | Hide the chart variation selector                |
| `showToolbar`  | `boolean`                                    | No       | `true`                        | Show toolbar with maximize/edit/delete buttons   |
| `className`    | `string`                                     | No       | --                            | Extra CSS class on the card container            |
| `variant`      | `'default' \| 'streaming'`                   | No       | `'default'`                   | `'streaming'`: edit opens embedded dialog + chat |

**Pre-loaded chart:**

```tsx
import { PaperCard } from '@papermap/papermap'
import type { TChartResponse } from '@papermap/papermap'

const chart: TChartResponse = {
  llm_data_chat_id: 'my-chart-id',
  name: 'Revenue',
  meta: { title: 'Revenue by Quarter', variant: 'default' },
  pin: false,
  chart_response: {
    chart_type: 'bar',
    data: [
      { quarter: 'Q1', revenue: 42000 },
      { quarter: 'Q2', revenue: 55000 },
    ],
    response_type: 'chart',
    schema_hints: { x_key: 'quarter', y_key: 'revenue', label_key: 'quarter' },
    visualization_config: { colors: ['#3b82f6'], width: 600, height: 400 },
  },
}

<PaperCard
  token="..."
  workspaceId="..."
  dashboardId="..."
  chart={chart}
  onEditClick={(id) => console.log('Edit', id)}
  onDelete={(id) => console.log('Delete', id)}
/>
```

#### `PaperBoard` props (high level)

| Prop                                                                                        | Notes                                                                                                              |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `token`, `workspaceId`, `dashboardId`, `apiUrl`                                             | Same as other components; can come from provider.                                                                  |
| `charts`                                                                                    | Optional pre-loaded charts; otherwise fetched when `enableFetch` is true (default).                                |
| `layouts` / `onLayoutsChange`                                                               | Controlled grid layouts per breakpoint.                                                                            |
| `isEditMode`, `editLayout`, `isViewer`                                                      | Edit vs view behavior.                                                                                             |
| `showToolbar`, `showScreenshot`, `showGenerateDashboard`, `showHeader`, `showChatAssistant` | Feature toggles.                                                                                                   |
| `variant`                                                                                   | `'default' \| 'streaming'` for embedded chart cards (matches `PaperCard`).                                         |
| `dashboardTheme`, `onDashboardThemeChange`, `persistWorkspaceTheme`, `renderThemeModal`     | Theming; built-in modal uses `ThemeCustomizationSettings`.                                                         |
| Callbacks                                                                                   | `onEditChart`, `onDeleteChart`, `onPinChange`, `onGenerateDashboard`, `onTakeScreenshot`, `onThemeModalOpen`, etc. |

See TypeScript types `PaperBoardProps` and Storybook stories for full detail.

### Streaming chart card variant

With `variant="streaming"`, the edit action opens an embedded expanded view with chart + conversation, SSE streaming, save-to-dashboard and maximize actions, and audit log on assistant messages.

```tsx
import { PaperCard } from '@papermap/papermap'

export function EmbeddedStreamingChart() {
  return (
    <div className="h-[420px] w-[520px]">
      <PaperCard
        token="..."
        workspaceId="..."
        dashboardId="..."
        variant="streaming"
        chartId="existing-chat-id"
      />
    </div>
  )
}
```

**Supported chart types:** `bar`, `line`, `area`, `pie`, `radar`, `scatter`, `table`, `tile` — aligned with the main Papermap app.

---

## Advanced exports

For custom layouts, the package also exports subcomponents (for example `ChatAssistant`, `StreamingChartDialog`, `ChartView`, `DataTable`), Zustand store helpers (`usePapermapStore`, `createPapermapStore`), hooks (`useAnalyticsStream`, …), API helpers (`createApiClient`, `decodeToken`, `buildAuthHeaders`), streaming and chart types, **theme presets** (`themePresets`, `defaultTheme`, `ThemeCustomizationSettings`), and **chart card id ↔ chat id** persistence helpers (`getChartCardIdLink`, `resolveChartFetchChatId`, …). Import paths are the same as the main entry: `@papermap/papermap`.

---

## Troubleshooting

### Cannot find module `@papermap/papermap/styles.css`

- Use the scoped package name and the `./styles.css` export.
- Reinstall after upgrading.

### "Papermap... requires token/workspaceId/dashboardId"

- Provide values once via `PapermapConfigProvider` / `PapermapProvider`, or pass them on each component.

### Requests hit the wrong backend

- Set `apiUrl` on the provider or per component. Default is `https://dataapi.papermap.ai`.

### Charts do not appear in `PaperCard`

- Pass a valid backend `chartId` (chat id), or supply preloaded `chart` data.

---

## How it works

### Authentication

The `token` prop is base64-encoded JSON:

```json
{
  "api_key_id": "ak_...",
  "workspace_id": "...",
  "valid_until": 1773246356,
  "signature": "88b34e..."
}
```

The library decodes it and sends these headers on API requests:

- `X-API-Key-ID`
- `X-Workspace-ID`
- `X-Valid-Until`
- `X-Signature`
- `X-Tenant-ID: da-app`

### Chat data flow (overview)

1. User sends a message; first message may create a chat via `POST /api/v1/analytics/chats`.
2. Message goes to `POST /api/v1/analytics/charts/stream` with SSE.
3. SSE connects to `POST /api/v1/analytics/requests/stream` for live updates; HTTP remains a fallback.
4. History: `GET /api/v1/analytics/chats/{id}/conversations`, dashboard recent chats, and full chart history per chat as needed.

### What users see in `PaperChat`

- Floating input bar (portaled to `document.body`), Cmd/Ctrl+K to focus, Escape to dismiss.
- Expanding input, backdrop, conversation panel, stop during load, new chat, scroll and history pagination.
- Recent conversations, per-chat chart history, feedback, optional execution view, model selector, and related toolbar actions.

---

## Roadmap

Additional embeddable surfaces (for example richer explorers) will follow the same pattern: self-contained components with `token` / `workspaceId` / `dashboardId` and optional callbacks, exported from `@papermap/papermap`.