@papermap/papermap
v1.1.0
Published
Embeddable AI chat bar and UI components from the Papermap data analytics platform
Readme
Papermap
Embeddable AI-powered components from the Papermap 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 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. Usevariant="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.
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
npm install @papermap/papermap
# or
pnpm add @papermap/papermapRequirements: React 18+ and React DOM 18+ (peer dependencies).
2. Import styles once
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.
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).
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:
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.
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.cssexport. - 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
apiUrlon the provider or per component. Default ishttps://dataapi.papermap.ai.
Charts do not appear in PaperCard
- Pass a valid backend
chartId(chat id), or supply preloadedchartdata.
How it works
Authentication
The token prop is base64-encoded 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-IDX-Workspace-IDX-Valid-UntilX-SignatureX-Tenant-ID: da-app
Chat data flow (overview)
- User sends a message; first message may create a chat via
POST /api/v1/analytics/chats. - Message goes to
POST /api/v1/analytics/charts/streamwith SSE. - SSE connects to
POST /api/v1/analytics/requests/streamfor live updates; HTTP remains a fallback. - 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.
