@aisuai/chat-widget 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.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # @aisuai/chat-widget
2
+
3
+ Embeddable chat widget for integrating AiSU AI assistant into any React application.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @aisuai/chat-widget
9
+ # or
10
+ pnpm add @aisuai/chat-widget
11
+ # or
12
+ yarn add @aisuai/chat-widget
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```tsx
18
+ import { ChatWidget } from "@aisuai/chat-widget";
19
+
20
+ function App() {
21
+ return (
22
+ <ChatWidget
23
+ apiKey="pk_live_xxx"
24
+ theme="auto"
25
+ position="bottom-right"
26
+ greeting="Hello! How can I help you today?"
27
+ />
28
+ );
29
+ }
30
+ ```
31
+
32
+ ### Next.js App Router
33
+
34
+ When using with Next.js App Router, add `"use client"` at the top of your component file:
35
+
36
+ ```tsx
37
+ "use client";
38
+
39
+ import { ChatWidget } from "@aisuai/chat-widget";
40
+
41
+ export function Chat() {
42
+ return <ChatWidget apiKey="pk_live_xxx" />;
43
+ }
44
+ ```
45
+
46
+ ## Configuration
47
+
48
+ | Property | Type | Default | Description |
49
+ | -------------- | --------------------------------- | --------------------- | ------------------------- |
50
+ | `apiKey` | `string` | required | Your AiSU API key |
51
+ | `apiEndpoint` | `string` | AiSU API | Custom API endpoint |
52
+ | `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Color theme |
53
+ | `primaryColor` | `string` | `'#0066FF'` | Primary accent color |
54
+ | `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Widget position |
55
+ | `greeting` | `string` | - | Initial greeting message |
56
+ | `placeholder` | `string` | `'Type a message...'` | Input placeholder |
57
+ | `onOpen` | `() => void` | - | Called when widget opens |
58
+ | `onClose` | `() => void` | - | Called when widget closes |
59
+ | `onMessage` | `(message: Message) => void` | - | Called on new message |
60
+ | `onError` | `(error: Error) => void` | - | Called on error |
61
+
62
+ ## API Key Types
63
+
64
+ - **Public keys** (`pk_live_*`): For client-side use, only accesses public documents
65
+ - **Private keys** (`sk_live_*`): For server-side use, accesses all documents
66
+
67
+ ## Development
68
+
69
+ ```bash
70
+ # Install dependencies
71
+ pnpm install
72
+
73
+ # Build the package
74
+ pnpm build
75
+
76
+ # Watch mode
77
+ pnpm dev
78
+
79
+ # Type check
80
+ pnpm type-check
81
+ ```
82
+
83
+ ## License
84
+
85
+ MIT
@@ -0,0 +1,320 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * Authentication Types
5
+ *
6
+ * Supports API key, session, public (anonymous), and custom authentication.
7
+ */
8
+ /**
9
+ * API Key authentication config
10
+ * For external customers embedding the widget on their sites
11
+ */
12
+ interface ApiKeyAuthConfig {
13
+ type: "api-key";
14
+ apiKey: string;
15
+ }
16
+ /**
17
+ * OAuth/Session authentication config
18
+ * Uses cookies/session - no explicit token needed
19
+ */
20
+ interface SessionAuthConfig {
21
+ type: "session";
22
+ /**
23
+ * Optional user ID for analytics/tracking
24
+ */
25
+ userId?: string;
26
+ }
27
+ /**
28
+ * Public/Anonymous authentication config
29
+ * For unauthenticated users on public websites
30
+ */
31
+ interface PublicAuthConfig {
32
+ type: "public";
33
+ }
34
+ /**
35
+ * Assistant-based authentication config
36
+ * Uses an assistant ID to configure the widget with curated document access
37
+ */
38
+ interface AssistantAuthConfig {
39
+ type: "assistant";
40
+ /**
41
+ * The assistant ID (e.g., "ast_xxx")
42
+ */
43
+ assistantId: string;
44
+ }
45
+ /**
46
+ * Custom authentication config
47
+ * Allows full control over auth headers
48
+ */
49
+ interface CustomAuthConfig {
50
+ type: "custom";
51
+ /**
52
+ * Function that returns headers for authentication
53
+ */
54
+ getAuthHeaders: () => Record<string, string> | Promise<Record<string, string>>;
55
+ }
56
+ /**
57
+ * Union of all auth configurations
58
+ */
59
+ type AuthConfig = ApiKeyAuthConfig | SessionAuthConfig | PublicAuthConfig | AssistantAuthConfig | CustomAuthConfig;
60
+
61
+ /**
62
+ * Chat Widget Configuration Types
63
+ *
64
+ * Core type definitions for configuring the embeddable chat widget.
65
+ */
66
+
67
+ /**
68
+ * Message in the chat conversation
69
+ */
70
+ interface Message {
71
+ id: string;
72
+ role: "user" | "assistant";
73
+ content: string;
74
+ timestamp: Date;
75
+ }
76
+ /**
77
+ * Configuration options for the chat widget
78
+ */
79
+ interface ChatWidgetConfig {
80
+ /**
81
+ * Authentication configuration
82
+ * Supports API key, session (OAuth), or custom auth
83
+ *
84
+ * @example API Key auth (external customers):
85
+ * ```
86
+ * auth: { type: 'api-key', apiKey: 'pk_live_xxx' }
87
+ * ```
88
+ *
89
+ * @example Session auth (web app):
90
+ * ```
91
+ * auth: { type: 'session', userId: 'user-123' }
92
+ * ```
93
+ */
94
+ auth: AuthConfig;
95
+ /**
96
+ * API endpoint URL (optional)
97
+ * Defaults to '/api/chat' for session auth or production API for API key auth
98
+ */
99
+ apiEndpoint?: string;
100
+ /**
101
+ * Color theme for the widget
102
+ * @default 'auto'
103
+ */
104
+ theme?: "light" | "dark" | "auto";
105
+ /**
106
+ * Primary accent color (hex or CSS color)
107
+ * @default '#0066FF'
108
+ */
109
+ primaryColor?: string;
110
+ /**
111
+ * Widget position on the page
112
+ * @default 'bottom-right'
113
+ */
114
+ position?: "bottom-right" | "bottom-left";
115
+ /**
116
+ * Initial greeting message shown to users
117
+ */
118
+ greeting?: string;
119
+ /**
120
+ * Placeholder text for the input field
121
+ * @default 'Type a message...'
122
+ */
123
+ placeholder?: string;
124
+ /**
125
+ * Callback when widget is opened
126
+ */
127
+ onOpen?: () => void;
128
+ /**
129
+ * Callback when widget is closed
130
+ */
131
+ onClose?: () => void;
132
+ /**
133
+ * Callback when a message is sent or received
134
+ */
135
+ onMessage?: (message: Message) => void;
136
+ /**
137
+ * Callback when an error occurs
138
+ * If provided, you can handle errors yourself (e.g., show custom UI)
139
+ * If not provided, a default friendly message is shown to the user
140
+ */
141
+ onError?: (error: Error) => void;
142
+ /**
143
+ * Custom error message to display when chat fails
144
+ * Only used when onError is not provided
145
+ * @default 'Sorry, I encountered an error. Please try again.'
146
+ */
147
+ errorMessage?: string;
148
+ }
149
+ /**
150
+ * Internal widget state
151
+ */
152
+ interface ChatWidgetState {
153
+ isOpen: boolean;
154
+ isLoading: boolean;
155
+ messages: Message[];
156
+ error: Error | null;
157
+ }
158
+ /**
159
+ * Widget display variant
160
+ */
161
+ type ChatWidgetVariant = "floating" | "inline" | "fullpage";
162
+ /**
163
+ * Props for the ChatWidget component
164
+ */
165
+ interface ChatWidgetProps extends ChatWidgetConfig {
166
+ /**
167
+ * Display variant for the widget
168
+ * - 'floating': Bubble in corner that expands to a panel (default)
169
+ * - 'inline': Embedded chat interface for placing within a page section
170
+ * - 'fullpage': Full viewport chat experience
171
+ * @default 'floating'
172
+ */
173
+ variant?: ChatWidgetVariant;
174
+ /**
175
+ * Whether the widget starts in open state (only applies to 'floating' variant)
176
+ * @default false
177
+ */
178
+ defaultOpen?: boolean;
179
+ /**
180
+ * Additional CSS class name
181
+ */
182
+ className?: string;
183
+ /**
184
+ * Custom title for the chat header
185
+ */
186
+ title?: string;
187
+ }
188
+
189
+ /**
190
+ * Style exports for @aisuai/chat-widget
191
+ *
192
+ * Styles will be added in subsequent tasks:
193
+ * - CSS variables for theming
194
+ * - Base component styles
195
+ * - Animation keyframes
196
+ */
197
+ declare const DEFAULT_THEME: {
198
+ readonly primaryColor: "#0066FF";
199
+ readonly backgroundColor: "#FFFFFF";
200
+ readonly textColor: "#1A1A1A";
201
+ readonly borderColor: "#E5E5E5";
202
+ readonly inputBackground: "#F5F5F5";
203
+ };
204
+ declare const DARK_THEME: {
205
+ readonly primaryColor: "#3B82F6";
206
+ readonly backgroundColor: "#1A1A1A";
207
+ readonly textColor: "#FFFFFF";
208
+ readonly borderColor: "#333333";
209
+ readonly inputBackground: "#2A2A2A";
210
+ };
211
+ type ThemeColors = typeof DEFAULT_THEME;
212
+
213
+ declare function ChatWidget({ auth, apiEndpoint, theme, primaryColor, position, greeting, placeholder, defaultOpen, variant, className, title: customTitle, onOpen, onClose, onMessage, onError, }: ChatWidgetProps): react_jsx_runtime.JSX.Element | null;
214
+ /**
215
+ * Helper to create API key auth config
216
+ * For external customers embedding the widget on their sites
217
+ */
218
+ declare function apiKeyAuth(apiKey: string): AuthConfig;
219
+ /**
220
+ * Helper to create session auth config
221
+ * For authenticated users in web apps
222
+ */
223
+ declare function sessionAuth(userId?: string): AuthConfig;
224
+ /**
225
+ * Helper to create public/anonymous auth config
226
+ * For unauthenticated users on public websites
227
+ */
228
+ declare function publicAuth(): AuthConfig;
229
+
230
+ /**
231
+ * ChatBubble Component
232
+ *
233
+ * Floating trigger button that opens the chat widget.
234
+ */
235
+ interface ChatBubbleProps {
236
+ onClick: () => void;
237
+ isOpen: boolean;
238
+ primaryColor?: string;
239
+ position?: "bottom-right" | "bottom-left";
240
+ }
241
+ declare function ChatBubble({ onClick, isOpen, primaryColor, position, }: ChatBubbleProps): react_jsx_runtime.JSX.Element | null;
242
+
243
+ interface ChatWindowProps {
244
+ messages: Message[];
245
+ isLoading: boolean;
246
+ onSendMessage: (message: string) => void;
247
+ onClose: () => void;
248
+ title?: string;
249
+ placeholder?: string;
250
+ primaryColor?: string;
251
+ position?: "bottom-right" | "bottom-left";
252
+ }
253
+ declare function ChatWindow({ messages, isLoading, onSendMessage, onClose, title, placeholder, primaryColor, position, }: ChatWindowProps): react_jsx_runtime.JSX.Element;
254
+
255
+ interface MessageListProps {
256
+ messages: Message[];
257
+ isLoading?: boolean;
258
+ primaryColor?: string;
259
+ }
260
+ declare function MessageList({ messages, isLoading, primaryColor, }: MessageListProps): react_jsx_runtime.JSX.Element;
261
+
262
+ /**
263
+ * ChatInput Component
264
+ *
265
+ * Text input with send button for the chat widget.
266
+ */
267
+ interface ChatInputProps {
268
+ onSubmit: (message: string) => void;
269
+ isLoading?: boolean;
270
+ placeholder?: string;
271
+ primaryColor?: string;
272
+ }
273
+ declare function ChatInput({ onSubmit, isLoading, placeholder, primaryColor, }: ChatInputProps): react_jsx_runtime.JSX.Element;
274
+
275
+ /**
276
+ * useChat Hook
277
+ *
278
+ * Core hook for chat API communication.
279
+ * Handles streaming responses and message management.
280
+ * Supports both API key and session/OAuth authentication.
281
+ */
282
+
283
+ interface UseChatOptions {
284
+ /**
285
+ * Authentication configuration
286
+ */
287
+ auth: AuthConfig;
288
+ /**
289
+ * API endpoint URL
290
+ * Defaults based on auth type:
291
+ * - API key: production API
292
+ * - Session: /api/chat or /api/authenticated-chat
293
+ */
294
+ apiEndpoint?: string;
295
+ /**
296
+ * Callback when a message is sent or received
297
+ */
298
+ onMessage?: (message: Message) => void;
299
+ /**
300
+ * Callback when an error occurs
301
+ * If provided, no default error message is shown - you handle it yourself
302
+ */
303
+ onError?: (error: Error) => void;
304
+ /**
305
+ * Custom error message to display when chat fails
306
+ * Only used when onError is not provided
307
+ * @default 'Sorry, I encountered an error. Please try again.'
308
+ */
309
+ errorMessage?: string;
310
+ }
311
+ interface UseChatReturn {
312
+ messages: Message[];
313
+ isLoading: boolean;
314
+ error: Error | null;
315
+ sendMessage: (content: string) => Promise<void>;
316
+ clearMessages: () => void;
317
+ }
318
+ declare function useChat({ auth, apiEndpoint, onMessage, onError, errorMessage, }: UseChatOptions): UseChatReturn;
319
+
320
+ export { type ApiKeyAuthConfig, type AuthConfig, ChatBubble, ChatInput, ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type ChatWidgetState, type ChatWidgetVariant, ChatWindow, type CustomAuthConfig, DARK_THEME, DEFAULT_THEME, type Message, MessageList, type PublicAuthConfig, type SessionAuthConfig, type ThemeColors, apiKeyAuth, publicAuth, sessionAuth, useChat };
@@ -0,0 +1,320 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * Authentication Types
5
+ *
6
+ * Supports API key, session, public (anonymous), and custom authentication.
7
+ */
8
+ /**
9
+ * API Key authentication config
10
+ * For external customers embedding the widget on their sites
11
+ */
12
+ interface ApiKeyAuthConfig {
13
+ type: "api-key";
14
+ apiKey: string;
15
+ }
16
+ /**
17
+ * OAuth/Session authentication config
18
+ * Uses cookies/session - no explicit token needed
19
+ */
20
+ interface SessionAuthConfig {
21
+ type: "session";
22
+ /**
23
+ * Optional user ID for analytics/tracking
24
+ */
25
+ userId?: string;
26
+ }
27
+ /**
28
+ * Public/Anonymous authentication config
29
+ * For unauthenticated users on public websites
30
+ */
31
+ interface PublicAuthConfig {
32
+ type: "public";
33
+ }
34
+ /**
35
+ * Assistant-based authentication config
36
+ * Uses an assistant ID to configure the widget with curated document access
37
+ */
38
+ interface AssistantAuthConfig {
39
+ type: "assistant";
40
+ /**
41
+ * The assistant ID (e.g., "ast_xxx")
42
+ */
43
+ assistantId: string;
44
+ }
45
+ /**
46
+ * Custom authentication config
47
+ * Allows full control over auth headers
48
+ */
49
+ interface CustomAuthConfig {
50
+ type: "custom";
51
+ /**
52
+ * Function that returns headers for authentication
53
+ */
54
+ getAuthHeaders: () => Record<string, string> | Promise<Record<string, string>>;
55
+ }
56
+ /**
57
+ * Union of all auth configurations
58
+ */
59
+ type AuthConfig = ApiKeyAuthConfig | SessionAuthConfig | PublicAuthConfig | AssistantAuthConfig | CustomAuthConfig;
60
+
61
+ /**
62
+ * Chat Widget Configuration Types
63
+ *
64
+ * Core type definitions for configuring the embeddable chat widget.
65
+ */
66
+
67
+ /**
68
+ * Message in the chat conversation
69
+ */
70
+ interface Message {
71
+ id: string;
72
+ role: "user" | "assistant";
73
+ content: string;
74
+ timestamp: Date;
75
+ }
76
+ /**
77
+ * Configuration options for the chat widget
78
+ */
79
+ interface ChatWidgetConfig {
80
+ /**
81
+ * Authentication configuration
82
+ * Supports API key, session (OAuth), or custom auth
83
+ *
84
+ * @example API Key auth (external customers):
85
+ * ```
86
+ * auth: { type: 'api-key', apiKey: 'pk_live_xxx' }
87
+ * ```
88
+ *
89
+ * @example Session auth (web app):
90
+ * ```
91
+ * auth: { type: 'session', userId: 'user-123' }
92
+ * ```
93
+ */
94
+ auth: AuthConfig;
95
+ /**
96
+ * API endpoint URL (optional)
97
+ * Defaults to '/api/chat' for session auth or production API for API key auth
98
+ */
99
+ apiEndpoint?: string;
100
+ /**
101
+ * Color theme for the widget
102
+ * @default 'auto'
103
+ */
104
+ theme?: "light" | "dark" | "auto";
105
+ /**
106
+ * Primary accent color (hex or CSS color)
107
+ * @default '#0066FF'
108
+ */
109
+ primaryColor?: string;
110
+ /**
111
+ * Widget position on the page
112
+ * @default 'bottom-right'
113
+ */
114
+ position?: "bottom-right" | "bottom-left";
115
+ /**
116
+ * Initial greeting message shown to users
117
+ */
118
+ greeting?: string;
119
+ /**
120
+ * Placeholder text for the input field
121
+ * @default 'Type a message...'
122
+ */
123
+ placeholder?: string;
124
+ /**
125
+ * Callback when widget is opened
126
+ */
127
+ onOpen?: () => void;
128
+ /**
129
+ * Callback when widget is closed
130
+ */
131
+ onClose?: () => void;
132
+ /**
133
+ * Callback when a message is sent or received
134
+ */
135
+ onMessage?: (message: Message) => void;
136
+ /**
137
+ * Callback when an error occurs
138
+ * If provided, you can handle errors yourself (e.g., show custom UI)
139
+ * If not provided, a default friendly message is shown to the user
140
+ */
141
+ onError?: (error: Error) => void;
142
+ /**
143
+ * Custom error message to display when chat fails
144
+ * Only used when onError is not provided
145
+ * @default 'Sorry, I encountered an error. Please try again.'
146
+ */
147
+ errorMessage?: string;
148
+ }
149
+ /**
150
+ * Internal widget state
151
+ */
152
+ interface ChatWidgetState {
153
+ isOpen: boolean;
154
+ isLoading: boolean;
155
+ messages: Message[];
156
+ error: Error | null;
157
+ }
158
+ /**
159
+ * Widget display variant
160
+ */
161
+ type ChatWidgetVariant = "floating" | "inline" | "fullpage";
162
+ /**
163
+ * Props for the ChatWidget component
164
+ */
165
+ interface ChatWidgetProps extends ChatWidgetConfig {
166
+ /**
167
+ * Display variant for the widget
168
+ * - 'floating': Bubble in corner that expands to a panel (default)
169
+ * - 'inline': Embedded chat interface for placing within a page section
170
+ * - 'fullpage': Full viewport chat experience
171
+ * @default 'floating'
172
+ */
173
+ variant?: ChatWidgetVariant;
174
+ /**
175
+ * Whether the widget starts in open state (only applies to 'floating' variant)
176
+ * @default false
177
+ */
178
+ defaultOpen?: boolean;
179
+ /**
180
+ * Additional CSS class name
181
+ */
182
+ className?: string;
183
+ /**
184
+ * Custom title for the chat header
185
+ */
186
+ title?: string;
187
+ }
188
+
189
+ /**
190
+ * Style exports for @aisuai/chat-widget
191
+ *
192
+ * Styles will be added in subsequent tasks:
193
+ * - CSS variables for theming
194
+ * - Base component styles
195
+ * - Animation keyframes
196
+ */
197
+ declare const DEFAULT_THEME: {
198
+ readonly primaryColor: "#0066FF";
199
+ readonly backgroundColor: "#FFFFFF";
200
+ readonly textColor: "#1A1A1A";
201
+ readonly borderColor: "#E5E5E5";
202
+ readonly inputBackground: "#F5F5F5";
203
+ };
204
+ declare const DARK_THEME: {
205
+ readonly primaryColor: "#3B82F6";
206
+ readonly backgroundColor: "#1A1A1A";
207
+ readonly textColor: "#FFFFFF";
208
+ readonly borderColor: "#333333";
209
+ readonly inputBackground: "#2A2A2A";
210
+ };
211
+ type ThemeColors = typeof DEFAULT_THEME;
212
+
213
+ declare function ChatWidget({ auth, apiEndpoint, theme, primaryColor, position, greeting, placeholder, defaultOpen, variant, className, title: customTitle, onOpen, onClose, onMessage, onError, }: ChatWidgetProps): react_jsx_runtime.JSX.Element | null;
214
+ /**
215
+ * Helper to create API key auth config
216
+ * For external customers embedding the widget on their sites
217
+ */
218
+ declare function apiKeyAuth(apiKey: string): AuthConfig;
219
+ /**
220
+ * Helper to create session auth config
221
+ * For authenticated users in web apps
222
+ */
223
+ declare function sessionAuth(userId?: string): AuthConfig;
224
+ /**
225
+ * Helper to create public/anonymous auth config
226
+ * For unauthenticated users on public websites
227
+ */
228
+ declare function publicAuth(): AuthConfig;
229
+
230
+ /**
231
+ * ChatBubble Component
232
+ *
233
+ * Floating trigger button that opens the chat widget.
234
+ */
235
+ interface ChatBubbleProps {
236
+ onClick: () => void;
237
+ isOpen: boolean;
238
+ primaryColor?: string;
239
+ position?: "bottom-right" | "bottom-left";
240
+ }
241
+ declare function ChatBubble({ onClick, isOpen, primaryColor, position, }: ChatBubbleProps): react_jsx_runtime.JSX.Element | null;
242
+
243
+ interface ChatWindowProps {
244
+ messages: Message[];
245
+ isLoading: boolean;
246
+ onSendMessage: (message: string) => void;
247
+ onClose: () => void;
248
+ title?: string;
249
+ placeholder?: string;
250
+ primaryColor?: string;
251
+ position?: "bottom-right" | "bottom-left";
252
+ }
253
+ declare function ChatWindow({ messages, isLoading, onSendMessage, onClose, title, placeholder, primaryColor, position, }: ChatWindowProps): react_jsx_runtime.JSX.Element;
254
+
255
+ interface MessageListProps {
256
+ messages: Message[];
257
+ isLoading?: boolean;
258
+ primaryColor?: string;
259
+ }
260
+ declare function MessageList({ messages, isLoading, primaryColor, }: MessageListProps): react_jsx_runtime.JSX.Element;
261
+
262
+ /**
263
+ * ChatInput Component
264
+ *
265
+ * Text input with send button for the chat widget.
266
+ */
267
+ interface ChatInputProps {
268
+ onSubmit: (message: string) => void;
269
+ isLoading?: boolean;
270
+ placeholder?: string;
271
+ primaryColor?: string;
272
+ }
273
+ declare function ChatInput({ onSubmit, isLoading, placeholder, primaryColor, }: ChatInputProps): react_jsx_runtime.JSX.Element;
274
+
275
+ /**
276
+ * useChat Hook
277
+ *
278
+ * Core hook for chat API communication.
279
+ * Handles streaming responses and message management.
280
+ * Supports both API key and session/OAuth authentication.
281
+ */
282
+
283
+ interface UseChatOptions {
284
+ /**
285
+ * Authentication configuration
286
+ */
287
+ auth: AuthConfig;
288
+ /**
289
+ * API endpoint URL
290
+ * Defaults based on auth type:
291
+ * - API key: production API
292
+ * - Session: /api/chat or /api/authenticated-chat
293
+ */
294
+ apiEndpoint?: string;
295
+ /**
296
+ * Callback when a message is sent or received
297
+ */
298
+ onMessage?: (message: Message) => void;
299
+ /**
300
+ * Callback when an error occurs
301
+ * If provided, no default error message is shown - you handle it yourself
302
+ */
303
+ onError?: (error: Error) => void;
304
+ /**
305
+ * Custom error message to display when chat fails
306
+ * Only used when onError is not provided
307
+ * @default 'Sorry, I encountered an error. Please try again.'
308
+ */
309
+ errorMessage?: string;
310
+ }
311
+ interface UseChatReturn {
312
+ messages: Message[];
313
+ isLoading: boolean;
314
+ error: Error | null;
315
+ sendMessage: (content: string) => Promise<void>;
316
+ clearMessages: () => void;
317
+ }
318
+ declare function useChat({ auth, apiEndpoint, onMessage, onError, errorMessage, }: UseChatOptions): UseChatReturn;
319
+
320
+ export { type ApiKeyAuthConfig, type AuthConfig, ChatBubble, ChatInput, ChatWidget, type ChatWidgetConfig, type ChatWidgetProps, type ChatWidgetState, type ChatWidgetVariant, ChatWindow, type CustomAuthConfig, DARK_THEME, DEFAULT_THEME, type Message, MessageList, type PublicAuthConfig, type SessionAuthConfig, type ThemeColors, apiKeyAuth, publicAuth, sessionAuth, useChat };
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var ne={primaryColor:"#0066FF",backgroundColor:"#FFFFFF",textColor:"#1A1A1A",borderColor:"#E5E5E5",inputBackground:"#F5F5F5"},ie={primaryColor:"#3B82F6",backgroundColor:"#1A1A1A",textColor:"#FFFFFF",borderColor:"#333333",inputBackground:"#2A2A2A"};function K({onClick:e,isOpen:n,primaryColor:u="#0066FF",position:o="bottom-right"}){return n?null:jsxRuntime.jsx("button",{type:"button",onClick:e,"aria-label":"Open chat",style:{position:"fixed",bottom:"24px",...o==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"56px",height:"56px",borderRadius:"50%",backgroundColor:u,border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)",transition:"transform 0.2s ease, box-shadow 0.2s ease",zIndex:9999},onMouseEnter:i=>{i.currentTarget.style.transform="scale(1.05)",i.currentTarget.style.boxShadow="0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)";},onMouseLeave:i=>{i.currentTarget.style.transform="scale(1)",i.currentTarget.style.boxShadow="0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)";},children:jsxRuntime.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsxRuntime.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})})}function k({messages:e,isLoading:n=false,primaryColor:u="#0066FF"}){let o=react.useRef(null);return react.useEffect(()=>{o.current?.scrollIntoView({behavior:"smooth"});},[e]),e.length===0&&!n?jsxRuntime.jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:"24px",color:"#666",textAlign:"center"},children:jsxRuntime.jsx("p",{style:{margin:0,fontSize:"14px"},children:"Start a conversation by typing a message below."})}):jsxRuntime.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"16px",display:"flex",flexDirection:"column",gap:"12px"},children:[e.map(r=>jsxRuntime.jsx("div",{style:{display:"flex",justifyContent:r.role==="user"?"flex-end":"flex-start"},children:jsxRuntime.jsx("div",{style:{maxWidth:"80%",padding:"12px 16px",borderRadius:"12px",backgroundColor:r.role==="user"?u:"#F3F4F6",color:r.role==="user"?"#FFFFFF":"#1F2937",fontSize:"14px",lineHeight:"1.5",wordBreak:"break-word",whiteSpace:"pre-wrap"},children:r.content})},r.id)),n&&e[e.length-1]?.role==="user"&&jsxRuntime.jsx("div",{style:{display:"flex",justifyContent:"flex-start"},children:jsxRuntime.jsxs("div",{style:{padding:"12px 16px",borderRadius:"12px",backgroundColor:"#F3F4F6",display:"flex",alignItems:"center",gap:"4px"},children:[jsxRuntime.jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite"}}),jsxRuntime.jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.2s"}}),jsxRuntime.jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.4s"}})]})}),jsxRuntime.jsx("div",{ref:o}),jsxRuntime.jsx("style",{children:`
2
+ @keyframes pulse {
3
+ 0%, 100% { opacity: 0.4; transform: scale(0.8); }
4
+ 50% { opacity: 1; transform: scale(1); }
5
+ }
6
+ `})]})}function M({onSubmit:e,isLoading:n=false,placeholder:u="Type a message...",primaryColor:o="#0066FF"}){let[r,i]=react.useState(""),s=react.useRef(null);react.useEffect(()=>{let t=s.current;t&&(t.style.height="auto",t.style.height=`${Math.min(t.scrollHeight,120)}px`);},[r]);let g=react.useCallback(()=>{let t=r.trim();!t||n||(e(t),i(""),s.current&&(s.current.style.height="auto"));},[r,n,e]),d=react.useCallback(t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),g());},[g]),a=r.trim().length>0&&!n;return jsxRuntime.jsxs("div",{style:{padding:"12px 16px",borderTop:"1px solid #E5E7EB",backgroundColor:"#FFFFFF"},children:[jsxRuntime.jsxs("div",{style:{display:"flex",alignItems:"flex-end",gap:"8px"},children:[jsxRuntime.jsx("textarea",{ref:s,value:r,onChange:t=>i(t.target.value),onKeyDown:d,placeholder:u,disabled:n,rows:1,style:{flex:1,padding:"10px 12px",borderRadius:"8px",border:"1px solid #E5E7EB",backgroundColor:"#F9FAFB",fontSize:"14px",lineHeight:"1.5",resize:"none",outline:"none",fontFamily:"inherit",minHeight:"42px",maxHeight:"120px"},onFocus:t=>{t.currentTarget.style.borderColor=o,t.currentTarget.style.boxShadow=`0 0 0 2px ${o}20`;},onBlur:t=>{t.currentTarget.style.borderColor="#E5E7EB",t.currentTarget.style.boxShadow="none";}}),jsxRuntime.jsx("button",{type:"button",onClick:g,disabled:!a,"aria-label":"Send message",style:{width:"42px",height:"42px",borderRadius:"8px",border:"none",backgroundColor:a?o:"#E5E7EB",cursor:a?"pointer":"not-allowed",display:"flex",alignItems:"center",justifyContent:"center",transition:"background-color 0.2s ease, transform 0.1s ease",flexShrink:0},onMouseEnter:t=>{a&&(t.currentTarget.style.transform="scale(1.05)");},onMouseLeave:t=>{t.currentTarget.style.transform="scale(1)";},children:n?jsxRuntime.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",style:{animation:"spin 1s linear infinite"},children:jsxRuntime.jsx("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})}):jsxRuntime.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:a?"white":"#9CA3AF",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),jsxRuntime.jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]}),jsxRuntime.jsx("style",{children:`
7
+ @keyframes spin {
8
+ from { transform: rotate(0deg); }
9
+ to { transform: rotate(360deg); }
10
+ }
11
+ `})]})}function O({messages:e,isLoading:n,onSendMessage:u,onClose:o,title:r="Chat",placeholder:i="Type a message...",primaryColor:s="#0066FF",position:g="bottom-right"}){return jsxRuntime.jsxs("div",{style:{position:"fixed",bottom:"24px",...g==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"380px",height:"520px",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)",display:"flex",flexDirection:"column",overflow:"hidden",zIndex:9999,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsxRuntime.jsxs("div",{style:{padding:"16px",backgroundColor:s,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsxRuntime.jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:r}),jsxRuntime.jsx("button",{type:"button",onClick:o,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"4px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px",transition:"background-color 0.2s ease"},onMouseEnter:a=>{a.currentTarget.style.backgroundColor="rgba(255, 255, 255, 0.2)";},onMouseLeave:a=>{a.currentTarget.style.backgroundColor="transparent";},children:jsxRuntime.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsxRuntime.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsxRuntime.jsx(k,{messages:e,isLoading:n,primaryColor:s}),jsxRuntime.jsx(M,{onSubmit:u,isLoading:n,placeholder:i,primaryColor:s})]})}async function J(e){switch(e.type){case "api-key":return {"x-api-key":e.apiKey};case "session":return {};case "public":return {};case "assistant":return {};case "custom":return e.getAuthHeaders();default:return {}}}var ge="Sorry, I encountered an error. Please try again.";function fe(e){switch(e.type){case "api-key":return "/api/chat";case "session":return "/api/authenticated-chat";case "public":return "/api/public-chat";case "assistant":return `/api/public/assistant/${e.assistantId}/chat`;case "custom":return "/api/authenticated-chat";default:return "/api/public-chat"}}function U({auth:e,apiEndpoint:n,onMessage:u,onError:o,errorMessage:r=ge}){let[i,s]=react.useState([]),[g,d]=react.useState(false),[a,t]=react.useState(null),h=react.useRef(null),S=n??fe(e),z=react.useCallback(async C=>{if(!C.trim()||g)return;h.current&&h.current.abort(),h.current=new AbortController;let R={id:`user-${Date.now()}`,role:"user",content:C.trim(),timestamp:new Date};s(c=>[...c,R]),u?.(R),d(true),t(null);try{let c=await J(e),l=await fetch(S,{method:"POST",headers:{"Content-Type":"application/json",...c},credentials:e.type==="session"?"include":"same-origin",body:JSON.stringify({messages:[...i,R].map(y=>({role:y.role,content:y.content})),...e.type==="session"&&e.userId?{userId:e.userId}:{}}),signal:h.current.signal});if(!l.ok){let y=await l.json().catch(()=>({}));throw new Error(y.error??`Request failed with status ${l.status}`)}let F=l.body?.getReader(),W=new TextDecoder,A="",w=`assistant-${Date.now()}`;if(F){let y={id:w,role:"assistant",content:"",timestamp:new Date};for(s(b=>[...b,y]);;){let{done:b,value:B}=await F.read();if(b)break;let se=W.decode(B,{stream:!0}).split(`
12
+ `),Y="";for(let H of se)if(H.startsWith("event:"))Y=H.slice(6).trim();else if(H.startsWith("data:")){let L=H.slice(5).trim();if(!L||L==="[DONE]")continue;try{let f=JSON.parse(L);if(Y==="text-delta"||f.type==="text-delta"){let N=f.delta??f.value??"";A+=N,s(v=>{let x=[...v],P=x.length-1;return P>=0&&x[P]?.role==="assistant"&&(x[P]={...x[P],content:A}),x});}}catch{if(L.startsWith("0:")){let f=L.slice(2);f.startsWith('"')&&f.endsWith('"')&&(f=f.slice(1,-1)),f=f.replace(/\\n/g,`
13
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\"),A+=f,s(N=>{let v=[...N],x=v.length-1;return x>=0&&v[x]?.role==="assistant"&&(v[x]={...v[x],content:A}),v});}}}}u?.({id:w,role:"assistant",content:A,timestamp:new Date});}}catch(c){if(c instanceof Error&&c.name==="AbortError")return;let l=c instanceof Error?c:new Error("An error occurred");if(t(l),o)o(l);else {let F={id:`error-${Date.now()}`,role:"assistant",content:r,timestamp:new Date};s(W=>[...W,F]);}}finally{d(false),h.current=null;}},[e,S,i,g,u,o,r]),j=react.useCallback(()=>{h.current&&h.current.abort(),s([]),t(null),d(false);},[]);return {messages:i,isLoading:g,error:a,sendMessage:z,clearMessages:j}}function ee({auth:e,apiEndpoint:n,theme:u="light",primaryColor:o="#0066FF",position:r="bottom-right",greeting:i,placeholder:s="Type a message...",defaultOpen:g=false,variant:d="floating",className:a,title:t,onOpen:h,onClose:S,onMessage:z,onError:j}){let[C,R]=react.useState(g),{messages:c,isLoading:l,sendMessage:F,clearMessages:W}=U({auth:e,apiEndpoint:n,onMessage:z,onError:j}),A=react.useCallback(()=>{R(true),h?.();},[h]),w=react.useCallback(()=>{R(false),S?.();},[S]);react.useEffect(()=>{if(d!=="floating")return;let b=B=>{B.key==="Escape"&&C&&(B.preventDefault(),w());};return window.addEventListener("keydown",b),()=>window.removeEventListener("keydown",b)},[C,d,w]);let y=react.useCallback(b=>{F(b);},[F]),D=t??(e.type==="api-key"?"Chat":"AiSU Assistant");return d==="floating"?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(K,{onClick:A,isOpen:C,primaryColor:o,position:r}),C&&jsxRuntime.jsx(O,{messages:c,isLoading:l,onSendMessage:y,onClose:w,title:D,placeholder:s,primaryColor:o,position:r})]}):d==="inline"?jsxRuntime.jsxs("div",{className:a,style:{display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",overflow:"hidden",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsxRuntime.jsx("div",{style:{padding:"16px",backgroundColor:o,color:"#FFFFFF"},children:jsxRuntime.jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:D})}),jsxRuntime.jsx(k,{messages:c,isLoading:l,primaryColor:o}),jsxRuntime.jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):d==="fullpage"?jsxRuntime.jsxs("div",{className:a,style:{position:"fixed",inset:0,display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',zIndex:9999},children:[jsxRuntime.jsxs("div",{style:{padding:"20px 24px",backgroundColor:o,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsxRuntime.jsx("h2",{style:{margin:0,fontSize:"20px",fontWeight:600},children:D}),S&&jsxRuntime.jsx("button",{type:"button",onClick:w,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"8px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px"},children:jsxRuntime.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsxRuntime.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsxRuntime.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsxRuntime.jsx("div",{style:{flex:1,overflow:"hidden"},children:jsxRuntime.jsx(k,{messages:c,isLoading:l,primaryColor:o})}),jsxRuntime.jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):null}function te(e){return {type:"api-key",apiKey:e}}function oe(e){return {type:"session",userId:e}}function re(){return {type:"public"}}exports.ChatBubble=K;exports.ChatInput=M;exports.ChatWidget=ee;exports.ChatWindow=O;exports.DARK_THEME=ie;exports.DEFAULT_THEME=ne;exports.MessageList=k;exports.apiKeyAuth=te;exports.publicAuth=re;exports.sessionAuth=oe;exports.useChat=U;//# sourceMappingURL=index.js.map
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles/index.ts","../src/components/ChatBubble.tsx","../src/components/MessageList.tsx","../src/components/ChatInput.tsx","../src/components/ChatWindow.tsx","../src/types/auth.ts","../src/hooks/useChat.ts","../src/components/ChatWidget.tsx"],"names":["DEFAULT_THEME","DARK_THEME","ChatBubble","onClick","isOpen","primaryColor","position","jsx","e","MessageList","messages","isLoading","messagesEndRef","useRef","useEffect","jsxs","message","ChatInput","onSubmit","placeholder","value","setValue","useState","textareaRef","textarea","handleSubmit","useCallback","trimmed","handleKeyDown","canSubmit","ChatWindow","onSendMessage","onClose","title","getAuthHeaders","config","DEFAULT_ERROR_MESSAGE","getDefaultEndpoint","auth","useChat","apiEndpoint","onMessage","onError","errorMessage","setMessages","setIsLoading","error","setError","abortControllerRef","endpoint","sendMessage","content","userMessage","prev","authHeaders","response","m","errorData","reader","decoder","assistantContent","assistantMessageId","initialAssistantMessage","done","lines","currentEvent","line","dataStr","data","text","newMessages","lastIdx","err","chatError","errorMsg","clearMessages","ChatWidget","theme","greeting","defaultOpen","variant","className","customTitle","onOpen","setIsOpen","handleOpen","handleClose","handleSendMessage","Fragment","apiKeyAuth","apiKey","sessionAuth","userId","publicAuth"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Style exports for @aisuai/chat-widget\n *\n * Styles will be added in subsequent tasks:\n * - CSS variables for theming\n * - Base component styles\n * - Animation keyframes\n */\n\n// Default theme colors\nexport const DEFAULT_THEME = {\n primaryColor: \"#0066FF\",\n backgroundColor: \"#FFFFFF\",\n textColor: \"#1A1A1A\",\n borderColor: \"#E5E5E5\",\n inputBackground: \"#F5F5F5\",\n} as const;\n\n// Dark theme colors\nexport const DARK_THEME = {\n primaryColor: \"#3B82F6\",\n backgroundColor: \"#1A1A1A\",\n textColor: \"#FFFFFF\",\n borderColor: \"#333333\",\n inputBackground: \"#2A2A2A\",\n} as const;\n\nexport type ThemeColors = typeof DEFAULT_THEME;\n","/**\n * ChatBubble Component\n *\n * Floating trigger button that opens the chat widget.\n */\n\nimport React from \"react\";\n\ninterface ChatBubbleProps {\n onClick: () => void;\n isOpen: boolean;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatBubble({\n onClick,\n isOpen,\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatBubbleProps) {\n if (isOpen) return null;\n\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Open chat\"\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n backgroundColor: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.2s ease, box-shadow 0.2s ease\",\n zIndex: 9999,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n e.currentTarget.style.boxShadow =\n \"0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n e.currentTarget.style.boxShadow =\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\";\n }}\n >\n {/* Chat icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </button>\n );\n}\n","/**\n * MessageList Component\n *\n * Displays chat messages with proper styling for user and assistant roles.\n */\n\nimport React, { useEffect, useRef } from \"react\";\nimport type { Message } from \"../types\";\n\ninterface MessageListProps {\n messages: Message[];\n isLoading?: boolean;\n primaryColor?: string;\n}\n\nexport function MessageList({\n messages,\n isLoading = false,\n primaryColor = \"#0066FF\",\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n if (messages.length === 0 && !isLoading) {\n return (\n <div\n style={{\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"24px\",\n color: \"#666\",\n textAlign: \"center\",\n }}\n >\n <p style={{ margin: 0, fontSize: \"14px\" }}>\n Start a conversation by typing a message below.\n </p>\n </div>\n );\n }\n\n return (\n <div\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: \"16px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {messages.map((message) => (\n <div\n key={message.id}\n style={{\n display: \"flex\",\n justifyContent: message.role === \"user\" ? \"flex-end\" : \"flex-start\",\n }}\n >\n <div\n style={{\n maxWidth: \"80%\",\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor:\n message.role === \"user\" ? primaryColor : \"#F3F4F6\",\n color: message.role === \"user\" ? \"#FFFFFF\" : \"#1F2937\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n wordBreak: \"break-word\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {message.content}\n </div>\n </div>\n ))}\n\n {/* Loading indicator */}\n {isLoading && messages[messages.length - 1]?.role === \"user\" && (\n <div style={{ display: \"flex\", justifyContent: \"flex-start\" }}>\n <div\n style={{\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor: \"#F3F4F6\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"4px\",\n }}\n >\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.2s\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.4s\",\n }}\n />\n </div>\n </div>\n )}\n\n {/* Auto-scroll anchor */}\n <div ref={messagesEndRef} />\n\n {/* Keyframe animation for loading dots */}\n <style>{`\n @keyframes pulse {\n 0%, 100% { opacity: 0.4; transform: scale(0.8); }\n 50% { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatInput Component\n *\n * Text input with send button for the chat widget.\n */\n\nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\n\ninterface ChatInputProps {\n onSubmit: (message: string) => void;\n isLoading?: boolean;\n placeholder?: string;\n primaryColor?: string;\n}\n\nexport function ChatInput({\n onSubmit,\n isLoading = false,\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n}: ChatInputProps) {\n const [value, setValue] = useState(\"\");\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-resize textarea\n useEffect(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n }\n }, [value]);\n\n const handleSubmit = useCallback(() => {\n const trimmed = value.trim();\n if (!trimmed || isLoading) return;\n\n onSubmit(trimmed);\n setValue(\"\");\n\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n }\n }, [value, isLoading, onSubmit]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n },\n [handleSubmit],\n );\n\n const canSubmit = value.trim().length > 0 && !isLoading;\n\n return (\n <div\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid #E5E7EB\",\n backgroundColor: \"#FFFFFF\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-end\",\n gap: \"8px\",\n }}\n >\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={isLoading}\n rows={1}\n style={{\n flex: 1,\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: \"1px solid #E5E7EB\",\n backgroundColor: \"#F9FAFB\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n resize: \"none\",\n outline: \"none\",\n fontFamily: \"inherit\",\n minHeight: \"42px\",\n maxHeight: \"120px\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.borderColor = primaryColor;\n e.currentTarget.style.boxShadow = `0 0 0 2px ${primaryColor}20`;\n }}\n onBlur={(e) => {\n e.currentTarget.style.borderColor = \"#E5E7EB\";\n e.currentTarget.style.boxShadow = \"none\";\n }}\n />\n\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n aria-label=\"Send message\"\n style={{\n width: \"42px\",\n height: \"42px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: canSubmit ? primaryColor : \"#E5E7EB\",\n cursor: canSubmit ? \"pointer\" : \"not-allowed\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n transition: \"background-color 0.2s ease, transform 0.1s ease\",\n flexShrink: 0,\n }}\n onMouseEnter={(e) => {\n if (canSubmit) {\n e.currentTarget.style.transform = \"scale(1.05)\";\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n }}\n >\n {isLoading ? (\n // Loading spinner\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n style={{\n animation: \"spin 1s linear infinite\",\n }}\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n ) : (\n // Send icon\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={canSubmit ? \"white\" : \"#9CA3AF\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n )}\n </button>\n </div>\n\n {/* Keyframe animation for spinner */}\n <style>{`\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatWindow Component\n *\n * The expandable chat panel containing messages and input.\n */\n\nimport React from \"react\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport type { Message } from \"../types\";\n\ninterface ChatWindowProps {\n messages: Message[];\n isLoading: boolean;\n onSendMessage: (message: string) => void;\n onClose: () => void;\n title?: string;\n placeholder?: string;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatWindow({\n messages,\n isLoading,\n onSendMessage,\n onClose,\n title = \"Chat\",\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatWindowProps) {\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <div\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"380px\",\n height: \"520px\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow:\n \"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)\",\n display: \"flex\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n zIndex: 9999,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n transition: \"background-color 0.2s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255, 255, 255, 0.2)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"transparent\";\n }}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={onSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n}\n","/**\n * Authentication Types\n *\n * Supports API key, session, public (anonymous), and custom authentication.\n */\n\n/**\n * API Key authentication config\n * For external customers embedding the widget on their sites\n */\nexport interface ApiKeyAuthConfig {\n type: \"api-key\";\n apiKey: string;\n}\n\n/**\n * OAuth/Session authentication config\n * Uses cookies/session - no explicit token needed\n */\nexport interface SessionAuthConfig {\n type: \"session\";\n /**\n * Optional user ID for analytics/tracking\n */\n userId?: string;\n}\n\n/**\n * Public/Anonymous authentication config\n * For unauthenticated users on public websites\n */\nexport interface PublicAuthConfig {\n type: \"public\";\n}\n\n/**\n * Assistant-based authentication config\n * Uses an assistant ID to configure the widget with curated document access\n */\nexport interface AssistantAuthConfig {\n type: \"assistant\";\n /**\n * The assistant ID (e.g., \"ast_xxx\")\n */\n assistantId: string;\n}\n\n/**\n * Custom authentication config\n * Allows full control over auth headers\n */\nexport interface CustomAuthConfig {\n type: \"custom\";\n /**\n * Function that returns headers for authentication\n */\n getAuthHeaders: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n}\n\n/**\n * Union of all auth configurations\n */\nexport type AuthConfig =\n | ApiKeyAuthConfig\n | SessionAuthConfig\n | PublicAuthConfig\n | AssistantAuthConfig\n | CustomAuthConfig;\n\n/**\n * Helper to build auth headers from config\n */\nexport async function getAuthHeaders(\n config: AuthConfig,\n): Promise<Record<string, string>> {\n switch (config.type) {\n case \"api-key\":\n return { \"x-api-key\": config.apiKey };\n case \"session\":\n // Session auth uses cookies, no explicit headers needed\n return {};\n case \"public\":\n // Public auth - no headers needed\n return {};\n case \"assistant\":\n // Assistant auth - no special headers, ID is in URL\n return {};\n case \"custom\":\n return config.getAuthHeaders();\n default:\n return {};\n }\n}\n","/**\n * useChat Hook\n *\n * Core hook for chat API communication.\n * Handles streaming responses and message management.\n * Supports both API key and session/OAuth authentication.\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Message, AuthConfig } from \"../types\";\nimport { getAuthHeaders } from \"../types\";\n\nconst DEFAULT_ERROR_MESSAGE =\n \"Sorry, I encountered an error. Please try again.\";\n\ninterface UseChatOptions {\n /**\n * Authentication configuration\n */\n auth: AuthConfig;\n\n /**\n * API endpoint URL\n * Defaults based on auth type:\n * - API key: production API\n * - Session: /api/chat or /api/authenticated-chat\n */\n apiEndpoint?: string;\n\n /**\n * Callback when a message is sent or received\n */\n onMessage?: (message: Message) => void;\n\n /**\n * Callback when an error occurs\n * If provided, no default error message is shown - you handle it yourself\n */\n onError?: (error: Error) => void;\n\n /**\n * Custom error message to display when chat fails\n * Only used when onError is not provided\n * @default 'Sorry, I encountered an error. Please try again.'\n */\n errorMessage?: string;\n}\n\ninterface UseChatReturn {\n messages: Message[];\n isLoading: boolean;\n error: Error | null;\n sendMessage: (content: string) => Promise<void>;\n clearMessages: () => void;\n}\n\n/**\n * Get default API endpoint based on auth type\n */\nfunction getDefaultEndpoint(auth: AuthConfig): string {\n switch (auth.type) {\n case \"api-key\":\n // External customers use the API key chat endpoint\n return \"/api/chat\";\n case \"session\":\n // Session auth uses authenticated chat\n return \"/api/authenticated-chat\";\n case \"public\":\n // Anonymous public users\n return \"/api/public-chat\";\n case \"assistant\":\n // Assistant-based public access\n return `/api/public/assistant/${auth.assistantId}/chat`;\n case \"custom\":\n // Custom auth - default to authenticated endpoint\n return \"/api/authenticated-chat\";\n default:\n return \"/api/public-chat\";\n }\n}\n\nexport function useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n errorMessage = DEFAULT_ERROR_MESSAGE,\n}: UseChatOptions): UseChatReturn {\n const [messages, setMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const endpoint = apiEndpoint ?? getDefaultEndpoint(auth);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim() || isLoading) return;\n\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n abortControllerRef.current = new AbortController();\n\n const userMessage: Message = {\n id: `user-${Date.now()}`,\n role: \"user\",\n content: content.trim(),\n timestamp: new Date(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessage?.(userMessage);\n setIsLoading(true);\n setError(null);\n\n try {\n // Get auth headers based on auth type\n const authHeaders = await getAuthHeaders(auth);\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...authHeaders,\n },\n // Include credentials for session auth (cookies)\n credentials: auth.type === \"session\" ? \"include\" : \"same-origin\",\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n // Include userId for session auth if provided\n ...(auth.type === \"session\" && auth.userId\n ? { userId: auth.userId }\n : {}),\n }),\n signal: abortControllerRef.current.signal,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error ?? `Request failed with status ${response.status}`,\n );\n }\n\n const reader = response.body?.getReader();\n const decoder = new TextDecoder();\n let assistantContent = \"\";\n const assistantMessageId = `assistant-${Date.now()}`;\n\n if (reader) {\n // Add initial assistant message\n const initialAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: \"\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, initialAssistantMessage]);\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n\n // Parse SSE format (AI SDK v6 UIMessageStream)\n const lines = chunk.split(\"\\n\");\n let currentEvent = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n currentEvent = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const dataStr = line.slice(5).trim();\n if (!dataStr || dataStr === \"[DONE]\") continue;\n\n try {\n const data = JSON.parse(dataStr) as {\n type?: string;\n delta?: string;\n value?: string;\n };\n\n // Handle text-delta events\n if (\n currentEvent === \"text-delta\" ||\n data.type === \"text-delta\"\n ) {\n const text = data.delta ?? data.value ?? \"\";\n assistantContent += text;\n\n // Update assistant message\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n } catch {\n // Try legacy format (0: prefix)\n if (dataStr.startsWith(\"0:\")) {\n let text = dataStr.slice(2);\n if (text.startsWith('\"') && text.endsWith('\"')) {\n text = text.slice(1, -1);\n }\n text = text\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\r/g, \"\\r\")\n .replace(/\\\\t/g, \"\\t\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n assistantContent += text;\n\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n }\n }\n }\n }\n\n // Notify about completed assistant message\n const finalAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: assistantContent,\n timestamp: new Date(),\n };\n onMessage?.(finalAssistantMessage);\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n // Request was cancelled, ignore\n return;\n }\n\n const chatError =\n err instanceof Error ? err : new Error(\"An error occurred\");\n setError(chatError);\n\n if (onError) {\n // User handles errors themselves\n onError(chatError);\n } else {\n // Show default friendly error message\n const errorMsg: Message = {\n id: `error-${Date.now()}`,\n role: \"assistant\",\n content: errorMessage,\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMsg]);\n }\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n },\n [auth, endpoint, messages, isLoading, onMessage, onError, errorMessage],\n );\n\n const clearMessages = useCallback(() => {\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n setMessages([]);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return {\n messages,\n isLoading,\n error,\n sendMessage,\n clearMessages,\n };\n}\n","/**\n * ChatWidget Component\n *\n * Main embeddable chat widget with multiple display variants:\n * - floating: Bubble trigger with expandable panel (default)\n * - inline: Embedded chat interface for page sections\n * - fullpage: Full viewport chat experience\n *\n * Supports both API key and session authentication.\n *\n * @example Floating widget (default)\n * ```tsx\n * <ChatWidget auth={sessionAuth()} />\n * ```\n *\n * @example Inline embed\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"inline\" className=\"h-[500px]\" />\n * ```\n *\n * @example Full page\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"fullpage\" />\n * ```\n */\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport { ChatBubble } from \"./ChatBubble\";\nimport { ChatWindow } from \"./ChatWindow\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport { useChat } from \"../hooks/useChat\";\nimport type { ChatWidgetProps, AuthConfig } from \"../types\";\n\nexport function ChatWidget({\n auth,\n apiEndpoint,\n theme = \"light\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n greeting,\n placeholder = \"Type a message...\",\n defaultOpen = false,\n variant = \"floating\",\n className,\n title: customTitle,\n onOpen,\n onClose,\n onMessage,\n onError,\n}: ChatWidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n const { messages, isLoading, sendMessage, clearMessages } = useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n });\n\n const handleOpen = useCallback(() => {\n setIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n // Handle keyboard shortcut (Escape to close) - only for floating variant\n useEffect(() => {\n if (variant !== \"floating\") return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && isOpen) {\n e.preventDefault();\n handleClose();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, variant, handleClose]);\n\n const handleSendMessage = useCallback(\n (content: string) => {\n void sendMessage(content);\n },\n [sendMessage],\n );\n\n // Determine title based on auth type or use custom title\n const title =\n customTitle ?? (auth.type === \"api-key\" ? \"Chat\" : \"AiSU Assistant\");\n\n // Floating variant: bubble + expandable window\n if (variant === \"floating\") {\n return (\n <>\n <ChatBubble\n onClick={handleOpen}\n isOpen={isOpen}\n primaryColor={primaryColor}\n position={position}\n />\n {isOpen && (\n <ChatWindow\n messages={messages}\n isLoading={isLoading}\n onSendMessage={handleSendMessage}\n onClose={handleClose}\n title={title}\n placeholder={placeholder}\n primaryColor={primaryColor}\n position={position}\n />\n )}\n </>\n );\n }\n\n // Inline variant: embedded chat interface\n if (variant === \"inline\") {\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow: \"0 2px 8px rgba(0, 0, 0, 0.1)\",\n overflow: \"hidden\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n // Fullpage variant: takes full viewport\n if (variant === \"fullpage\") {\n return (\n <div\n className={className}\n style={{\n position: \"fixed\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n zIndex: 9999,\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"20px 24px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h2\n style={{\n margin: 0,\n fontSize: \"20px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h2>\n {onClose && (\n <button\n type=\"button\"\n onClick={handleClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"8px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n\n {/* Messages - flex grow to fill space */}\n <div style={{ flex: 1, overflow: \"hidden\" }}>\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n </div>\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n return null;\n}\n\n/**\n * Helper to create API key auth config\n * For external customers embedding the widget on their sites\n */\nexport function apiKeyAuth(apiKey: string): AuthConfig {\n return { type: \"api-key\", apiKey };\n}\n\n/**\n * Helper to create session auth config\n * For authenticated users in web apps\n */\nexport function sessionAuth(userId?: string): AuthConfig {\n return { type: \"session\", userId };\n}\n\n/**\n * Helper to create public/anonymous auth config\n * For unauthenticated users on public websites\n */\nexport function publicAuth(): AuthConfig {\n return { type: \"public\" };\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,14 @@
1
+ import {useRef,useEffect,useState,useCallback}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var ne={primaryColor:"#0066FF",backgroundColor:"#FFFFFF",textColor:"#1A1A1A",borderColor:"#E5E5E5",inputBackground:"#F5F5F5"},ie={primaryColor:"#3B82F6",backgroundColor:"#1A1A1A",textColor:"#FFFFFF",borderColor:"#333333",inputBackground:"#2A2A2A"};function K({onClick:e,isOpen:n,primaryColor:u="#0066FF",position:o="bottom-right"}){return n?null:jsx("button",{type:"button",onClick:e,"aria-label":"Open chat",style:{position:"fixed",bottom:"24px",...o==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"56px",height:"56px",borderRadius:"50%",backgroundColor:u,border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)",transition:"transform 0.2s ease, box-shadow 0.2s ease",zIndex:9999},onMouseEnter:i=>{i.currentTarget.style.transform="scale(1.05)",i.currentTarget.style.boxShadow="0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)";},onMouseLeave:i=>{i.currentTarget.style.transform="scale(1)",i.currentTarget.style.boxShadow="0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)";},children:jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})})})}function k({messages:e,isLoading:n=false,primaryColor:u="#0066FF"}){let o=useRef(null);return useEffect(()=>{o.current?.scrollIntoView({behavior:"smooth"});},[e]),e.length===0&&!n?jsx("div",{style:{flex:1,display:"flex",alignItems:"center",justifyContent:"center",padding:"24px",color:"#666",textAlign:"center"},children:jsx("p",{style:{margin:0,fontSize:"14px"},children:"Start a conversation by typing a message below."})}):jsxs("div",{style:{flex:1,overflowY:"auto",padding:"16px",display:"flex",flexDirection:"column",gap:"12px"},children:[e.map(r=>jsx("div",{style:{display:"flex",justifyContent:r.role==="user"?"flex-end":"flex-start"},children:jsx("div",{style:{maxWidth:"80%",padding:"12px 16px",borderRadius:"12px",backgroundColor:r.role==="user"?u:"#F3F4F6",color:r.role==="user"?"#FFFFFF":"#1F2937",fontSize:"14px",lineHeight:"1.5",wordBreak:"break-word",whiteSpace:"pre-wrap"},children:r.content})},r.id)),n&&e[e.length-1]?.role==="user"&&jsx("div",{style:{display:"flex",justifyContent:"flex-start"},children:jsxs("div",{style:{padding:"12px 16px",borderRadius:"12px",backgroundColor:"#F3F4F6",display:"flex",alignItems:"center",gap:"4px"},children:[jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite"}}),jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.2s"}}),jsx("span",{style:{width:"8px",height:"8px",borderRadius:"50%",backgroundColor:"#9CA3AF",animation:"pulse 1s ease-in-out infinite 0.4s"}})]})}),jsx("div",{ref:o}),jsx("style",{children:`
2
+ @keyframes pulse {
3
+ 0%, 100% { opacity: 0.4; transform: scale(0.8); }
4
+ 50% { opacity: 1; transform: scale(1); }
5
+ }
6
+ `})]})}function M({onSubmit:e,isLoading:n=false,placeholder:u="Type a message...",primaryColor:o="#0066FF"}){let[r,i]=useState(""),s=useRef(null);useEffect(()=>{let t=s.current;t&&(t.style.height="auto",t.style.height=`${Math.min(t.scrollHeight,120)}px`);},[r]);let g=useCallback(()=>{let t=r.trim();!t||n||(e(t),i(""),s.current&&(s.current.style.height="auto"));},[r,n,e]),d=useCallback(t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),g());},[g]),a=r.trim().length>0&&!n;return jsxs("div",{style:{padding:"12px 16px",borderTop:"1px solid #E5E7EB",backgroundColor:"#FFFFFF"},children:[jsxs("div",{style:{display:"flex",alignItems:"flex-end",gap:"8px"},children:[jsx("textarea",{ref:s,value:r,onChange:t=>i(t.target.value),onKeyDown:d,placeholder:u,disabled:n,rows:1,style:{flex:1,padding:"10px 12px",borderRadius:"8px",border:"1px solid #E5E7EB",backgroundColor:"#F9FAFB",fontSize:"14px",lineHeight:"1.5",resize:"none",outline:"none",fontFamily:"inherit",minHeight:"42px",maxHeight:"120px"},onFocus:t=>{t.currentTarget.style.borderColor=o,t.currentTarget.style.boxShadow=`0 0 0 2px ${o}20`;},onBlur:t=>{t.currentTarget.style.borderColor="#E5E7EB",t.currentTarget.style.boxShadow="none";}}),jsx("button",{type:"button",onClick:g,disabled:!a,"aria-label":"Send message",style:{width:"42px",height:"42px",borderRadius:"8px",border:"none",backgroundColor:a?o:"#E5E7EB",cursor:a?"pointer":"not-allowed",display:"flex",alignItems:"center",justifyContent:"center",transition:"background-color 0.2s ease, transform 0.1s ease",flexShrink:0},onMouseEnter:t=>{a&&(t.currentTarget.style.transform="scale(1.05)");},onMouseLeave:t=>{t.currentTarget.style.transform="scale(1)";},children:n?jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",style:{animation:"spin 1s linear infinite"},children:jsx("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})}):jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:a?"white":"#9CA3AF",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]}),jsx("style",{children:`
7
+ @keyframes spin {
8
+ from { transform: rotate(0deg); }
9
+ to { transform: rotate(360deg); }
10
+ }
11
+ `})]})}function O({messages:e,isLoading:n,onSendMessage:u,onClose:o,title:r="Chat",placeholder:i="Type a message...",primaryColor:s="#0066FF",position:g="bottom-right"}){return jsxs("div",{style:{position:"fixed",bottom:"24px",...g==="bottom-left"?{left:"24px",right:"auto"}:{right:"24px",left:"auto"},width:"380px",height:"520px",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)",display:"flex",flexDirection:"column",overflow:"hidden",zIndex:9999,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsxs("div",{style:{padding:"16px",backgroundColor:s,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:r}),jsx("button",{type:"button",onClick:o,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"4px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px",transition:"background-color 0.2s ease"},onMouseEnter:a=>{a.currentTarget.style.backgroundColor="rgba(255, 255, 255, 0.2)";},onMouseLeave:a=>{a.currentTarget.style.backgroundColor="transparent";},children:jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsx(k,{messages:e,isLoading:n,primaryColor:s}),jsx(M,{onSubmit:u,isLoading:n,placeholder:i,primaryColor:s})]})}async function J(e){switch(e.type){case "api-key":return {"x-api-key":e.apiKey};case "session":return {};case "public":return {};case "assistant":return {};case "custom":return e.getAuthHeaders();default:return {}}}var ge="Sorry, I encountered an error. Please try again.";function fe(e){switch(e.type){case "api-key":return "/api/chat";case "session":return "/api/authenticated-chat";case "public":return "/api/public-chat";case "assistant":return `/api/public/assistant/${e.assistantId}/chat`;case "custom":return "/api/authenticated-chat";default:return "/api/public-chat"}}function U({auth:e,apiEndpoint:n,onMessage:u,onError:o,errorMessage:r=ge}){let[i,s]=useState([]),[g,d]=useState(false),[a,t]=useState(null),h=useRef(null),S=n??fe(e),z=useCallback(async C=>{if(!C.trim()||g)return;h.current&&h.current.abort(),h.current=new AbortController;let R={id:`user-${Date.now()}`,role:"user",content:C.trim(),timestamp:new Date};s(c=>[...c,R]),u?.(R),d(true),t(null);try{let c=await J(e),l=await fetch(S,{method:"POST",headers:{"Content-Type":"application/json",...c},credentials:e.type==="session"?"include":"same-origin",body:JSON.stringify({messages:[...i,R].map(y=>({role:y.role,content:y.content})),...e.type==="session"&&e.userId?{userId:e.userId}:{}}),signal:h.current.signal});if(!l.ok){let y=await l.json().catch(()=>({}));throw new Error(y.error??`Request failed with status ${l.status}`)}let F=l.body?.getReader(),W=new TextDecoder,A="",w=`assistant-${Date.now()}`;if(F){let y={id:w,role:"assistant",content:"",timestamp:new Date};for(s(b=>[...b,y]);;){let{done:b,value:B}=await F.read();if(b)break;let se=W.decode(B,{stream:!0}).split(`
12
+ `),Y="";for(let H of se)if(H.startsWith("event:"))Y=H.slice(6).trim();else if(H.startsWith("data:")){let L=H.slice(5).trim();if(!L||L==="[DONE]")continue;try{let f=JSON.parse(L);if(Y==="text-delta"||f.type==="text-delta"){let N=f.delta??f.value??"";A+=N,s(v=>{let x=[...v],P=x.length-1;return P>=0&&x[P]?.role==="assistant"&&(x[P]={...x[P],content:A}),x});}}catch{if(L.startsWith("0:")){let f=L.slice(2);f.startsWith('"')&&f.endsWith('"')&&(f=f.slice(1,-1)),f=f.replace(/\\n/g,`
13
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\"),A+=f,s(N=>{let v=[...N],x=v.length-1;return x>=0&&v[x]?.role==="assistant"&&(v[x]={...v[x],content:A}),v});}}}}u?.({id:w,role:"assistant",content:A,timestamp:new Date});}}catch(c){if(c instanceof Error&&c.name==="AbortError")return;let l=c instanceof Error?c:new Error("An error occurred");if(t(l),o)o(l);else {let F={id:`error-${Date.now()}`,role:"assistant",content:r,timestamp:new Date};s(W=>[...W,F]);}}finally{d(false),h.current=null;}},[e,S,i,g,u,o,r]),j=useCallback(()=>{h.current&&h.current.abort(),s([]),t(null),d(false);},[]);return {messages:i,isLoading:g,error:a,sendMessage:z,clearMessages:j}}function ee({auth:e,apiEndpoint:n,theme:u="light",primaryColor:o="#0066FF",position:r="bottom-right",greeting:i,placeholder:s="Type a message...",defaultOpen:g=false,variant:d="floating",className:a,title:t,onOpen:h,onClose:S,onMessage:z,onError:j}){let[C,R]=useState(g),{messages:c,isLoading:l,sendMessage:F,clearMessages:W}=U({auth:e,apiEndpoint:n,onMessage:z,onError:j}),A=useCallback(()=>{R(true),h?.();},[h]),w=useCallback(()=>{R(false),S?.();},[S]);useEffect(()=>{if(d!=="floating")return;let b=B=>{B.key==="Escape"&&C&&(B.preventDefault(),w());};return window.addEventListener("keydown",b),()=>window.removeEventListener("keydown",b)},[C,d,w]);let y=useCallback(b=>{F(b);},[F]),D=t??(e.type==="api-key"?"Chat":"AiSU Assistant");return d==="floating"?jsxs(Fragment,{children:[jsx(K,{onClick:A,isOpen:C,primaryColor:o,position:r}),C&&jsx(O,{messages:c,isLoading:l,onSendMessage:y,onClose:w,title:D,placeholder:s,primaryColor:o,position:r})]}):d==="inline"?jsxs("div",{className:a,style:{display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",borderRadius:"12px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",overflow:"hidden",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'},children:[jsx("div",{style:{padding:"16px",backgroundColor:o,color:"#FFFFFF"},children:jsx("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:D})}),jsx(k,{messages:c,isLoading:l,primaryColor:o}),jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):d==="fullpage"?jsxs("div",{className:a,style:{position:"fixed",inset:0,display:"flex",flexDirection:"column",backgroundColor:"#FFFFFF",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',zIndex:9999},children:[jsxs("div",{style:{padding:"20px 24px",backgroundColor:o,color:"#FFFFFF",display:"flex",alignItems:"center",justifyContent:"space-between"},children:[jsx("h2",{style:{margin:0,fontSize:"20px",fontWeight:600},children:D}),S&&jsx("button",{type:"button",onClick:w,"aria-label":"Close chat",style:{background:"transparent",border:"none",cursor:"pointer",padding:"8px",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:"4px"},children:jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})})]}),jsx("div",{style:{flex:1,overflow:"hidden"},children:jsx(k,{messages:c,isLoading:l,primaryColor:o})}),jsx(M,{onSubmit:y,isLoading:l,placeholder:s,primaryColor:o})]}):null}function te(e){return {type:"api-key",apiKey:e}}function oe(e){return {type:"session",userId:e}}function re(){return {type:"public"}}export{K as ChatBubble,M as ChatInput,ee as ChatWidget,O as ChatWindow,ie as DARK_THEME,ne as DEFAULT_THEME,k as MessageList,te as apiKeyAuth,re as publicAuth,oe as sessionAuth,U as useChat};//# sourceMappingURL=index.mjs.map
14
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles/index.ts","../src/components/ChatBubble.tsx","../src/components/MessageList.tsx","../src/components/ChatInput.tsx","../src/components/ChatWindow.tsx","../src/types/auth.ts","../src/hooks/useChat.ts","../src/components/ChatWidget.tsx"],"names":["DEFAULT_THEME","DARK_THEME","ChatBubble","onClick","isOpen","primaryColor","position","jsx","e","MessageList","messages","isLoading","messagesEndRef","useRef","useEffect","jsxs","message","ChatInput","onSubmit","placeholder","value","setValue","useState","textareaRef","textarea","handleSubmit","useCallback","trimmed","handleKeyDown","canSubmit","ChatWindow","onSendMessage","onClose","title","getAuthHeaders","config","DEFAULT_ERROR_MESSAGE","getDefaultEndpoint","auth","useChat","apiEndpoint","onMessage","onError","errorMessage","setMessages","setIsLoading","error","setError","abortControllerRef","endpoint","sendMessage","content","userMessage","prev","authHeaders","response","m","errorData","reader","decoder","assistantContent","assistantMessageId","initialAssistantMessage","done","lines","currentEvent","line","dataStr","data","text","newMessages","lastIdx","err","chatError","errorMsg","clearMessages","ChatWidget","theme","greeting","defaultOpen","variant","className","customTitle","onOpen","setIsOpen","handleOpen","handleClose","handleSendMessage","Fragment","apiKeyAuth","apiKey","sessionAuth","userId","publicAuth"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Style exports for @aisuai/chat-widget\n *\n * Styles will be added in subsequent tasks:\n * - CSS variables for theming\n * - Base component styles\n * - Animation keyframes\n */\n\n// Default theme colors\nexport const DEFAULT_THEME = {\n primaryColor: \"#0066FF\",\n backgroundColor: \"#FFFFFF\",\n textColor: \"#1A1A1A\",\n borderColor: \"#E5E5E5\",\n inputBackground: \"#F5F5F5\",\n} as const;\n\n// Dark theme colors\nexport const DARK_THEME = {\n primaryColor: \"#3B82F6\",\n backgroundColor: \"#1A1A1A\",\n textColor: \"#FFFFFF\",\n borderColor: \"#333333\",\n inputBackground: \"#2A2A2A\",\n} as const;\n\nexport type ThemeColors = typeof DEFAULT_THEME;\n","/**\n * ChatBubble Component\n *\n * Floating trigger button that opens the chat widget.\n */\n\nimport React from \"react\";\n\ninterface ChatBubbleProps {\n onClick: () => void;\n isOpen: boolean;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatBubble({\n onClick,\n isOpen,\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatBubbleProps) {\n if (isOpen) return null;\n\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Open chat\"\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"50%\",\n backgroundColor: primaryColor,\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.2s ease, box-shadow 0.2s ease\",\n zIndex: 9999,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n e.currentTarget.style.boxShadow =\n \"0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.15)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n e.currentTarget.style.boxShadow =\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)\";\n }}\n >\n {/* Chat icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n </button>\n );\n}\n","/**\n * MessageList Component\n *\n * Displays chat messages with proper styling for user and assistant roles.\n */\n\nimport React, { useEffect, useRef } from \"react\";\nimport type { Message } from \"../types\";\n\ninterface MessageListProps {\n messages: Message[];\n isLoading?: boolean;\n primaryColor?: string;\n}\n\nexport function MessageList({\n messages,\n isLoading = false,\n primaryColor = \"#0066FF\",\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n if (messages.length === 0 && !isLoading) {\n return (\n <div\n style={{\n flex: 1,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"24px\",\n color: \"#666\",\n textAlign: \"center\",\n }}\n >\n <p style={{ margin: 0, fontSize: \"14px\" }}>\n Start a conversation by typing a message below.\n </p>\n </div>\n );\n }\n\n return (\n <div\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: \"16px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {messages.map((message) => (\n <div\n key={message.id}\n style={{\n display: \"flex\",\n justifyContent: message.role === \"user\" ? \"flex-end\" : \"flex-start\",\n }}\n >\n <div\n style={{\n maxWidth: \"80%\",\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor:\n message.role === \"user\" ? primaryColor : \"#F3F4F6\",\n color: message.role === \"user\" ? \"#FFFFFF\" : \"#1F2937\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n wordBreak: \"break-word\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {message.content}\n </div>\n </div>\n ))}\n\n {/* Loading indicator */}\n {isLoading && messages[messages.length - 1]?.role === \"user\" && (\n <div style={{ display: \"flex\", justifyContent: \"flex-start\" }}>\n <div\n style={{\n padding: \"12px 16px\",\n borderRadius: \"12px\",\n backgroundColor: \"#F3F4F6\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"4px\",\n }}\n >\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.2s\",\n }}\n />\n <span\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: \"#9CA3AF\",\n animation: \"pulse 1s ease-in-out infinite 0.4s\",\n }}\n />\n </div>\n </div>\n )}\n\n {/* Auto-scroll anchor */}\n <div ref={messagesEndRef} />\n\n {/* Keyframe animation for loading dots */}\n <style>{`\n @keyframes pulse {\n 0%, 100% { opacity: 0.4; transform: scale(0.8); }\n 50% { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatInput Component\n *\n * Text input with send button for the chat widget.\n */\n\nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\n\ninterface ChatInputProps {\n onSubmit: (message: string) => void;\n isLoading?: boolean;\n placeholder?: string;\n primaryColor?: string;\n}\n\nexport function ChatInput({\n onSubmit,\n isLoading = false,\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n}: ChatInputProps) {\n const [value, setValue] = useState(\"\");\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-resize textarea\n useEffect(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;\n }\n }, [value]);\n\n const handleSubmit = useCallback(() => {\n const trimmed = value.trim();\n if (!trimmed || isLoading) return;\n\n onSubmit(trimmed);\n setValue(\"\");\n\n // Reset textarea height\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n }\n }, [value, isLoading, onSubmit]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n },\n [handleSubmit],\n );\n\n const canSubmit = value.trim().length > 0 && !isLoading;\n\n return (\n <div\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid #E5E7EB\",\n backgroundColor: \"#FFFFFF\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-end\",\n gap: \"8px\",\n }}\n >\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={isLoading}\n rows={1}\n style={{\n flex: 1,\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: \"1px solid #E5E7EB\",\n backgroundColor: \"#F9FAFB\",\n fontSize: \"14px\",\n lineHeight: \"1.5\",\n resize: \"none\",\n outline: \"none\",\n fontFamily: \"inherit\",\n minHeight: \"42px\",\n maxHeight: \"120px\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.borderColor = primaryColor;\n e.currentTarget.style.boxShadow = `0 0 0 2px ${primaryColor}20`;\n }}\n onBlur={(e) => {\n e.currentTarget.style.borderColor = \"#E5E7EB\";\n e.currentTarget.style.boxShadow = \"none\";\n }}\n />\n\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n aria-label=\"Send message\"\n style={{\n width: \"42px\",\n height: \"42px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: canSubmit ? primaryColor : \"#E5E7EB\",\n cursor: canSubmit ? \"pointer\" : \"not-allowed\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n transition: \"background-color 0.2s ease, transform 0.1s ease\",\n flexShrink: 0,\n }}\n onMouseEnter={(e) => {\n if (canSubmit) {\n e.currentTarget.style.transform = \"scale(1.05)\";\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n }}\n >\n {isLoading ? (\n // Loading spinner\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n style={{\n animation: \"spin 1s linear infinite\",\n }}\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n ) : (\n // Send icon\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={canSubmit ? \"white\" : \"#9CA3AF\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n )}\n </button>\n </div>\n\n {/* Keyframe animation for spinner */}\n <style>{`\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}</style>\n </div>\n );\n}\n","/**\n * ChatWindow Component\n *\n * The expandable chat panel containing messages and input.\n */\n\nimport React from \"react\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport type { Message } from \"../types\";\n\ninterface ChatWindowProps {\n messages: Message[];\n isLoading: boolean;\n onSendMessage: (message: string) => void;\n onClose: () => void;\n title?: string;\n placeholder?: string;\n primaryColor?: string;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\nexport function ChatWindow({\n messages,\n isLoading,\n onSendMessage,\n onClose,\n title = \"Chat\",\n placeholder = \"Type a message...\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n}: ChatWindowProps) {\n const positionStyles =\n position === \"bottom-left\"\n ? { left: \"24px\", right: \"auto\" }\n : { right: \"24px\", left: \"auto\" };\n\n return (\n <div\n style={{\n position: \"fixed\",\n bottom: \"24px\",\n ...positionStyles,\n width: \"380px\",\n height: \"520px\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow:\n \"0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1)\",\n display: \"flex\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n zIndex: 9999,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n transition: \"background-color 0.2s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255, 255, 255, 0.2)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"transparent\";\n }}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={onSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n}\n","/**\n * Authentication Types\n *\n * Supports API key, session, public (anonymous), and custom authentication.\n */\n\n/**\n * API Key authentication config\n * For external customers embedding the widget on their sites\n */\nexport interface ApiKeyAuthConfig {\n type: \"api-key\";\n apiKey: string;\n}\n\n/**\n * OAuth/Session authentication config\n * Uses cookies/session - no explicit token needed\n */\nexport interface SessionAuthConfig {\n type: \"session\";\n /**\n * Optional user ID for analytics/tracking\n */\n userId?: string;\n}\n\n/**\n * Public/Anonymous authentication config\n * For unauthenticated users on public websites\n */\nexport interface PublicAuthConfig {\n type: \"public\";\n}\n\n/**\n * Assistant-based authentication config\n * Uses an assistant ID to configure the widget with curated document access\n */\nexport interface AssistantAuthConfig {\n type: \"assistant\";\n /**\n * The assistant ID (e.g., \"ast_xxx\")\n */\n assistantId: string;\n}\n\n/**\n * Custom authentication config\n * Allows full control over auth headers\n */\nexport interface CustomAuthConfig {\n type: \"custom\";\n /**\n * Function that returns headers for authentication\n */\n getAuthHeaders: () =>\n | Record<string, string>\n | Promise<Record<string, string>>;\n}\n\n/**\n * Union of all auth configurations\n */\nexport type AuthConfig =\n | ApiKeyAuthConfig\n | SessionAuthConfig\n | PublicAuthConfig\n | AssistantAuthConfig\n | CustomAuthConfig;\n\n/**\n * Helper to build auth headers from config\n */\nexport async function getAuthHeaders(\n config: AuthConfig,\n): Promise<Record<string, string>> {\n switch (config.type) {\n case \"api-key\":\n return { \"x-api-key\": config.apiKey };\n case \"session\":\n // Session auth uses cookies, no explicit headers needed\n return {};\n case \"public\":\n // Public auth - no headers needed\n return {};\n case \"assistant\":\n // Assistant auth - no special headers, ID is in URL\n return {};\n case \"custom\":\n return config.getAuthHeaders();\n default:\n return {};\n }\n}\n","/**\n * useChat Hook\n *\n * Core hook for chat API communication.\n * Handles streaming responses and message management.\n * Supports both API key and session/OAuth authentication.\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport type { Message, AuthConfig } from \"../types\";\nimport { getAuthHeaders } from \"../types\";\n\nconst DEFAULT_ERROR_MESSAGE =\n \"Sorry, I encountered an error. Please try again.\";\n\ninterface UseChatOptions {\n /**\n * Authentication configuration\n */\n auth: AuthConfig;\n\n /**\n * API endpoint URL\n * Defaults based on auth type:\n * - API key: production API\n * - Session: /api/chat or /api/authenticated-chat\n */\n apiEndpoint?: string;\n\n /**\n * Callback when a message is sent or received\n */\n onMessage?: (message: Message) => void;\n\n /**\n * Callback when an error occurs\n * If provided, no default error message is shown - you handle it yourself\n */\n onError?: (error: Error) => void;\n\n /**\n * Custom error message to display when chat fails\n * Only used when onError is not provided\n * @default 'Sorry, I encountered an error. Please try again.'\n */\n errorMessage?: string;\n}\n\ninterface UseChatReturn {\n messages: Message[];\n isLoading: boolean;\n error: Error | null;\n sendMessage: (content: string) => Promise<void>;\n clearMessages: () => void;\n}\n\n/**\n * Get default API endpoint based on auth type\n */\nfunction getDefaultEndpoint(auth: AuthConfig): string {\n switch (auth.type) {\n case \"api-key\":\n // External customers use the API key chat endpoint\n return \"/api/chat\";\n case \"session\":\n // Session auth uses authenticated chat\n return \"/api/authenticated-chat\";\n case \"public\":\n // Anonymous public users\n return \"/api/public-chat\";\n case \"assistant\":\n // Assistant-based public access\n return `/api/public/assistant/${auth.assistantId}/chat`;\n case \"custom\":\n // Custom auth - default to authenticated endpoint\n return \"/api/authenticated-chat\";\n default:\n return \"/api/public-chat\";\n }\n}\n\nexport function useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n errorMessage = DEFAULT_ERROR_MESSAGE,\n}: UseChatOptions): UseChatReturn {\n const [messages, setMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const endpoint = apiEndpoint ?? getDefaultEndpoint(auth);\n\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim() || isLoading) return;\n\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n abortControllerRef.current = new AbortController();\n\n const userMessage: Message = {\n id: `user-${Date.now()}`,\n role: \"user\",\n content: content.trim(),\n timestamp: new Date(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n onMessage?.(userMessage);\n setIsLoading(true);\n setError(null);\n\n try {\n // Get auth headers based on auth type\n const authHeaders = await getAuthHeaders(auth);\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...authHeaders,\n },\n // Include credentials for session auth (cookies)\n credentials: auth.type === \"session\" ? \"include\" : \"same-origin\",\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n // Include userId for session auth if provided\n ...(auth.type === \"session\" && auth.userId\n ? { userId: auth.userId }\n : {}),\n }),\n signal: abortControllerRef.current.signal,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error ?? `Request failed with status ${response.status}`,\n );\n }\n\n const reader = response.body?.getReader();\n const decoder = new TextDecoder();\n let assistantContent = \"\";\n const assistantMessageId = `assistant-${Date.now()}`;\n\n if (reader) {\n // Add initial assistant message\n const initialAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: \"\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, initialAssistantMessage]);\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n\n // Parse SSE format (AI SDK v6 UIMessageStream)\n const lines = chunk.split(\"\\n\");\n let currentEvent = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n currentEvent = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const dataStr = line.slice(5).trim();\n if (!dataStr || dataStr === \"[DONE]\") continue;\n\n try {\n const data = JSON.parse(dataStr) as {\n type?: string;\n delta?: string;\n value?: string;\n };\n\n // Handle text-delta events\n if (\n currentEvent === \"text-delta\" ||\n data.type === \"text-delta\"\n ) {\n const text = data.delta ?? data.value ?? \"\";\n assistantContent += text;\n\n // Update assistant message\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n } catch {\n // Try legacy format (0: prefix)\n if (dataStr.startsWith(\"0:\")) {\n let text = dataStr.slice(2);\n if (text.startsWith('\"') && text.endsWith('\"')) {\n text = text.slice(1, -1);\n }\n text = text\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\r/g, \"\\r\")\n .replace(/\\\\t/g, \"\\t\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n assistantContent += text;\n\n setMessages((prev) => {\n const newMessages = [...prev];\n const lastIdx = newMessages.length - 1;\n if (\n lastIdx >= 0 &&\n newMessages[lastIdx]?.role === \"assistant\"\n ) {\n newMessages[lastIdx] = {\n ...newMessages[lastIdx]!,\n content: assistantContent,\n };\n }\n return newMessages;\n });\n }\n }\n }\n }\n }\n\n // Notify about completed assistant message\n const finalAssistantMessage: Message = {\n id: assistantMessageId,\n role: \"assistant\",\n content: assistantContent,\n timestamp: new Date(),\n };\n onMessage?.(finalAssistantMessage);\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n // Request was cancelled, ignore\n return;\n }\n\n const chatError =\n err instanceof Error ? err : new Error(\"An error occurred\");\n setError(chatError);\n\n if (onError) {\n // User handles errors themselves\n onError(chatError);\n } else {\n // Show default friendly error message\n const errorMsg: Message = {\n id: `error-${Date.now()}`,\n role: \"assistant\",\n content: errorMessage,\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMsg]);\n }\n } finally {\n setIsLoading(false);\n abortControllerRef.current = null;\n }\n },\n [auth, endpoint, messages, isLoading, onMessage, onError, errorMessage],\n );\n\n const clearMessages = useCallback(() => {\n // Cancel any in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n setMessages([]);\n setError(null);\n setIsLoading(false);\n }, []);\n\n return {\n messages,\n isLoading,\n error,\n sendMessage,\n clearMessages,\n };\n}\n","/**\n * ChatWidget Component\n *\n * Main embeddable chat widget with multiple display variants:\n * - floating: Bubble trigger with expandable panel (default)\n * - inline: Embedded chat interface for page sections\n * - fullpage: Full viewport chat experience\n *\n * Supports both API key and session authentication.\n *\n * @example Floating widget (default)\n * ```tsx\n * <ChatWidget auth={sessionAuth()} />\n * ```\n *\n * @example Inline embed\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"inline\" className=\"h-[500px]\" />\n * ```\n *\n * @example Full page\n * ```tsx\n * <ChatWidget auth={sessionAuth()} variant=\"fullpage\" />\n * ```\n */\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport { ChatBubble } from \"./ChatBubble\";\nimport { ChatWindow } from \"./ChatWindow\";\nimport { MessageList } from \"./MessageList\";\nimport { ChatInput } from \"./ChatInput\";\nimport { useChat } from \"../hooks/useChat\";\nimport type { ChatWidgetProps, AuthConfig } from \"../types\";\n\nexport function ChatWidget({\n auth,\n apiEndpoint,\n theme = \"light\",\n primaryColor = \"#0066FF\",\n position = \"bottom-right\",\n greeting,\n placeholder = \"Type a message...\",\n defaultOpen = false,\n variant = \"floating\",\n className,\n title: customTitle,\n onOpen,\n onClose,\n onMessage,\n onError,\n}: ChatWidgetProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n\n const { messages, isLoading, sendMessage, clearMessages } = useChat({\n auth,\n apiEndpoint,\n onMessage,\n onError,\n });\n\n const handleOpen = useCallback(() => {\n setIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n // Handle keyboard shortcut (Escape to close) - only for floating variant\n useEffect(() => {\n if (variant !== \"floating\") return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && isOpen) {\n e.preventDefault();\n handleClose();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, variant, handleClose]);\n\n const handleSendMessage = useCallback(\n (content: string) => {\n void sendMessage(content);\n },\n [sendMessage],\n );\n\n // Determine title based on auth type or use custom title\n const title =\n customTitle ?? (auth.type === \"api-key\" ? \"Chat\" : \"AiSU Assistant\");\n\n // Floating variant: bubble + expandable window\n if (variant === \"floating\") {\n return (\n <>\n <ChatBubble\n onClick={handleOpen}\n isOpen={isOpen}\n primaryColor={primaryColor}\n position={position}\n />\n {isOpen && (\n <ChatWindow\n messages={messages}\n isLoading={isLoading}\n onSendMessage={handleSendMessage}\n onClose={handleClose}\n title={title}\n placeholder={placeholder}\n primaryColor={primaryColor}\n position={position}\n />\n )}\n </>\n );\n }\n\n // Inline variant: embedded chat interface\n if (variant === \"inline\") {\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n borderRadius: \"12px\",\n boxShadow: \"0 2px 8px rgba(0, 0, 0, 0.1)\",\n overflow: \"hidden\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"16px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n }}\n >\n <h3\n style={{\n margin: 0,\n fontSize: \"16px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h3>\n </div>\n\n {/* Messages */}\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n // Fullpage variant: takes full viewport\n if (variant === \"fullpage\") {\n return (\n <div\n className={className}\n style={{\n position: \"fixed\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"#FFFFFF\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n zIndex: 9999,\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"20px 24px\",\n backgroundColor: primaryColor,\n color: \"#FFFFFF\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <h2\n style={{\n margin: 0,\n fontSize: \"20px\",\n fontWeight: 600,\n }}\n >\n {title}\n </h2>\n {onClose && (\n <button\n type=\"button\"\n onClick={handleClose}\n aria-label=\"Close chat\"\n style={{\n background: \"transparent\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"8px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"4px\",\n }}\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"white\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n\n {/* Messages - flex grow to fill space */}\n <div style={{ flex: 1, overflow: \"hidden\" }}>\n <MessageList\n messages={messages}\n isLoading={isLoading}\n primaryColor={primaryColor}\n />\n </div>\n\n {/* Input */}\n <ChatInput\n onSubmit={handleSendMessage}\n isLoading={isLoading}\n placeholder={placeholder}\n primaryColor={primaryColor}\n />\n </div>\n );\n }\n\n return null;\n}\n\n/**\n * Helper to create API key auth config\n * For external customers embedding the widget on their sites\n */\nexport function apiKeyAuth(apiKey: string): AuthConfig {\n return { type: \"api-key\", apiKey };\n}\n\n/**\n * Helper to create session auth config\n * For authenticated users in web apps\n */\nexport function sessionAuth(userId?: string): AuthConfig {\n return { type: \"session\", userId };\n}\n\n/**\n * Helper to create public/anonymous auth config\n * For unauthenticated users on public websites\n */\nexport function publicAuth(): AuthConfig {\n return { type: \"public\" };\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@aisuai/chat-widget",
3
+ "version": "0.1.0",
4
+ "description": "Embeddable chat widget for AiSU",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "sideEffects": false,
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "provenance": true
23
+ },
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsup --watch",
27
+ "type-check": "tsc --noEmit",
28
+ "clean": "rm -rf dist",
29
+ "prepublishOnly": "pnpm build"
30
+ },
31
+ "peerDependencies": {
32
+ "react": ">=18.0.0",
33
+ "react-dom": ">=18.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "^18.2.0",
37
+ "@types/react-dom": "^18.2.0",
38
+ "react": "^18.2.0",
39
+ "react-dom": "^18.2.0",
40
+ "tsup": "^8.0.0",
41
+ "typescript": "^5.0.0"
42
+ },
43
+ "keywords": [
44
+ "chat",
45
+ "widget",
46
+ "react",
47
+ "ai",
48
+ "aisu"
49
+ ],
50
+ "license": "MIT",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "https://github.com/AiSU-AI/Company-Site.git",
54
+ "directory": "packages/chat-widget"
55
+ }
56
+ }