@bernierllc/onboarding-chat-ui 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +344 -28
  3. package/dist/components/AttachmentDropzone.d.ts +11 -0
  4. package/dist/components/AttachmentDropzone.d.ts.map +1 -0
  5. package/dist/components/AttachmentDropzone.js +128 -0
  6. package/dist/components/AttachmentDropzone.js.map +1 -0
  7. package/dist/components/ChatPane.d.ts +12 -0
  8. package/dist/components/ChatPane.d.ts.map +1 -0
  9. package/dist/components/ChatPane.js +54 -0
  10. package/dist/components/ChatPane.js.map +1 -0
  11. package/dist/components/CompletionCard.d.ts +9 -0
  12. package/dist/components/CompletionCard.d.ts.map +1 -0
  13. package/dist/components/CompletionCard.js +14 -0
  14. package/dist/components/CompletionCard.js.map +1 -0
  15. package/dist/components/OnboardingChat.d.ts +14 -0
  16. package/dist/components/OnboardingChat.d.ts.map +1 -0
  17. package/dist/components/OnboardingChat.js +72 -0
  18. package/dist/components/OnboardingChat.js.map +1 -0
  19. package/dist/components/ProgressChecklist.d.ts +9 -0
  20. package/dist/components/ProgressChecklist.d.ts.map +1 -0
  21. package/dist/components/ProgressChecklist.js +20 -0
  22. package/dist/components/ProgressChecklist.js.map +1 -0
  23. package/dist/components/RatingBar.d.ts +9 -0
  24. package/dist/components/RatingBar.d.ts.map +1 -0
  25. package/dist/components/RatingBar.js +38 -0
  26. package/dist/components/RatingBar.js.map +1 -0
  27. package/dist/components/SidePanel.d.ts +11 -0
  28. package/dist/components/SidePanel.d.ts.map +1 -0
  29. package/dist/components/SidePanel.js +13 -0
  30. package/dist/components/SidePanel.js.map +1 -0
  31. package/dist/context/OnboardingChatContext.d.ts +29 -0
  32. package/dist/context/OnboardingChatContext.d.ts.map +1 -0
  33. package/dist/context/OnboardingChatContext.js +30 -0
  34. package/dist/context/OnboardingChatContext.js.map +1 -0
  35. package/dist/errors.d.ts +16 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +27 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/hooks/useAutoGreeting.d.ts +9 -0
  40. package/dist/hooks/useAutoGreeting.d.ts.map +1 -0
  41. package/dist/hooks/useAutoGreeting.js +36 -0
  42. package/dist/hooks/useAutoGreeting.js.map +1 -0
  43. package/dist/hooks/useGoalProgress.d.ts +10 -0
  44. package/dist/hooks/useGoalProgress.d.ts.map +1 -0
  45. package/dist/hooks/useGoalProgress.js +48 -0
  46. package/dist/hooks/useGoalProgress.js.map +1 -0
  47. package/dist/hooks/useOnboardingChat.d.ts +16 -0
  48. package/dist/hooks/useOnboardingChat.d.ts.map +1 -0
  49. package/dist/hooks/useOnboardingChat.js +172 -0
  50. package/dist/hooks/useOnboardingChat.js.map +1 -0
  51. package/dist/hooks/usePanelRegistry.d.ts +11 -0
  52. package/dist/hooks/usePanelRegistry.d.ts.map +1 -0
  53. package/dist/hooks/usePanelRegistry.js +44 -0
  54. package/dist/hooks/usePanelRegistry.js.map +1 -0
  55. package/dist/index.d.ts +16 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +25 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/types/ui-types.d.ts +161 -0
  60. package/dist/types/ui-types.d.ts.map +1 -0
  61. package/dist/types/ui-types.js +9 -0
  62. package/dist/types/ui-types.js.map +1 -0
  63. package/package.json +70 -7
package/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Copyright (c) 2025 Bernier LLC
2
+
3
+ This file is licensed to the client under a limited-use license.
4
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
5
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
package/README.md CHANGED
@@ -1,45 +1,361 @@
1
1
  # @bernierllc/onboarding-chat-ui
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ React 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.
4
4
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
5
+ ## Installation
6
6
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
7
+ ```bash
8
+ npm install @bernierllc/onboarding-chat-ui
9
+ ```
8
10
 
