{"_id":"@bernierllc/onboarding-chat-ui","_rev":"4-15c7befdaab4253bb0b520c2931da885","name":"@bernierllc/onboarding-chat-ui","dist-tags":{"latest":"0.1.2"},"versions":{"0.0.1":{"name":"@bernierllc/onboarding-chat-ui","version":"0.0.1","keywords":["oidc","trusted-publishing","setup"],"_id":"@bernierllc/onboarding-chat-ui@0.0.1","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"fa185a5442d10d46fe0cf5c3fe58c2ad7fed3b3e","tarball":"https://registry.npmjs.org/@bernierllc/onboarding-chat-ui/-/onboarding-chat-ui-0.0.1.tgz","fileCount":2,"integrity":"sha512-USI78Pgr9XGemq3mDABPkQ0+33sbtLZQ+c9u3q+2QCCTdD6RxdcUC5/kCaSA7C/YsVrk/8jcWgQrHUlQjk6/4Q==","signatures":[{"sig":"MEYCIQDEcfWSodiJkmk8+4UXPcuQ2P1DvpW9G8JJkLSpZwXnHwIhAJG4XqhTWMxHVKH1c2TxU3sHjy1ZlopPr0E33jH1KzfT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2083},"_npmUser":{"name":"mkbernier","email":"mkbernier@gmail.com"},"_npmVersion":"11.12.1","description":"OIDC trusted publishing setup package for @bernierllc/onboarding-chat-ui","directories":{},"_nodeVersion":"25.9.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/onboarding-chat-ui_0.0.1_1781984293340_0.5896894402617532","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@bernierllc/onboarding-chat-ui","version":"0.1.0","keywords":["onboarding","chat","ui","react","components","sse","typescript"],"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE","_id":"@bernierllc/onboarding-chat-ui@0.1.0","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"23439acb4ca7c7a43a686fb4189bdc0f94d56e23","tarball":"https://registry.npmjs.org/@bernierllc/onboarding-chat-ui/-/onboarding-chat-ui-0.1.0.tgz","fileCount":63,"integrity":"sha512-/VPm3BKF46ZTzTSp/JxTqM94Qw/H6zatSWBn5kERhQv+dn7xmABOYGpQUPDRfpXCJymWH5qwmi/jBRQkv566Hg==","signatures":[{"sig":"MEQCIQDV/yvN/bf08HsiBvLN1mNtxPOwcbWfXcopyuw7WxEdgQIfIcAtySVvjGiC2Edf5b2GJm/f2sJCrG/Oyr0NKRV2fA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103023},"main":"dist/index.js","_from":"file:bernierllc-onboarding-chat-ui-0.1.0.tgz","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts,.tsx","test":"echo 'Tests skipped for initial publish'","build":"tsc","clean":"rm -rf dist","test:run":"jest --watchAll=false","test:watch":"jest --watch","test:coverage":"jest --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f24fd4b6-6310-42b6-87b2-0269391ed97e"}},"_resolved":"/home/runner/work/tools/tools/packages/ui/onboarding-chat-ui/bernierllc-onboarding-chat-ui-0.1.0.tgz","_integrity":"sha512-/VPm3BKF46ZTzTSp/JxTqM94Qw/H6zatSWBn5kERhQv+dn7xmABOYGpQUPDRfpXCJymWH5qwmi/jBRQkv566Hg==","bernierllc":{"runtime":"browser","category":"ui","integration":{"logger":"optional","neverhub":"not-applicable","neveradmin":"optional"}},"_npmVersion":"11.17.0","description":"React onboarding chat UI: split-pane chat with side panels, progress checklist, completion and rating, attachment dropzone, auto-greeting, and onboarding SSE hooks.","directories":{},"_nodeVersion":"24.16.0","dependencies":{"@bernierllc/logger":"1.7.0","@bernierllc/messaging-ui":"0.4.0","@bernierllc/onboarding-config-core":"0.2.0","@bernierllc/onboarding-feature-plugin":"0.2.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","react":"^18.0.0","eslint":"^8.45.0","ts-jest":"^29.1.0","react-dom":"^18.0.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/react":"^18.0.0","@types/react-dom":"^18.0.0","@testing-library/react":"^13.4.0","jest-environment-jsdom":"^29.5.0","@testing-library/jest-dom":"^5.16.0","@typescript-eslint/parser":"^6.0.0","@testing-library/user-event":"^14.4.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/onboarding-chat-ui_0.1.0_1781986010903_0.6229850108758235","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bernierllc/onboarding-chat-ui","version":"0.1.1","keywords":["onboarding","chat","ui","react","components","sse","typescript"],"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE","_id":"@bernierllc/onboarding-chat-ui@0.1.1","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"1169bd184432d02e7beb2634ec4b88d7c5a2262a","tarball":"https://registry.npmjs.org/@bernierllc/onboarding-chat-ui/-/onboarding-chat-ui-0.1.1.tgz","fileCount":63,"integrity":"sha512-TSvv9QfXzZK9pk7AGz9syBKbVBf0IZ+4ZiAjgeD2eOQ9a0gm7yap7h4CxxBcczYgv4gjQilhNvBZqWFXdVrz+Q==","signatures":[{"sig":"MEYCIQCN2E5qGAfZC8Nl5iHwOBXFYF6GZyeoj7vDuUQ/6FlSjAIhAJL4CNF1rD4PyXhQmQJrsf7KeYdUyYtIzJak591jGISC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103023},"main":"dist/index.js","_from":"file:bernierllc-onboarding-chat-ui-0.1.1.tgz","types":"dist/index.d.ts","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts,.tsx","test":"echo 'Tests skipped for initial publish'","build":"tsc","clean":"rm -rf dist","test:run":"jest --watchAll=false","test:watch":"jest --watch","test:coverage":"jest --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f24fd4b6-6310-42b6-87b2-0269391ed97e"}},"_resolved":"/home/runner/work/tools/tools/packages/ui/onboarding-chat-ui/bernierllc-onboarding-chat-ui-0.1.1.tgz","_integrity":"sha512-TSvv9QfXzZK9pk7AGz9syBKbVBf0IZ+4ZiAjgeD2eOQ9a0gm7yap7h4CxxBcczYgv4gjQilhNvBZqWFXdVrz+Q==","bernierllc":{"runtime":"browser","category":"ui","integration":{"logger":"optional","neverhub":"not-applicable","neveradmin":"optional"}},"_npmVersion":"12.0.1","description":"React onboarding chat UI: split-pane chat with side panels, progress checklist, completion and rating, attachment dropzone, auto-greeting, and onboarding SSE hooks.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"@bernierllc/logger":"1.7.1","@bernierllc/messaging-ui":"0.4.0","@bernierllc/onboarding-config-core":"0.2.1","@bernierllc/onboarding-feature-plugin":"0.2.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","react":"^18.0.0","eslint":"^8.45.0","ts-jest":"^29.1.0","react-dom":"^18.0.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/react":"^18.0.0","@types/react-dom":"^18.0.0","@testing-library/react":"^13.4.0","jest-environment-jsdom":"^29.5.0","@testing-library/jest-dom":"^5.16.0","@typescript-eslint/parser":"^6.0.0","@testing-library/user-event":"^14.4.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"tmp":"tmp/onboarding-chat-ui_0.1.1_1784016166607_0.5530595962105913","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"_id":"@bernierllc/onboarding-chat-ui@0.1.2","dist":{"shasum":"84edf80d1efbd6db491e4c6a6fea15688fd63848","tarball":"https://registry.npmjs.org/@bernierllc/onboarding-chat-ui/-/onboarding-chat-ui-0.1.2.tgz","fileCount":63,"integrity":"sha512-FCjlVAbYMLN9cgZ1XV4vDZ9H//kZ6b6ZBhO/KdOPYgl824M/8301/zPZiUiIw8PeQUyQPwYllrSJ4byxy4JdaA==","signatures":[{"sig":"MEUCIBMkyr67lGbITkblgDe2oIFclZc+n4V1sV31UIkB5HgwAiEAzrivtshjSb+1+3Q2coSP1xfGwCFZv6XVgU1Y1VNbHK4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDN9h0/WzFzdngqo3PI3FUAfui8f9bDE16qlFvQ+ZgdGgIhAKAkrjjX4MaF9dJAdKG8HUoT+w6h2NMn10nEUJC/h/55"}],"unpackedSize":103027},"main":"dist/index.js","name":"@bernierllc/onboarding-chat-ui","_from":"file:bernierllc-onboarding-chat-ui-0.1.2.tgz","types":"dist/index.d.ts","author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE","scripts":{"dev":"tsc --watch","lint":"eslint src --ext .ts,.tsx","test":"echo 'Tests skipped for initial publish'","build":"tsc","clean":"rm -rf dist","test:run":"jest --watchAll=false","test:watch":"jest --watch","test:coverage":"jest --coverage"},"version":"0.1.2","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"f24fd4b6-6310-42b6-87b2-0269391ed97e"}},"keywords":["onboarding","chat","ui","react","components","sse","typescript"],"_resolved":"/home/runner/work/tools/tools/packages/ui/onboarding-chat-ui/bernierllc-onboarding-chat-ui-0.1.2.tgz","_integrity":"sha512-FCjlVAbYMLN9cgZ1XV4vDZ9H//kZ6b6ZBhO/KdOPYgl824M/8301/zPZiUiIw8PeQUyQPwYllrSJ4byxy4JdaA==","bernierllc":{"runtime":"browser","category":"ui","integration":{"logger":"optional","neverhub":"not-applicable","neveradmin":"optional"}},"_npmVersion":"12.2.0","description":"React onboarding chat UI: split-pane chat with side panels, progress checklist, completion and rating, attachment dropzone, auto-greeting, and onboarding SSE hooks.","directories":{},"maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"_nodeVersion":"24.21.0","dependencies":{"@bernierllc/logger":"^1.7.1","@bernierllc/messaging-ui":"^0.4.0","@bernierllc/onboarding-config-core":"^0.2.1","@bernierllc/onboarding-feature-plugin":"^0.2.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","react":"^18.0.0","eslint":"^8.45.0","ts-jest":"^29.1.0","react-dom":"^18.0.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/react":"^18.0.0","@types/react-dom":"^18.0.0","@testing-library/react":"^13.4.0","jest-environment-jsdom":"^29.5.0","@testing-library/jest-dom":"^5.16.0","@typescript-eslint/parser":"^6.0.0","@testing-library/user-event":"^14.4.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"react":">=16.8.0","react-dom":">=16.8.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/onboarding-chat-ui_0.1.2_1790797295749_0.12327397105346449"}}},"time":{"created":"2026-06-20T19:38:13.172Z","modified":"2026-09-30T19:41:36.047Z","0.0.1":"2026-06-20T19:38:13.484Z","0.1.0":"2026-06-20T20:06:51.037Z","0.1.1":"2026-07-14T08:02:46.778Z","0.1.2":"2026-09-30T19:41:35.826Z"},"author":{"name":"Bernier LLC"},"license":"SEE LICENSE IN LICENSE","keywords":["onboarding","chat","ui","react","components","sse","typescript"],"description":"React onboarding chat UI: split-pane chat with side panels, progress checklist, completion and rating, attachment dropzone, auto-greeting, and onboarding SSE hooks.","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"readme":"# @bernierllc/onboarding-chat-ui\n\nReact UI component library for onboarding chat experiences. Provides a full-featured streaming chat interface backed by Server-Sent Events (SSE), goal progress tracking, plugin-driven side panels, and completion handoffs — all wired to `@bernierllc/onboarding-config-core` configuration objects.\n\n## Installation\n\n```bash\nnpm install @bernierllc/onboarding-chat-ui\n```\n\nPeer dependencies:\n\n```bash\nnpm install react react-dom @bernierllc/onboarding-config-core @bernierllc/onboarding-feature-plugin\n```\n\n## Usage\n\n```tsx\nimport { OnboardingChat } from '@bernierllc/onboarding-chat-ui';\nimport type { OnboardingConfig } from '@bernierllc/onboarding-config-core';\n\nconst config: OnboardingConfig = {\n  id: 'my-onboarding',\n  name: 'Getting Started',\n  persona: {\n    tone: 'friendly-expert',\n    greeting: \"Hi! Let's get you set up.\",\n    askOneAtATime: true,\n  },\n  phases: [{ id: 'setup', title: 'Setup', guidance: 'Configure your account.', order: 1 }],\n  goals: [\n    {\n      id: 'add-logo',\n      description: 'Add your logo',\n      required: true,\n      phase: 'setup',\n      completionCheck: { type: 'field-present', field: 'logoUrl' },\n    },\n  ],\n  completionCriteria: { requireAllGoals: true },\n  handoffs: [{ id: 'dashboard', type: 'route', label: 'Go to Dashboard', order: 1 }],\n  features: { enabledPlugins: [], pluginConfig: {} },\n};\n\nexport default function OnboardingPage() {\n  return (\n    <OnboardingChat\n      chatEndpoint=\"/api/onboarding/chat\"\n      sessionId=\"sess-abc123\"\n      userId=\"user-xyz\"\n      config={config}\n      onComplete={(status) => console.log('Onboarding complete', status)}\n    />\n  );\n}\n```\n\n### Custom Hooks Usage\n\nUse the low-level hooks directly to build a custom UI:\n\n```tsx\nimport { useOnboardingChat, useGoalProgress } from '@bernierllc/onboarding-chat-ui';\n\nfunction MyCustomChat({ config }) {\n  const { messages, send, isStreaming, setupStatus, isComplete, error } = useOnboardingChat({\n    chatEndpoint: '/api/chat',\n    sessionId: 'sess-1',\n    userId: 'user-1',\n  });\n\n  const { goalItems, requiredMet, requiredTotal } = useGoalProgress({\n    goals: config.goals,\n    setupStatus,\n  });\n\n  return (\n    <div>\n      {error && <p>Error: {error.message}</p>}\n      <p>{requiredMet}/{requiredTotal} goals complete</p>\n      {messages.map(m => <div key={m.id}>{m.role}: {m.content}</div>)}\n      {isComplete && <p>All done!</p>}\n      <button disabled={isStreaming} onClick={() => send('Hello')}>Send</button>\n    </div>\n  );\n}\n```\n\n## API\n\n### `OnboardingChat` Component\n\nRoot orchestrator component. Renders the three-column layout: chat pane, progress checklist, and side panel.\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `chatEndpoint` | `string` | Yes | POST endpoint for chat messages |\n| `config` | `OnboardingConfig` | Yes | Onboarding configuration object |\n| `sessionId` | `string` | Yes | Unique session identifier |\n| `userId` | `string` | Yes | Current user identifier |\n| `statusEndpoint` | `string` | No | Endpoint for goal status polling |\n| `ratingEndpoint` | `string` | No | Endpoint for thumbs up/down ratings |\n| `panelDescriptors` | `PluginPanelDescriptor[]` | No | Plugin panel slot declarations |\n| `panelComponents` | `Record<string, React.ComponentType>` | No | React components keyed by panel slot |\n| `onComplete` | `(status: SetupStatus \\| null) => void` | No | Callback when onboarding completes |\n| `fetchFn` | `typeof fetch` | No | Injectable fetch (useful for tests) |\n| `className` | `string` | No | Additional CSS class |\n\n### `ChatPane` Component\n\nThe message thread plus input area.\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `messages` | `OnboardingMessage[]` | Yes | Current message list |\n| `isStreaming` | `boolean` | Yes | Whether an SSE stream is in progress |\n| `onSend` | `(text: string, attachments?: Attachment[]) => void` | Yes | Send handler |\n| `className` | `string` | No | Additional CSS class |\n\n### `ProgressChecklist` Component\n\nRenders goal items with check/incomplete badges, driven by `SetupStatus` from the SSE stream.\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `goals` | `OnboardingGoal[]` | Yes | Goals from `OnboardingConfig` |\n| `status` | `SetupStatus \\| null` | Yes | Latest status from SSE stream |\n| `showRequired` | `boolean` | No | Filter to required goals only |\n| `className` | `string` | No | Additional CSS class |\n\n### `SidePanel` Component\n\nPlugin slot container. Renders the component registered for the currently active panel slot.\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `activePanel` | `string \\| null` | Yes | Currently active slot key |\n| `panelComponents` | `Record<string, React.ComponentType>` | Yes | Component map by slot |\n| `fallback` | `React.ReactNode` | No | Rendered when no active panel |\n| `className` | `string` | No | Additional CSS class |\n\n### `CompletionCard` Component\n\nShown when the onboarding is complete.\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `onboardingName` | `string` | Yes | Display name of the onboarding flow |\n| `handoffs` | `HandoffTarget[]` | Yes | Available next steps from config |\n| `onHandoffClick` | `(target: HandoffTarget) => void` | Yes | Called when user clicks a handoff |\n| `children` | `React.ReactNode` | No | Optional extra content |\n| `className` | `string` | No | Additional CSS class |\n\n### `RatingBar` Component\n\nThumbs up / thumbs down rating widget.\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `onRate` | `(rating: 'up' \\| 'down') => void` | Yes | Called with the selected rating |\n| `className` | `string` | No | Additional CSS class |\n\n### `AttachmentDropzone` Component\n\nDrag-and-drop file picker. Converts files to base64 data URLs and calls `onAttach`.\n\n| Prop | Type | Required | Description |\n|------|------|----------|-------------|\n| `onAttach` | `(attachments: Attachment[]) => void` | Yes | Called with converted attachments |\n| `accept` | `string` | No | File types for the hidden input (e.g. `\"image/*\"`) |\n| `maxSizeMB` | `number` | No | Max file size (default: 5 MB) |\n| `className` | `string` | No | Additional CSS class |\n\n### `useOnboardingChat` Hook\n\nCore hook managing SSE streaming, message accumulation, and state transitions.\n\n```tsx\nimport { useOnboardingChat } from '@bernierllc/onboarding-chat-ui';\n\nconst {\n  messages,       // OnboardingMessage[]\n  send,           // (text: string, attachments?: Attachment[]) => void\n  isStreaming,    // boolean\n  toolCallEvents, // ToolCallEvent[]\n  lastToolCall,   // ToolCallEvent | null\n  setupStatus,    // SetupStatus | null\n  isComplete,     // boolean\n  error,          // Error | null\n} = useOnboardingChat({\n  chatEndpoint: '/api/chat',\n  sessionId: 'sess-1',\n  userId: 'user-1',\n  fetchFn: customFetch, // optional, defaults to window.fetch\n});\n```\n\n**Options:**\n\n| Option | Type | Required | Description |\n|--------|------|----------|-------------|\n| `chatEndpoint` | `string` | Yes | POST endpoint URL |\n| `sessionId` | `string` | Yes | Session ID sent in request body |\n| `userId` | `string` | Yes | User ID sent in request body |\n| `fetchFn` | `typeof fetch` | No | Injectable fetch (testing/SSR) |\n\n### `useGoalProgress` Hook\n\nDerives display-ready goal items from raw goals and live `SetupStatus`.\n\n```tsx\nimport { useGoalProgress } from '@bernierllc/onboarding-chat-ui';\n\nconst { goalItems, requiredMet, requiredTotal, isComplete } = useGoalProgress({\n  goals: config.goals,\n  setupStatus,\n});\n```\n\n### `usePanelRegistry` Hook\n\nDetermines which plugin panel slot is active based on recent tool call events.\n\n```tsx\nimport { usePanelRegistry } from '@bernierllc/onboarding-chat-ui';\n\nconst { activePanel } = usePanelRegistry({\n  panelDescriptors: config.features.panelDescriptors ?? [],\n  toolCallEvents,\n});\n```\n\n### `useAutoGreeting` Hook\n\nFires an initial greeting message after a configurable delay when the message list is empty.\n\n```tsx\nimport { useAutoGreeting } from '@bernierllc/onboarding-chat-ui';\n\nuseAutoGreeting({\n  messages,\n  send,\n  greeting: config.persona.greeting,\n  delayMs: 500, // default\n});\n```\n\n### `OnboardingChatProvider` / `useOnboardingChatContext`\n\nShare chat state across a component subtree without prop drilling.\n\n```tsx\nimport { OnboardingChatProvider, useOnboardingChatContext } from '@bernierllc/onboarding-chat-ui';\n\nfunction App() {\n  return (\n    <OnboardingChatProvider value={chatState}>\n      <MyPanel />\n    </OnboardingChatProvider>\n  );\n}\n\nfunction MyPanel() {\n  const { messages, isStreaming } = useOnboardingChatContext();\n  return <div>{isStreaming ? 'Thinking...' : `${messages.length} messages`}</div>;\n}\n```\n\n### `OnboardingUIError`\n\nAll errors thrown by this package are instances of `OnboardingUIError` with a `code` field and optional `cause` chain.\n\n```ts\nimport { OnboardingUIError } from '@bernierllc/onboarding-chat-ui';\n\nif (error instanceof OnboardingUIError) {\n  console.error(error.code, error.message, error.cause);\n}\n```\n\n| Code | Cause |\n|------|-------|\n| `CHAT_REQUEST_FAILED` | Non-2xx HTTP response from chat endpoint |\n| `NO_RESPONSE_BODY` | Successful HTTP response but `body` is null |\n| `STREAM_ERROR` | Exception thrown during streaming (network failure, parse error) |\n| `FILE_READ_ERROR` | `FileReader` error inside `AttachmentDropzone` |\n\n## Integration Documentation\n\n### Logger Integration\n\nThis package uses `@bernierllc/logger` for structured error logging. All caught errors are logged at the `error` level with full context before propagating to the caller. The logger auto-detects the service environment; no configuration is required.\n\n```ts\n// Internal usage — no setup needed by consumers\nimport { logger } from '@bernierllc/logger';\nlogger.error('OnboardingUIError during chat stream', error, { context });\n```\n\n### NeverHub Integration\n\nThis package supports optional NeverHub integration for real-time event tracking and session telemetry. When `@bernierllc/neverhub-adapter` is available in the environment and `NeverHubAdapter.detect()` returns `true`, the `OnboardingChat` component registers itself and emits lifecycle events. Core functionality works regardless of NeverHub availability (graceful degradation).\n\n```ts\n// NeverHub auto-detection pattern (internal)\nimport { NeverHubAdapter } from '@bernierllc/neverhub-adapter';\n\nif (await NeverHubAdapter.detect()) {\n  const adapter = new NeverHubAdapter();\n  await adapter.register({ type: 'onboarding-chat-ui', sessionId });\n}\n```\n\nTo enable NeverHub in your app, install and configure the adapter before rendering `OnboardingChat`. No additional props are required.\n\n### SSE Stream Protocol\n\nThe backend chat endpoint must respond with `Content-Type: text/event-stream`. Each event is a newline-delimited JSON frame:\n\n```\ndata: {\"type\":\"delta\",\"delta\":\"Hello \"}\\n\\n\ndata: {\"type\":\"delta\",\"delta\":\"world!\"}\\n\\n\ndata: {\"type\":\"tool_call\",\"toolName\":\"preview_site\",\"args\":{\"url\":\"https://example.com\"}}\\n\\n\ndata: {\"type\":\"status\",\"status\":{...GoalProgress...}}\\n\\n\ndata: {\"type\":\"complete\"}\\n\\n\n```\n\n| Event type | Payload fields | Effect |\n|------------|---------------|--------|\n| `delta` | `delta: string` | Appends to the current assistant message |\n| `tool_call` | `toolName: string`, `args: unknown` | Pushes to `toolCallEvents`, updates `lastToolCall`, activates side panel |\n| `status` | `status: GoalProgress` | Updates `setupStatus` and goal checklist |\n| `complete` | — | Sets `isComplete: true`, calls `onComplete` callback |\n\n### Testing Integration\n\nThe package provides `fetchFn` prop/option for full test isolation without mocking globals:\n\n```tsx\nimport { useOnboardingChat } from '@bernierllc/onboarding-chat-ui';\nimport { renderHook, act } from '@testing-library/react';\n\nconst mockFetch: typeof fetch = async () => ({\n  ok: true,\n  status: 200,\n  body: { getReader: () => myCustomReader },\n} as unknown as Response);\n\nconst { result } = renderHook(() =>\n  useOnboardingChat({ chatEndpoint: '/api/chat', sessionId: 's', userId: 'u', fetchFn: mockFetch })\n);\n```\n\n## Browser Requirements\n\nThis package is browser-only. It uses `fetch`, `ReadableStream`, `TextDecoder`, and `FileReader`. It does not import Node.js built-ins.\n\n## License\n\nCopyright (c) 2025 Bernier LLC. Limited-use license — see package header.\n","readmeFilename":"README.md"}