Storybook visual stories for the `EmbeddableChat` component, covering new-user, returning-user, loading, error, and agent-mode states using mocked runtimes and NATS chat adapters.
## Key Components
| Export / Identifier | Purpose |
|---|---|
| `createMockRuntime()` | Builds a minimal `ChatRuntime` with stub endpoints (no real server calls) |
| `createMockMingoConfig()` | Base NATS adapter config; `getNatsWsUrl` returns `null` to keep WS idle |
| `createMockMingoConfigWithDialogs()` | Extends base config with a paginated dialog history, rename/archive callbacks, and archived dialog support |
| `createMockMingoConfigChatsLoading()` | Pins `isDialogsLoading: true` via a never-settling `fetchDialogs` promise |
| `createMockMingoConfigChatLoading()` | Resolves the dialog list but pins message loading via a never-settling `fetchDialogMessages` |
| `createMockMingoConfigChatsError()` | Rejects `fetchDialogs` to exercise the load-error + retry UI path |
| `createMockMingoConfigArchiveEmpty()` | Resolves an empty archived dialogs page to render the archive empty state |
| `SAMPLE_DIALOGS` | Eight canned `DialogItem` entries representing a returning user's chat history |
| `SAMPLE_QUICK_ACTIONS` | Five `MingoQuickAction` chips passed to `EmbeddableChat` for the welcome view |
| `FAE_AGENT_CONFIG` | Mocked `/api/ai-agents/fae` response for agent-mode quick-action chip rendering |
| `COMMANDS_URL` / `COMMANDS_PREFIX` | Constants shared between the runtime mock and the `fetch` shim for slash-command stubs |
## Usage Example
```typescript
// Wrap EmbeddableChat in the required providers for a story
function MemoizedRuntime({ children }: { children: React.ReactNode }) {
const runtime = useMemo(() => createMockRuntime(), [])
const queryClient = useMemo(() => new QueryClient(), [])
return (
{children}
)
}
// Returning-user story with dialog history
export const ReturningUser: StoryObj = {
render: () => (
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
await userEvent.click(canvas.getByRole('button', { name: /history/i }))
},
}
```
## Notes
- The `pending()` helper (`new Promise(() => {})`) is the idiomatic way to freeze a loading state in Storybook without fake timers.
- The `fetch` shim intercepts `COMMANDS_URL` and `AI_AGENT_CONFIG_PREFIX` requests so agent-mode and slash-command UI renders without a live backend.
- Source: [`EmbeddableChat.stories.tsx`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/EmbeddableChat.stories.tsx)