9
- ## Purpose
11
+ Peer dependencies:
10
12
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@bernierllc/onboarding-chat-ui`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
13
+ ```bash
14
+ npm install react react-dom @bernierllc/onboarding-config-core @bernierllc/onboarding-feature-plugin
15
+ ```
15
16
 
16
- ## What is OIDC Trusted Publishing?
17
+ ## Usage
17
18
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
19
+ ```tsx
20
+ import { OnboardingChat } from '@bernierllc/onboarding-chat-ui';
21
+ import type { OnboardingConfig } from '@bernierllc/onboarding-config-core';
19
22
 
20
- ## Setup Instructions
23
+ const config: OnboardingConfig = {
24
+ id: 'my-onboarding',
25
+ name: 'Getting Started',
26
+ persona: {
27
+ tone: 'friendly-expert',
28
+ greeting: "Hi! Let's get you set up.",
29
+ askOneAtATime: true,
30
+ },
31
+ phases: [{ id: 'setup', title: 'Setup', guidance: 'Configure your account.', order: 1 }],
32
+ goals: [
33
+ {
34
+ id: 'add-logo',
35
+ description: 'Add your logo',
36
+ required: true,
37
+ phase: 'setup',
38
+ completionCheck: { type: 'field-present', field: 'logoUrl' },
39
+ },
40
+ ],
41
+ completionCriteria: { requireAllGoals: true },
42
+ handoffs: [{ id: 'dashboard', type: 'route', label: 'Go to Dashboard', order: 1 }],
43
+ features: { enabledPlugins: [], pluginConfig: {} },
44
+ };
21
45
 
22
- To properly configure OIDC trusted publishing for this package:
46
+ export default function OnboardingPage() {
47
+ return (
48
+ <OnboardingChat
49
+ chatEndpoint="/api/onboarding/chat"
50
+ sessionId="sess-abc123"
51
+ userId="user-xyz"
52
+ config={config}
53
+ onComplete={(status) => console.log('Onboarding complete', status)}
54
+ />
55
+ );
56
+ }
57
+ ```
23
58
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
59
+ ### Custom Hooks Usage
28
60
 
29
- ## DO NOT USE THIS PACKAGE
61
+ Use the low-level hooks directly to build a custom UI:
30
62
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
63
+ ```tsx
64
+ import { useOnboardingChat, useGoalProgress } from '@bernierllc/onboarding-chat-ui';
36
65
 
