@hissuno/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.
@@ -0,0 +1,507 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as react from 'react';
3
+ import { ReactNode, FormEvent } from 'react';
4
+ import { Message } from '@ai-sdk/react';
5
+ export { Message } from '@ai-sdk/react';
6
+
7
+ /**
8
+ * Position options for the bubble trigger
9
+ */
10
+ type BubblePosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
11
+ /**
12
+ * Widget trigger types - what activates the widget
13
+ */
14
+ type WidgetTrigger = 'bubble' | 'drawer-badge' | 'headless';
15
+ /**
16
+ * Widget display types - how the chat UI appears
17
+ */
18
+ type WidgetDisplay = 'popup' | 'sidepanel' | 'dialog';
19
+ /**
20
+ * Offset configuration for bubble positioning
21
+ */
22
+ interface BubbleOffset {
23
+ x?: number;
24
+ y?: number;
25
+ }
26
+ /**
27
+ * Props passed to the custom trigger render function
28
+ */
29
+ interface TriggerRenderProps {
30
+ open: () => void;
31
+ close: () => void;
32
+ toggle: () => void;
33
+ isOpen: boolean;
34
+ }
35
+ /**
36
+ * Props for the HissunoWidget component
37
+ */
38
+ interface HissunoWidgetProps {
39
+ /**
40
+ * The project ID from your Hissuno dashboard
41
+ * This uniquely identifies your project
42
+ */
43
+ projectId: string;
44
+ /**
45
+ * JWT token for secure widget authentication (optional)
46
+ * Generated on your backend using your project's secret key
47
+ * Required if widget_token_required is enabled on the project
48
+ */
49
+ widgetToken?: string;
50
+ /**
51
+ * Widget trigger type - what activates the widget
52
+ * - 'bubble': Floating 56x56 button at configurable corner position
53
+ * - 'drawer-badge': Vertical tab fixed to right edge with rotated label
54
+ * - 'headless': No visual element, keyboard-only activation
55
+ * @default "bubble"
56
+ */
57
+ trigger?: WidgetTrigger;
58
+ /**
59
+ * Widget display type - how the chat UI appears
60
+ * - 'popup': Corner modal (380x520px)
61
+ * - 'sidepanel': Full-height right drawer (400px)
62
+ * - 'dialog': Centered modal with blur backdrop
63
+ * @default "sidepanel"
64
+ */
65
+ display?: WidgetDisplay;
66
+ /**
67
+ * Keyboard shortcut to open/toggle the widget
68
+ * Supports 'mod+k' (cmd on Mac, ctrl on Windows/Linux), 'ctrl+shift+p', etc.
69
+ * Set to false to disable keyboard activation
70
+ * @default "mod+k"
71
+ */
72
+ shortcut?: string | false;
73
+ /**
74
+ * Whether to fetch default settings from the server
75
+ * When true, the widget will fetch settings using the publicKey and use them as defaults.
76
+ * Explicit props will always override fetched defaults.
77
+ * @default true
78
+ */
79
+ fetchDefaults?: boolean;
80
+ /**
81
+ * Optional identifier for the end-user using the widget
82
+ * This helps track sessions per user in your Hissuno dashboard
83
+ */
84
+ userId?: string;
85
+ /**
86
+ * Optional metadata about the end-user (e.g., name, email, plan)
87
+ * This information will be visible in session details
88
+ */
89
+ userMetadata?: Record<string, string>;
90
+ /**
91
+ * The URL of your Hissuno API endpoint
92
+ * @default "/api/agent"
93
+ */
94
+ apiUrl?: string;
95
+ /**
96
+ * Theme for the chat widget
97
+ * @default "light"
98
+ */
99
+ theme?: 'light' | 'dark' | 'auto';
100
+ /**
101
+ * Position of the floating bubble on the page
102
+ * Only applies when trigger='bubble'
103
+ * @default "bottom-right"
104
+ */
105
+ bubblePosition?: BubblePosition;
106
+ /**
107
+ * Offset from the edge of the screen in pixels
108
+ * Only applies when trigger='bubble'
109
+ * @default { x: 20, y: 20 }
110
+ */
111
+ bubbleOffset?: BubbleOffset;
112
+ /**
113
+ * Label text for the drawer badge trigger
114
+ * Only applies when trigger='drawer-badge'
115
+ * @default "Support"
116
+ */
117
+ drawerBadgeLabel?: string;
118
+ /**
119
+ * Width of the dialog display
120
+ * Only applies when display='dialog'
121
+ * @default 600
122
+ */
123
+ dialogWidth?: number;
124
+ /**
125
+ * Height of the dialog display
126
+ * Only applies when display='dialog'
127
+ * @default 500
128
+ */
129
+ dialogHeight?: number;
130
+ /**
131
+ * Custom render function for the trigger element
132
+ * Use this to provide your own button/component to open the chat
133
+ */
134
+ renderTrigger?: (props: TriggerRenderProps) => ReactNode;
135
+ /**
136
+ * Custom title for the chat window
137
+ * @default "Support"
138
+ */
139
+ title?: string;
140
+ /**
141
+ * Custom placeholder text for the input field
142
+ * @default "Ask a question or report an issue..."
143
+ */
144
+ placeholder?: string;
145
+ /**
146
+ * Initial message shown when the chat opens
147
+ * @default "Hi! How can I help you today?"
148
+ */
149
+ initialMessage?: string;
150
+ /**
151
+ * Whether the chat window should be open by default
152
+ * @default false
153
+ */
154
+ defaultOpen?: boolean;
155
+ /**
156
+ * Callback when the chat window opens
157
+ */
158
+ onOpen?: () => void;
159
+ /**
160
+ * Callback when the chat window closes
161
+ */
162
+ onClose?: () => void;
163
+ /**
164
+ * Additional CSS class name for custom styling
165
+ */
166
+ className?: string;
167
+ /**
168
+ * Custom headers to send with each request
169
+ */
170
+ headers?: Record<string, string>;
171
+ }
172
+ /**
173
+ * Configuration for the Hissuno widget
174
+ */
175
+ interface HissunoConfig {
176
+ projectId: string;
177
+ apiUrl: string;
178
+ widgetToken?: string;
179
+ }
180
+ /**
181
+ * Sender type for messages
182
+ */
183
+ type MessageSenderType = 'ai' | 'human_agent' | 'system';
184
+ /**
185
+ * Chat message structure
186
+ */
187
+ interface ChatMessage {
188
+ id: string;
189
+ role: 'user' | 'assistant';
190
+ content: string;
191
+ createdAt?: Date;
192
+ senderType?: MessageSenderType;
193
+ }
194
+ /**
195
+ * Widget settings fetched from server
196
+ */
197
+ interface WidgetSettings {
198
+ trigger: WidgetTrigger;
199
+ display: WidgetDisplay;
200
+ shortcut: string | false;
201
+ theme: 'light' | 'dark' | 'auto';
202
+ position: BubblePosition;
203
+ title: string;
204
+ initialMessage: string;
205
+ drawerBadgeLabel?: string;
206
+ tokenRequired?: boolean;
207
+ blocked?: boolean;
208
+ }
209
+
210
+ /**
211
+ * HissunoWidget - Embeddable support agent widget
212
+ *
213
+ * Add this component to your app to enable AI-powered support.
214
+ *
215
+ * @example
216
+ * ```tsx
217
+ * import { HissunoWidget } from '@hissuno/widget';
218
+ * import '@hissuno/widget/styles.css';
219
+ *
220
+ * function App() {
221
+ * return (
222
+ * <div>
223
+ * <YourApp />
224
+ * <HissunoWidget
225
+ * projectId="your-project-id"
226
+ * widgetToken={generatedToken} // Optional: generated on your backend
227
+ * userId={currentUser.id}
228
+ * userMetadata={{ name: currentUser.name, email: currentUser.email }}
229
+ * />
230
+ * </div>
231
+ * );
232
+ * }
233
+ * ```
234
+ */
235
+ declare function HissunoWidget({ projectId, widgetToken, trigger: propTrigger, display: propDisplay, shortcut: propShortcut, fetchDefaults, userId, userMetadata, apiUrl, theme: propTheme, bubblePosition: propBubblePosition, bubbleOffset, drawerBadgeLabel: propDrawerBadgeLabel, dialogWidth: propDialogWidth, dialogHeight: propDialogHeight, renderTrigger, title: propTitle, placeholder, initialMessage: propInitialMessage, defaultOpen, onOpen, onClose, className, headers, }: HissunoWidgetProps): react_jsx_runtime.JSX.Element | null;
236
+
237
+ interface ChatBubbleProps {
238
+ isOpen: boolean;
239
+ onClick: () => void;
240
+ position?: BubblePosition;
241
+ offset?: BubbleOffset;
242
+ theme?: 'light' | 'dark';
243
+ }
244
+ declare function ChatBubble({ isOpen, onClick, position, offset, theme, }: ChatBubbleProps): react_jsx_runtime.JSX.Element;
245
+
246
+ interface DrawerBadgeProps {
247
+ isOpen: boolean;
248
+ onClick: () => void;
249
+ label?: string;
250
+ theme?: 'light' | 'dark';
251
+ }
252
+ declare function DrawerBadge({ isOpen, onClick, label, theme, }: DrawerBadgeProps): react_jsx_runtime.JSX.Element;
253
+
254
+ /**
255
+ * Session entry for conversation history
256
+ * Stored in localStorage when userId is provided
257
+ */
258
+ interface SessionEntry {
259
+ /** Unique session identifier */
260
+ sessionId: string;
261
+ /** User who owns this session */
262
+ userId: string;
263
+ /** Title derived from first user message */
264
+ title: string;
265
+ /** ISO timestamp of last message */
266
+ lastMessageAt: string;
267
+ /** Total number of messages in session */
268
+ messageCount: number;
269
+ }
270
+ /**
271
+ * Options for the useHissunoChat hook
272
+ */
273
+ interface UseHissunoChatOptions {
274
+ /** Required: Your Hissuno project ID */
275
+ projectId: string;
276
+ /** JWT token for secure widget authentication */
277
+ widgetToken?: string;
278
+ /** Custom API endpoint URL (default: '/api/agent') */
279
+ apiUrl?: string;
280
+ /** Initial assistant message shown when chat opens */
281
+ initialMessage?: string;
282
+ /** Custom headers to include with API requests */
283
+ headers?: Record<string, string>;
284
+ /** End-user identifier for session tracking and history */
285
+ userId?: string;
286
+ /** Additional user metadata (name, email, plan, etc.) */
287
+ userMetadata?: Record<string, string>;
288
+ /** Custom session ID (auto-generated if not provided) */
289
+ sessionId?: string;
290
+ /** Inactivity timeout in ms before auto-closing session (default: 30 minutes) */
291
+ inactivityTimeout?: number;
292
+ /** Callback when session is closed */
293
+ onSessionClose?: () => void;
294
+ }
295
+ /**
296
+ * Return type for the useHissunoChat hook
297
+ */
298
+ interface UseHissunoChatReturn {
299
+ /** All chat messages in the current session */
300
+ messages: ChatMessage[];
301
+ /** Current input field value */
302
+ input: string;
303
+ /** Update the input field value */
304
+ setInput: (value: string) => void;
305
+ /** Submit the current message */
306
+ handleSubmit: (e?: React.FormEvent) => void;
307
+ /** Whether waiting for a response */
308
+ isLoading: boolean;
309
+ /** Whether response is currently streaming */
310
+ isStreaming: boolean;
311
+ /** Partial content being streamed */
312
+ streamingContent: string;
313
+ /** Last error that occurred */
314
+ error: Error | undefined;
315
+ /** Clear history and start a new conversation */
316
+ clearHistory: () => void;
317
+ /** Current session ID */
318
+ currentSessionId: string | null;
319
+ /** Load a previous session by ID */
320
+ loadSession: (sessionId: string, sessionMessages?: Message[]) => void;
321
+ /** Close current session and trigger PM review */
322
+ closeSession: () => Promise<void>;
323
+ /** Cancel an in-progress streaming response */
324
+ cancelChat: () => Promise<void>;
325
+ /** Get list of past sessions (requires userId) */
326
+ getSessionHistory: () => SessionEntry[];
327
+ /** Delete a session from history (requires userId) */
328
+ deleteSession: (sessionId: string) => void;
329
+ }
330
+ /**
331
+ * React hook for managing Hissuno chat functionality
332
+ *
333
+ * Provides complete chat state management including messages, input handling,
334
+ * streaming responses, session management, and conversation history.
335
+ *
336
+ * @example
337
+ * ```tsx
338
+ * const {
339
+ * messages,
340
+ * input,
341
+ * setInput,
342
+ * handleSubmit,
343
+ * isLoading,
344
+ * isStreaming,
345
+ * streamingContent,
346
+ * } = useHissunoChat({
347
+ * projectId: 'your-project-id',
348
+ * userId: 'user-123',
349
+ * });
350
+ * ```
351
+ *
352
+ * @param options - Hook configuration options
353
+ * @returns Chat state and control functions
354
+ */
355
+ declare function useHissunoChat({ projectId, widgetToken, apiUrl, initialMessage, headers, userId, userMetadata, sessionId: providedSessionId, inactivityTimeout, onSessionClose, }: UseHissunoChatOptions): UseHissunoChatReturn;
356
+
357
+ interface ChatPopupProps {
358
+ isOpen: boolean;
359
+ onClose: () => void;
360
+ messages: ChatMessage[];
361
+ input: string;
362
+ setInput: (value: string) => void;
363
+ handleSubmit: (e?: FormEvent) => void;
364
+ isLoading: boolean;
365
+ isStreaming?: boolean;
366
+ streamingContent?: string;
367
+ error?: Error;
368
+ title?: string;
369
+ placeholder?: string;
370
+ theme?: 'light' | 'dark';
371
+ position?: BubblePosition;
372
+ offset?: BubbleOffset;
373
+ onClearHistory?: () => void;
374
+ onCancelChat?: () => void;
375
+ onOpenHistory?: () => void;
376
+ isHistoryOpen?: boolean;
377
+ sessionHistory?: SessionEntry[];
378
+ currentSessionId?: string | null;
379
+ onCloseHistory?: () => void;
380
+ onSelectSession?: (sessionId: string) => void;
381
+ onDeleteSession?: (sessionId: string) => void;
382
+ }
383
+ declare function ChatPopup({ isOpen, onClose, messages, input, setInput, handleSubmit, isLoading, isStreaming, streamingContent, error, title, placeholder, theme, position, offset, onClearHistory, onCancelChat, onOpenHistory, isHistoryOpen, sessionHistory, currentSessionId, onCloseHistory, onSelectSession, onDeleteSession, }: ChatPopupProps): react_jsx_runtime.JSX.Element | null;
384
+
385
+ interface ChatSidepanelProps {
386
+ isOpen: boolean;
387
+ onClose: () => void;
388
+ messages: ChatMessage[];
389
+ input: string;
390
+ setInput: (value: string) => void;
391
+ handleSubmit: (e?: FormEvent) => void;
392
+ isLoading: boolean;
393
+ isStreaming?: boolean;
394
+ streamingContent?: string;
395
+ error?: Error;
396
+ title?: string;
397
+ placeholder?: string;
398
+ theme?: 'light' | 'dark';
399
+ onClearHistory?: () => void;
400
+ onCancelChat?: () => void;
401
+ onOpenHistory?: () => void;
402
+ isHistoryOpen?: boolean;
403
+ sessionHistory?: SessionEntry[];
404
+ currentSessionId?: string | null;
405
+ onCloseHistory?: () => void;
406
+ onSelectSession?: (sessionId: string) => void;
407
+ onDeleteSession?: (sessionId: string) => void;
408
+ }
409
+ declare function ChatSidepanel({ isOpen, onClose, messages, input, setInput, handleSubmit, isLoading, isStreaming, streamingContent, error, title, placeholder, theme, onClearHistory, onCancelChat, onOpenHistory, isHistoryOpen, sessionHistory, currentSessionId, onCloseHistory, onSelectSession, onDeleteSession, }: ChatSidepanelProps): react_jsx_runtime.JSX.Element | null;
410
+
411
+ interface ChatDialogProps {
412
+ isOpen: boolean;
413
+ onClose: () => void;
414
+ messages: ChatMessage[];
415
+ input: string;
416
+ setInput: (value: string) => void;
417
+ handleSubmit: (e?: FormEvent) => void;
418
+ isLoading: boolean;
419
+ isStreaming?: boolean;
420
+ streamingContent?: string;
421
+ error?: Error;
422
+ title?: string;
423
+ placeholder?: string;
424
+ theme?: 'light' | 'dark';
425
+ width?: number;
426
+ height?: number;
427
+ onClearHistory?: () => void;
428
+ onCancelChat?: () => void;
429
+ onOpenHistory?: () => void;
430
+ isHistoryOpen?: boolean;
431
+ sessionHistory?: SessionEntry[];
432
+ currentSessionId?: string | null;
433
+ onCloseHistory?: () => void;
434
+ onSelectSession?: (sessionId: string) => void;
435
+ onDeleteSession?: (sessionId: string) => void;
436
+ }
437
+ declare function ChatDialog({ isOpen, onClose, messages, input, setInput, handleSubmit, isLoading, isStreaming, streamingContent, error, title, placeholder, theme, width, height, onClearHistory, onCancelChat, onOpenHistory, isHistoryOpen, sessionHistory, currentSessionId, onCloseHistory, onSelectSession, onDeleteSession, }: ChatDialogProps): react_jsx_runtime.JSX.Element | null;
438
+
439
+ interface ChatMessagesProps {
440
+ messages: ChatMessage[];
441
+ isLoading: boolean;
442
+ isStreaming?: boolean;
443
+ streamingContent?: string;
444
+ theme?: 'light' | 'dark';
445
+ }
446
+ declare function ChatMessages({ messages, isLoading, isStreaming, streamingContent, theme, }: ChatMessagesProps): react_jsx_runtime.JSX.Element;
447
+
448
+ interface ConversationHistoryProps {
449
+ isOpen: boolean;
450
+ onClose: () => void;
451
+ sessions: SessionEntry[];
452
+ onSelectSession: (sessionId: string) => void;
453
+ onDeleteSession: (sessionId: string) => void;
454
+ currentSessionId?: string | null;
455
+ theme?: 'light' | 'dark';
456
+ }
457
+ declare function ConversationHistory({ isOpen, onClose, sessions, onSelectSession, onDeleteSession, currentSessionId, theme, }: ConversationHistoryProps): react_jsx_runtime.JSX.Element;
458
+
459
+ declare function HistoryIcon(): react_jsx_runtime.JSX.Element;
460
+
461
+ interface UseKeyboardShortcutOptions {
462
+ /**
463
+ * Shortcut string (e.g., 'mod+k', 'ctrl+shift+p')
464
+ * Set to false or undefined to disable
465
+ */
466
+ shortcut?: string | false;
467
+ /**
468
+ * Callback when shortcut is triggered
469
+ */
470
+ onTrigger: () => void;
471
+ /**
472
+ * Whether the shortcut is enabled
473
+ * @default true
474
+ */
475
+ enabled?: boolean;
476
+ }
477
+ /**
478
+ * Hook to register a keyboard shortcut
479
+ *
480
+ * @example
481
+ * useKeyboardShortcut({
482
+ * shortcut: 'mod+k',
483
+ * onTrigger: () => setIsOpen(true),
484
+ * });
485
+ */
486
+ declare function useKeyboardShortcut({ shortcut, onTrigger, enabled, }: UseKeyboardShortcutOptions): void;
487
+ /**
488
+ * Format a shortcut string for display
489
+ * Converts 'mod+k' to 'Cmd+K' on Mac or 'Ctrl+K' on Windows
490
+ */
491
+ declare function formatShortcut(shortcut: string): string;
492
+
493
+ /**
494
+ * Hook to resolve 'auto' theme to 'light' or 'dark' based on system preference
495
+ */
496
+ declare function useResolvedTheme(theme: 'light' | 'dark' | 'auto'): 'light' | 'dark';
497
+
498
+ /**
499
+ * Hook to trap focus within a container element
500
+ * Used for modal dialogs to maintain accessibility compliance
501
+ *
502
+ * @param isActive - Whether the focus trap should be active
503
+ * @returns Ref to attach to the container element
504
+ */
505
+ declare function useFocusTrap<T extends HTMLElement = HTMLElement>(isActive: boolean): react.RefObject<T | null>;
506
+
507
+ export { type BubbleOffset, type BubblePosition, ChatBubble, ChatDialog, type ChatMessage, ChatMessages, ChatPopup, ChatSidepanel, ConversationHistory, DrawerBadge, type HissunoConfig, HissunoWidget, type HissunoWidgetProps, HistoryIcon, type SessionEntry, HissunoWidget as SupportWidget, type TriggerRenderProps, type UseHissunoChatOptions, type UseHissunoChatReturn, type WidgetDisplay, type WidgetSettings, type WidgetTrigger, formatShortcut, useFocusTrap, useHissunoChat, useKeyboardShortcut, useResolvedTheme };