37
- ## More Information
66
+ function MyCustomChat({ config }) {
67
+ const { messages, send, isStreaming, setupStatus, isComplete, error } = useOnboardingChat({
68
+ chatEndpoint: '/api/chat',
69
+ sessionId: 'sess-1',
70
+ userId: 'user-1',
71
+ });
38
72
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
73
+ const { goalItems, requiredMet, requiredTotal } = useGoalProgress({
74
+ goals: config.goals,
75
+ setupStatus,
76
+ });
42
77
 
43
- ---
78
+ return (
79
+ <div>
80
+ {error && <p>Error: {error.message}</p>}
81
+ <p>{requiredMet}/{requiredTotal} goals complete</p>
82
+ {messages.map(m => <div key={m.id}>{m.role}: {m.content}</div>)}
83
+ {isComplete && <p>All done!</p>}
84
+ <button disabled={isStreaming} onClick={() => send('Hello')}>Send</button>
85
+ </div>
86
+ );
87
+ }
88
+ ```
44
89
 
45
- **Maintained for OIDC setup purposes only**
90
+ ## API
91
+
92
+ ### `OnboardingChat` Component
93
+
94
+ Root orchestrator component. Renders the three-column layout: chat pane, progress checklist, and side panel.
95
+
96
+ | Prop | Type | Required | Description |
97
+ |------|------|----------|-------------|
98
+ | `chatEndpoint` | `string` | Yes | POST endpoint for chat messages |
99
+ | `config` | `OnboardingConfig` | Yes | Onboarding configuration object |
100
+ | `sessionId` | `string` | Yes | Unique session identifier |
101
+ | `userId` | `string` | Yes | Current user identifier |
102
+ | `statusEndpoint` | `string` | No | Endpoint for goal status polling |
103
+ | `ratingEndpoint` | `string` | No | Endpoint for thumbs up/down ratings |
104
+ | `panelDescriptors` | `PluginPanelDescriptor[]` | No | Plugin panel slot declarations |
105
+ | `panelComponents` | `Record<string, React.ComponentType>` | No | React components keyed by panel slot |
106
+ | `onComplete` | `(status: SetupStatus \| null) => void` | No | Callback when onboarding completes |
107
+ | `fetchFn` | `typeof fetch` | No | Injectable fetch (useful for tests) |
108
+ | `className` | `string` | No | Additional CSS class |
109
+
110
+ ### `ChatPane` Component
111
+
112
+ The message thread plus input area.
113
+
114
+ | Prop | Type | Required | Description |
115
+ |------|------|----------|-------------|
116
+ | `messages` | `OnboardingMessage[]` | Yes | Current message list |
117
+ | `isStreaming` | `boolean` | Yes | Whether an SSE stream is in progress |
118
+ | `onSend` | `(text: string, attachments?: Attachment[]) => void` | Yes | Send handler |
119
+ | `className` | `string` | No | Additional CSS class |
120
+
121
+ ### `ProgressChecklist` Component
122
+
123
+ Renders goal items with check/incomplete badges, driven by `SetupStatus` from the SSE stream.
124
+
125
+ | Prop | Type | Required | Description |
126
+ |------|------|----------|-------------|
127
+ | `goals` | `OnboardingGoal[]` | Yes | Goals from `OnboardingConfig` |
128
+ | `status` | `SetupStatus \| null` | Yes | Latest status from SSE stream |
129
+ | `showRequired` | `boolean` | No | Filter to required goals only |
130
+ | `className` | `string` | No | Additional CSS class |
131
+
132
+ ### `SidePanel` Component
133
+
134
+ Plugin slot container. Renders the component registered for the currently active panel slot.
135
+
136
+ | Prop | Type | Required | Description |
137
+ |------|------|----------|-------------|
138
+ | `activePanel` | `string \| null` | Yes | Currently active slot key |
139
+ | `panelComponents` | `Record<string, React.ComponentType>` | Yes | Component map by slot |
140
+ | `fallback` | `React.ReactNode` | No | Rendered when no active panel |
141
+ | `className` | `string` | No | Additional CSS class |
142
+
143
+ ### `CompletionCard` Component
144
+
145
+ Shown when the onboarding is complete.
146
+
147
+ | Prop | Type | Required | Description |
148
+ |------|------|----------|-------------|
149
+ | `onboardingName` | `string` | Yes | Display name of the onboarding flow |
150
+ | `handoffs` | `HandoffTarget[]` | Yes | Available next steps from config |
151
+ | `onHandoffClick` | `(target: HandoffTarget) => void` | Yes | Called when user clicks a handoff |
152
+ | `children` | `React.ReactNode` | No | Optional extra content |
153
+ | `className` | `string` | No | Additional CSS class |
154
+
155
+ ### `RatingBar` Component
156
+
157
+ Thumbs up / thumbs down rating widget.
158
+
159
+ | Prop | Type | Required | Description |
160
+ |------|------|----------|-------------|
161
+ | `onRate` | `(rating: 'up' \| 'down') => void` | Yes | Called with the selected rating |
162
+ | `className` | `string` | No | Additional CSS class |
163
+
164
+ ### `AttachmentDropzone` Component
165
+
166
+ Drag-and-drop file picker. Converts files to base64 data URLs and calls `onAttach`.
167
+
168
+ | Prop | Type | Required | Description |
169
+ |------|------|----------|-------------|
170
+ | `onAttach` | `(attachments: Attachment[]) => void` | Yes | Called with converted attachments |
171
+ | `accept` | `string` | No | File types for the hidden input (e.g. `"image/*"`) |
172
+ | `maxSizeMB` | `number` | No | Max file size (default: 5 MB) |
173
+ | `className` | `string` | No | Additional CSS class |
174
+
175
+ ### `useOnboardingChat` Hook
176
+
177
+ Core hook managing SSE streaming, message accumulation, and state transitions.
178
+
179
+ ```tsx
180
+ import { useOnboardingChat } from '@bernierllc/onboarding-chat-ui';
181
+
182
+ const {
183
+ messages, // OnboardingMessage[]
184
+ send, // (text: string, attachments?: Attachment[]) => void
185
+ isStreaming, // boolean
186
+ toolCallEvents, // ToolCallEvent[]
187
+ lastToolCall, // ToolCallEvent | null
188
+ setupStatus, // SetupStatus | null
189
+ isComplete, // boolean
190
+ error, // Error | null
191
+ } = useOnboardingChat({
192
+ chatEndpoint: '/api/chat',
193
+ sessionId: 'sess-1',
194
+ userId: 'user-1',
195
+ fetchFn: customFetch, // optional, defaults to window.fetch
196
+ });
197
+ ```
198
+
199
+ **Options:**
200
+
201
+ | Option | Type | Required | Description |
202
+ |--------|------|----------|-------------|
203
+ | `chatEndpoint` | `string` | Yes | POST endpoint URL |
204
+ | `sessionId` | `string` | Yes | Session ID sent in request body |
205
+ | `userId` | `string` | Yes | User ID sent in request body |
206
+ | `fetchFn` | `typeof fetch` | No | Injectable fetch (testing/SSR) |
207
+
208
+ ### `useGoalProgress` Hook
209
+
210
+ Derives display-ready goal items from raw goals and live `SetupStatus`.
211
+
212
+ ```tsx
213
+ import { useGoalProgress } from '@bernierllc/onboarding-chat-ui';
214
+
215
+ const { goalItems, requiredMet, requiredTotal, isComplete } = useGoalProgress({
216
+ goals: config.goals,
217
+ setupStatus,
218
+ });
219
+ ```
220
+
221
+ ### `usePanelRegistry` Hook
222
+
223
+ Determines which plugin panel slot is active based on recent tool call events.
224
+
225
+ ```tsx
226
+ import { usePanelRegistry } from '@bernierllc/onboarding-chat-ui';
227
+
228
+ const { activePanel } = usePanelRegistry({
229
+ panelDescriptors: config.features.panelDescriptors ?? [],
230
+ toolCallEvents,
231
+ });
232
+ ```
233
+
234
+ ### `useAutoGreeting` Hook
235
+
236
+ Fires an initial greeting message after a configurable delay when the message list is empty.
237
+
238
+ ```tsx
239
+ import { useAutoGreeting } from '@bernierllc/onboarding-chat-ui';
240
+
241
+ useAutoGreeting({
242
+ messages,
243
+ send,
244
+ greeting: config.persona.greeting,
245
+ delayMs: 500, // default
246
+ });
247
+ ```
248
+
249
+ ### `OnboardingChatProvider` / `useOnboardingChatContext`
250
+
251
+ Share chat state across a component subtree without prop drilling.
252
+
253
+ ```tsx
254
+ import { OnboardingChatProvider, useOnboardingChatContext } from '@bernierllc/onboarding-chat-ui';
255
+
256
+ function App() {
257
+ return (
258
+ <OnboardingChatProvider value={chatState}>
259
+ <MyPanel />
260
+ </OnboardingChatProvider>
261
+ );
262
+ }
263
+
264
+ function MyPanel() {
265
+ const { messages, isStreaming } = useOnboardingChatContext();
266
+ return <div>{isStreaming ? 'Thinking...' : `${messages.length} messages`}</div>;
267
+ }
268
+ ```
269
+
270
+ ### `OnboardingUIError`
271
+
272
+ All errors thrown by this package are instances of `OnboardingUIError` with a `code` field and optional `cause` chain.
273
+
274
+ ```ts
275
+ import { OnboardingUIError } from '@bernierllc/onboarding-chat-ui';
276
+
277
+ if (error instanceof OnboardingUIError) {
278
+ console.error(error.code, error.message, error.cause);
279
+ }
280
+ ```
281
+
282
+ | Code | Cause |
283
+ |------|-------|
284
+ | `CHAT_REQUEST_FAILED` | Non-2xx HTTP response from chat endpoint |
285
+ | `NO_RESPONSE_BODY` | Successful HTTP response but `body` is null |
286
+ | `STREAM_ERROR` | Exception thrown during streaming (network failure, parse error) |
287
+ | `FILE_READ_ERROR` | `FileReader` error inside `AttachmentDropzone` |
288
+
289
+ ## Integration Documentation
290
+
291
+ ### Logger Integration
292
+
293
+ This 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.
294
+
295
+ ```ts
296
+ // Internal usage — no setup needed by consumers
297
+ import { logger } from '@bernierllc/logger';
298
+ logger.error('OnboardingUIError during chat stream', error, { context });
299
+ ```
300
+
301
+ ### NeverHub Integration
302
+
303
+ This 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).
304
+
305
+ ```ts
306
+ // NeverHub auto-detection pattern (internal)
307
+ import { NeverHubAdapter } from '@bernierllc/neverhub-adapter';
308
+
309
+ if (await NeverHubAdapter.detect()) {
310
+ const adapter = new NeverHubAdapter();
311
+ await adapter.register({ type: 'onboarding-chat-ui', sessionId });
312
+ }
313
+ ```
314
+
315
+ To enable NeverHub in your app, install and configure the adapter before rendering `OnboardingChat`. No additional props are required.
316
+
317
+ ### SSE Stream Protocol
318
+
319
+ The backend chat endpoint must respond with `Content-Type: text/event-stream`. Each event is a newline-delimited JSON frame:
320
+
321
+ ```
322
+ data: {"type":"delta","delta":"Hello "}\n\n
323
+ data: {"type":"delta","delta":"world!"}\n\n
324
+ data: {"type":"tool_call","toolName":"preview_site","args":{"url":"https://example.com"}}\n\n
325
+ data: {"type":"status","status":{...GoalProgress...}}\n\n
326
+ data: {"type":"complete"}\n\n
327
+ ```
328
+
329
+ | Event type | Payload fields | Effect |
330
+ |------------|---------------|--------|
331
+ | `delta` | `delta: string` | Appends to the current assistant message |
332
+ | `tool_call` | `toolName: string`, `args: unknown` | Pushes to `toolCallEvents`, updates `lastToolCall`, activates side panel |
333
+ | `status` | `status: GoalProgress` | Updates `setupStatus` and goal checklist |
334
+ | `complete` | — | Sets `isComplete: true`, calls `onComplete` callback |
335
+
336
+ ### Testing Integration
337
+
338
+ The package provides `fetchFn` prop/option for full test isolation without mocking globals:
339
+
340
+ ```tsx
341
+ import { useOnboardingChat } from '@bernierllc/onboarding-chat-ui';
342
+ import { renderHook, act } from '@testing-library/react';
343
+
344
+ const mockFetch: typeof fetch = async () => ({
345
+ ok: true,
346
+ status: 200,
347
+ body: { getReader: () => myCustomReader },
348
+ } as unknown as Response);
349
+
350
+ const { result } = renderHook(() =>
351
+ useOnboardingChat({ chatEndpoint: '/api/chat', sessionId: 's', userId: 'u', fetchFn: mockFetch })
352
+ );
353
+ ```
354
+
355
+ ## Browser Requirements
356
+
357
+ This package is browser-only. It uses `fetch`, `ReadableStream`, `TextDecoder`, and `FileReader`. It does not import Node.js built-ins.
358
+
359
+ ## License
360
+
361
+ Copyright (c) 2025 Bernier LLC. Limited-use license — see package header.
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { AttachmentDropzoneProps } from '../types/ui-types';
3
+ /**
4
+ * Drag-and-drop (and click-to-browse) attachment dropzone.
5
+ *
6
+ * Converts dropped or selected files to base64 data URLs and calls
7
+ * `onAttach` with the resulting `Attachment[]`. Enforces `maxSizeMB`
8
+ * and renders image preview thumbnails.
9
+ */
10
+ export declare function AttachmentDropzone({ accept, onAttach, maxSizeMB, className, }: AttachmentDropzoneProps): React.ReactElement;
11
+ //# sourceMappingURL=AttachmentDropzone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentDropzone.d.ts","sourceRoot":"","sources":["../../src/components/AttachmentDropzone.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAG7D,OAAO,KAAK,EAAc,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AA8B7E;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,QAAQ,EACR,SAA+B,EAC/B,SAAS,GACV,EAAE,uBAAuB,GAAG,KAAK,CAAC,YAAY,CAmL9C"}
@@ -0,0 +1,128 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ This file is licensed to the client under a limited-use license.
6
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
7
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
+ */
9
+ import { useRef, useState, useCallback } from 'react';
10
+ import { OnboardingUIError } from '../errors';
11
+ import { logger } from '@bernierllc/logger';
12
+ const DEFAULT_MAX_SIZE_MB = 5;
13
+ /**
14
+ * Convert a `File` to a base64 data URL using `FileReader`.
15
+ * Browser-safe; no Node.js imports.
16
+ */
17
+ function fileToDataUrl(file) {
18
+ return new Promise((resolve, reject) => {
19
+ const reader = new FileReader();
20
+ reader.onload = () => {
21
+ if (typeof reader.result === 'string') {
22
+ resolve(reader.result);
23
+ }
24
+ else {
25
+ reject(new OnboardingUIError('FileReader returned unexpected result type', {
26
+ code: 'FILE_READ_ERROR',
27
+ }));
28
+ }
29
+ };
30
+ reader.onerror = () => {
31
+ reject(new OnboardingUIError('FileReader error', {
32
+ code: 'FILE_READ_ERROR',
33
+ context: { fileName: file.name },
34
+ }));
35
+ };
36
+ reader.readAsDataURL(file);
37
+ });
38
+ }
39
+ /**
40
+ * Drag-and-drop (and click-to-browse) attachment dropzone.
41
+ *
42
+ * Converts dropped or selected files to base64 data URLs and calls
43
+ * `onAttach` with the resulting `Attachment[]`. Enforces `maxSizeMB`
44
+ * and renders image preview thumbnails.
45
+ */
46
+ export function AttachmentDropzone({ accept, onAttach, maxSizeMB = DEFAULT_MAX_SIZE_MB, className, }) {
47
+ const inputRef = useRef(null);
48
+ const [isDragOver, setIsDragOver] = useState(false);
49
+ const [previews, setPreviews] = useState([]);
50
+ const [sizeError, setSizeError] = useState(null);
51
+ const processFiles = useCallback(async (files) => {
52
+ if (!files || files.length === 0) {
53
+ return;
54
+ }
55
+ setSizeError(null);
56
+ const maxBytes = maxSizeMB * 1024 * 1024;
57
+ const valid = [];
58
+ for (let i = 0; i < files.length; i++) {
59
+ const file = files[i];
60
+ if (file === undefined) {
61
+ continue;
62
+ }
63
+ if (file.size > maxBytes) {
64
+ setSizeError(`"${file.name}" exceeds the ${maxSizeMB} MB size limit.`);
65
+ continue;
66
+ }
67
+ valid.push(file);
68
+ }
69
+ if (valid.length === 0) {
70
+ return;
71
+ }
72
+ try {
73
+ const attachments = await Promise.all(valid.map(async (file) => {
74
+ const dataUrl = await fileToDataUrl(file);
75
+ return {
76
+ name: file.name,
77
+ type: file.type,
78
+ dataUrl,
79
+ size: file.size,
80
+ };
81
+ }));
82
+ setPreviews(prev => [...prev, ...attachments]);
83
+ onAttach(attachments);
84
+ }
85
+ catch (err) {
86
+ if (err instanceof OnboardingUIError) {
87
+ logger.error('AttachmentDropzone file read failed', err);
88
+ }
89
+ else if (err instanceof Error) {
90
+ logger.error('AttachmentDropzone file read failed', new OnboardingUIError('File read failed', { cause: err, code: 'FILE_READ_ERROR' }));
91
+ }
92
+ }
93
+ }, [onAttach, maxSizeMB]);
94
+ const handleDrop = useCallback((e) => {
95
+ e.preventDefault();
96
+ setIsDragOver(false);
97
+ void processFiles(e.dataTransfer.files);
98
+ }, [processFiles]);
99
+ const handleDragOver = useCallback((e) => {
100
+ e.preventDefault();
101
+ setIsDragOver(true);
102
+ }, []);
103
+ const handleDragLeave = useCallback(() => {
104
+ setIsDragOver(false);
105
+ }, []);
106
+ const handleInputChange = useCallback((e) => {
107
+ void processFiles(e.target.files);
108
+ }, [processFiles]);
109
+ const handleClick = useCallback(() => {
110
+ inputRef.current?.click();
111
+ }, []);
112
+ const handleKeyDown = useCallback((e) => {
113
+ if (e.key === 'Enter' || e.key === ' ') {
114
+ e.preventDefault();
115
+ inputRef.current?.click();
116
+ }
117
+ }, []);
118
+ const removePreview = useCallback((index) => {
119
+ setPreviews(prev => prev.filter((_, i) => i !== index));
120
+ }, []);
121
+ return (_jsxs("div", { className: ['ocu-attachment-dropzone', className].filter(Boolean).join(' '), children: [_jsxs("div", { className: [
122
+ 'ocu-attachment-dropzone__zone',
123
+ isDragOver ? 'ocu-attachment-dropzone__zone--drag-over' : '',
124
+ ]
125
+ .filter(Boolean)
126
+ .join(' '), onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onClick: handleClick, onKeyDown: handleKeyDown, role: "button", tabIndex: 0, "aria-label": "Attach files", children: [_jsx("span", { className: "ocu-attachment-dropzone__icon", "aria-hidden": "true", children: "\uD83D\uDCCE" }), _jsx("span", { className: "ocu-attachment-dropzone__label", children: isDragOver ? 'Drop files here' : 'Attach files' }), _jsx("input", { ref: inputRef, type: "file", accept: accept, multiple: true, className: "ocu-attachment-dropzone__input", style: { display: 'none' }, onChange: handleInputChange, "aria-hidden": "true", tabIndex: -1 })] }), sizeError !== null && (_jsx("p", { className: "ocu-attachment-dropzone__error", role: "alert", children: sizeError })), previews.length > 0 && (_jsx("ul", { className: "ocu-attachment-dropzone__previews", children: previews.map((attachment, index) => (_jsxs("li", { className: "ocu-attachment-dropzone__preview-item", children: [attachment.type.startsWith('image/') && (_jsx("img", { src: attachment.dataUrl, alt: attachment.name, className: "ocu-attachment-dropzone__preview-img" })), _jsx("span", { className: "ocu-attachment-dropzone__preview-name", children: attachment.name }), _jsx("button", { type: "button", className: "ocu-attachment-dropzone__preview-remove", onClick: () => removePreview(index), "aria-label": `Remove ${attachment.name}`, children: "\u2715" })] }, `${attachment.name}-${index}`))) }))] }));
127
+ }
128
+ //# sourceMappingURL=AttachmentDropzone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentDropzone.js","sourceRoot":"","sources":["../../src/components/AttachmentDropzone.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { ChatPaneProps } from '../types/ui-types';
3
+ /**
4
+ * Left pane of the split-pane layout: renders the onboarding message
5
+ * list and the message input bar from @bernierllc/messaging-ui.
6
+ *
7
+ * Uses `MessageInput` for the input bar. Renders messages as a simple
8
+ * accessible list (not `MessageList`, which is designed for multi-user
9
+ * chat with reactions/replies).
10
+ */
11
+ export declare function ChatPane({ messages, isStreaming, onSend, className, }: ChatPaneProps): React.ReactElement;
12
+ //# sourceMappingURL=ChatPane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatPane.d.ts","sourceRoot":"","sources":["../../src/components/ChatPane.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAExE,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,mBAAmB,CAAC;AAGtF;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,WAAW,EACX,MAAM,EACN,SAAS,GACV,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CAyEpC"}
@@ -0,0 +1,54 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ This file is licensed to the client under a limited-use license.
6
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
7
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
+ */
9
+ import { useRef, useEffect, useState, useCallback } from 'react';
10
+ import { MessageInput } from '@bernierllc/messaging-ui';
11
+ import { AttachmentDropzone } from './AttachmentDropzone';
12
+ /**
13
+ * Left pane of the split-pane layout: renders the onboarding message
14
+ * list and the message input bar from @bernierllc/messaging-ui.
15
+ *
16
+ * Uses `MessageInput` for the input bar. Renders messages as a simple
17
+ * accessible list (not `MessageList`, which is designed for multi-user
18
+ * chat with reactions/replies).
19
+ */
20
+ export function ChatPane({ messages, isStreaming, onSend, className, }) {
21
+ const bottomRef = useRef(null);
22
+ const [pendingAttachments, setPendingAttachments] = useState([]);
23
+ // Auto-scroll to the latest message.
24
+ useEffect(() => {
25
+ bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
26
+ }, [messages]);
27
+ const handleSendMessage = useCallback((content, files) => {
28
+ if (files && files.length > 0) {
29
+ // Files from MessageInput are raw Files — convert via parent flow.
30
+ // For simplicity, send without attachments when files come via
31
+ // MessageInput (use AttachmentDropzone for base64 uploads).
32
+ onSend(content, pendingAttachments);
33
+ }
34
+ else {
35
+ onSend(content, pendingAttachments.length > 0 ? pendingAttachments : undefined);
36
+ }
37
+ setPendingAttachments([]);
38
+ }, [onSend, pendingAttachments]);
39
+ const handleTyping = useCallback(() => {
40
+ // Typing indicator is informational; no action required in this pane.
41
+ }, []);
42
+ const handleAttach = useCallback((attachments) => {
43
+ setPendingAttachments(prev => [...prev, ...attachments]);
44
+ }, []);
45
+ return (_jsxs("div", { className: ['ocu-chat-pane', className].filter(Boolean).join(' '), role: "region", "aria-label": "Onboarding chat", children: [_jsxs("div", { className: "ocu-chat-pane__messages", role: "log", "aria-live": "polite", "aria-label": "Messages", children: [messages.map(msg => (_jsx(MessageBubble, { message: msg }, msg.id))), isStreaming && (_jsxs("div", { className: "ocu-chat-pane__typing", "aria-label": "Assistant is typing", role: "status", children: [_jsx("span", { className: "ocu-chat-pane__typing-dot" }), _jsx("span", { className: "ocu-chat-pane__typing-dot" }), _jsx("span", { className: "ocu-chat-pane__typing-dot" })] })), _jsx("div", { ref: bottomRef })] }), _jsxs("div", { className: "ocu-chat-pane__input-area", children: [_jsx(AttachmentDropzone, { onAttach: handleAttach, accept: "image/*,application/pdf", className: "ocu-chat-pane__dropzone" }), pendingAttachments.length > 0 && (_jsxs("div", { className: "ocu-chat-pane__pending-count", "aria-live": "polite", children: [pendingAttachments.length, " file(s) ready to send"] })), _jsx(MessageInput, { onSendMessage: handleSendMessage, onTyping: handleTyping, placeholder: "Type a message\u2026", disabled: isStreaming, allowAttachments: false })] })] }));
46
+ }
47
+ function MessageBubble({ message }) {
48
+ const isUser = message.role === 'user';
49
+ return (_jsxs("div", { className: [
50
+ 'ocu-chat-pane__bubble',
51
+ isUser ? 'ocu-chat-pane__bubble--user' : 'ocu-chat-pane__bubble--assistant',
52
+ ].join(' '), "data-role": message.role, children: [_jsxs("span", { className: "ocu-chat-pane__bubble-role sr-only", children: [isUser ? 'You' : 'Assistant', ":"] }), _jsx("p", { className: "ocu-chat-pane__bubble-text", children: message.content }), message.attachments !== undefined && message.attachments.length > 0 && (_jsx("ul", { className: "ocu-chat-pane__bubble-attachments", children: message.attachments.map((att, i) => (_jsx("li", { className: "ocu-chat-pane__attachment", children: att.type.startsWith('image/') ? (_jsx("img", { src: att.dataUrl, alt: att.name, className: "ocu-chat-pane__attachment-img" })) : (_jsx("span", { className: "ocu-chat-pane__attachment-name", children: att.name })) }, `${att.name}-${i}`))) }))] }));
53
+ }
54
+ //# sourceMappingURL=ChatPane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatPane.js","sourceRoot":"","sources":["../../src/components/ChatPane.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { CompletionCardProps } from '../types/ui-types';
3
+ /**
4
+ * Post-completion summary card shown when the onboarding session finishes.
5
+ * Displays the onboarding name, any handoff targets, and slots for children
6
+ * (typically a `<RatingBar>`).
7
+ */
8
+ export declare function CompletionCard({ onboardingName, handoffs, onHandoffClick, children, className, }: CompletionCardProps): React.ReactElement;
9
+ //# sourceMappingURL=CompletionCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompletionCard.d.ts","sourceRoot":"","sources":["../../src/components/CompletionCard.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAG7D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,cAAc,EACd,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,SAAS,GACV,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CAsC1C"}