@ihoomanai/chat-widget 2.5.13 → 3.0.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/src/types.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * Type definitions for @ihooman/chat-widget
3
+ * Enhanced with professional features
3
4
  */
4
5
 
6
+ // ============================================================================
7
+ // Theme Configuration Types
8
+ // ============================================================================
9
+
5
10
  /**
6
11
  * Theme configuration for the widget appearance
7
12
  */
@@ -58,8 +63,14 @@ export interface BrandingConfig {
58
63
  avatarUrl?: string | null;
59
64
  /** Show "Powered by Ihooman" branding */
60
65
  poweredBy?: boolean;
66
+ /** Custom CSS for widget styling */
67
+ customCss?: string;
61
68
  }
62
69
 
70
+ // ============================================================================
71
+ // Preset Questions & Quick Replies
72
+ // ============================================================================
73
+
63
74
  /**
64
75
  * Preset question for quick access
65
76
  */
@@ -70,8 +81,156 @@ export interface PresetQuestion {
70
81
  text: string;
71
82
  /** Optional emoji icon */
72
83
  icon?: string;
84
+ /** Optional emoji (alias for icon) */
85
+ emoji?: string;
86
+ }
87
+
88
+ /**
89
+ * Quick reply suggestion from AI agent
90
+ */
91
+ export interface QuickReply {
92
+ id: string;
93
+ text: string;
94
+ }
95
+
96
+ // ============================================================================
97
+ // Proactive Messages
98
+ // ============================================================================
99
+
100
+ /**
101
+ * Proactive message trigger configuration
102
+ */
103
+ export interface ProactiveTriggerConfig {
104
+ type: 'time' | 'scroll' | 'exit_intent' | 'url_pattern';
105
+ value: number | string;
106
+ }
107
+
108
+ /**
109
+ * Proactive message configuration
110
+ */
111
+ export interface ProactiveMessage {
112
+ id: string;
113
+ message: string;
114
+ trigger: ProactiveTriggerConfig;
115
+ autoOpen: boolean;
116
+ cooldownMinutes: number;
117
+ startDate?: Date;
118
+ endDate?: Date;
119
+ }
120
+
121
+ // ============================================================================
122
+ // Survey Configuration
123
+ // ============================================================================
124
+
125
+ /**
126
+ * Survey type options
127
+ */
128
+ export type SurveyType = 'star' | 'nps' | 'emoji';
129
+
130
+ /**
131
+ * Survey configuration
132
+ */
133
+ export interface SurveyConfig {
134
+ id: string;
135
+ type: SurveyType;
136
+ question: string;
137
+ followUpQuestion?: string;
138
+ thankYouMessage: string;
139
+ }
140
+
141
+ /**
142
+ * Survey response
143
+ */
144
+ export interface SurveyResponse {
145
+ surveyId: string;
146
+ rating: number;
147
+ comment?: string;
148
+ sessionId: string;
149
+ timestamp: Date;
150
+ }
151
+
152
+ // ============================================================================
153
+ // Rich Message Types
154
+ // ============================================================================
155
+
156
+ /**
157
+ * Card button action type
158
+ */
159
+ export type CardButtonAction = 'link' | 'message' | 'callback';
160
+
161
+ /**
162
+ * Card button
163
+ */
164
+ export interface CardButton {
165
+ id: string;
166
+ label: string;
167
+ action: CardButtonAction;
168
+ value: string;
169
+ }
170
+
171
+ /**
172
+ * Card content for carousel messages
173
+ */
174
+ export interface CardContent {
175
+ id: string;
176
+ imageUrl?: string;
177
+ title: string;
178
+ description?: string;
179
+ buttons: CardButton[];
73
180
  }
74
181
 
182
+ /**
183
+ * Form field type
184
+ */
185
+ export type FormFieldType = 'text' | 'email' | 'phone' | 'select' | 'checkbox' | 'textarea';
186
+
187
+ /**
188
+ * Form field validation rule
189
+ */
190
+ export interface ValidationRule {
191
+ pattern?: string;
192
+ minLength?: number;
193
+ maxLength?: number;
194
+ message: string;
195
+ }
196
+
197
+ /**
198
+ * Form field option (for select fields)
199
+ */
200
+ export interface FormFieldOption {
201
+ value: string;
202
+ label: string;
203
+ }
204
+
205
+ /**
206
+ * Form field
207
+ */
208
+ export interface FormField {
209
+ id: string;
210
+ type: FormFieldType;
211
+ label: string;
212
+ placeholder?: string;
213
+ required: boolean;
214
+ options?: FormFieldOption[];
215
+ validation?: ValidationRule;
216
+ }
217
+
218
+ /**
219
+ * Image item for gallery messages
220
+ */
221
+ export interface GalleryImage {
222
+ id: string;
223
+ url: string;
224
+ thumbnailUrl?: string;
225
+ alt: string;
226
+ width?: number;
227
+ height?: number;
228
+ }
229
+
230
+ // ============================================================================
231
+ // Main Widget Configuration
232
+ // ============================================================================
233
+
75
234
  /**
76
235
  * Main widget configuration options
77
236
  */
@@ -90,7 +249,7 @@ export interface WidgetConfig {
90
249
  serverUrl?: string;
91
250
 
92
251
  /** Widget color theme */
93
- theme?: 'light' | 'dark';
252
+ theme?: 'light' | 'dark' | 'auto';
94
253
 
95
254
  /** Widget position on the page */
96
255
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
@@ -155,9 +314,39 @@ export interface WidgetConfig {
155
314
  /** Custom avatar URL */
156
315
  avatarUrl?: string;
157
316
 
317
+ /** Custom logo URL */
318
+ logoUrl?: string;
319
+
158
320
  /** Show powered by branding */
159
321
  poweredBy?: boolean;
160
322
 
323
+ /** Custom CSS for widget styling */
324
+ customCss?: string;
325
+
326
+ /** Preset questions for quick access */
327
+ presetQuestions?: PresetQuestion[];
328
+
329
+ /** Proactive messages configuration */
330
+ proactiveMessages?: ProactiveMessage[];
331
+
332
+ /** Survey configuration */
333
+ surveyConfig?: SurveyConfig | null;
334
+
335
+ /** Localization locale */
336
+ locale?: string;
337
+
338
+ /** Custom translations */
339
+ translations?: Record<string, string>;
340
+
341
+ /** Right-to-left text direction */
342
+ rtl?: boolean;
343
+
344
+ /** Allowed domains for security validation */
345
+ allowedDomains?: string[];
346
+
347
+ /** Allow localhost for development */
348
+ allowLocalhost?: boolean;
349
+
161
350
  /** Callback when widget is ready */
162
351
  onReady?: () => void;
163
352
 
@@ -174,6 +363,10 @@ export interface WidgetConfig {
174
363
  onError?: (error: Error) => void;
175
364
  }
176
365
 
366
+ // ============================================================================
367
+ // User Information
368
+ // ============================================================================
369
+
177
370
  /**
178
371
  * User information for personalization
179
372
  */
@@ -182,22 +375,73 @@ export interface UserInfo {
182
375
  name?: string;
183
376
  /** User's email address */
184
377
  email?: string;
378
+ /** User's phone number */
379
+ phone?: string;
185
380
  /** Additional metadata */
186
- metadata?: Record<string, string>;
381
+ metadata?: Record<string, unknown>;
187
382
  }
188
383
 
384
+ // ============================================================================
385
+ // Message Types
386
+ // ============================================================================
387
+
388
+ /**
389
+ * Message sender type
390
+ */
391
+ export type MessageSender = 'user' | 'bot' | 'assistant' | 'agent' | 'system';
392
+
393
+ /**
394
+ * Message delivery status
395
+ */
396
+ export type MessageStatus = 'pending' | 'sending' | 'sent' | 'delivered' | 'read' | 'error';
397
+
398
+ /**
399
+ * Message type
400
+ */
401
+ export type MessageType = 'text' | 'image' | 'file' | 'carousel' | 'form' | 'buttons' | 'gallery';
402
+
189
403
  /**
190
404
  * Chat message structure
191
405
  */
192
406
  export interface Message {
193
407
  /** Unique message ID */
194
408
  id: string;
195
- /** Message content */
409
+ /** Message type */
410
+ type?: MessageType;
411
+ /** Message content (for text messages) */
196
412
  content: string;
197
413
  /** Message sender type */
198
- sender: 'user' | 'bot';
414
+ sender: MessageSender;
199
415
  /** Message timestamp */
200
416
  timestamp: Date;
417
+ /** Session ID */
418
+ sessionId?: string;
419
+ /** Message status */
420
+ status?: MessageStatus;
421
+ /** Whether content contains markdown */
422
+ markdown?: boolean;
423
+ /** Image URL (for image messages) */
424
+ imageUrl?: string;
425
+ /** File URL (for file messages) */
426
+ fileUrl?: string;
427
+ /** Filename (for file messages) */
428
+ filename?: string;
429
+ /** File size (for file messages) */
430
+ fileSize?: number;
431
+ /** Cards (for carousel messages) */
432
+ cards?: CardContent[];
433
+ /** Form fields (for form messages) */
434
+ formFields?: FormField[];
435
+ /** Form ID (for form messages) */
436
+ formId?: string;
437
+ /** Form title (for form messages) */
438
+ formTitle?: string;
439
+ /** Submit label (for form messages) */
440
+ submitLabel?: string;
441
+ /** Buttons (for button group messages) */
442
+ buttons?: CardButton[];
443
+ /** Gallery images (for gallery messages) */
444
+ images?: GalleryImage[];
201
445
  /** Additional message metadata */
202
446
  metadata?: {
203
447
  /** Source documents for RAG responses */
@@ -215,9 +459,40 @@ export interface Message {
215
459
  escalated?: boolean;
216
460
  /** Whether this is a system message */
217
461
  is_system_message?: boolean;
462
+ /** Quick replies */
463
+ quick_replies?: QuickReply[];
218
464
  };
219
465
  }
220
466
 
467
+ // ============================================================================
468
+ // Widget State
469
+ // ============================================================================
470
+
471
+ /**
472
+ * Widget initialization status
473
+ */
474
+ export type WidgetStatus = 'initializing' | 'ready' | 'open' | 'error';
475
+
476
+ /**
477
+ * Connection status
478
+ */
479
+ export type ConnectionStatus = 'connected' | 'connecting' | 'disconnected' | 'offline';
480
+
481
+ /**
482
+ * Current view in the widget
483
+ */
484
+ export type WidgetView = 'chat' | 'ticket' | 'history' | 'survey';
485
+
486
+ /**
487
+ * Escalation status
488
+ */
489
+ export interface EscalationStatus {
490
+ active: boolean;
491
+ type: 'live_agent' | 'ticket';
492
+ queuePosition?: number;
493
+ estimatedWait?: number;
494
+ }
495
+
221
496
  /**
222
497
  * Widget state information
223
498
  */
@@ -228,24 +503,82 @@ export interface WidgetState {
228
503
  isConnected: boolean;
229
504
  /** Chat message history */
230
505
  messages: Message[];
506
+ /** Pending messages (offline queue) */
507
+ pendingMessages?: Message[];
231
508
  /** Current session ID */
232
509
  sessionId: string | null;
233
510
  /** Visitor ID */
234
511
  visitorId: string | null;
235
512
  /** Number of unread messages */
236
513
  unreadCount: number;
514
+ /** Current view */
515
+ view?: WidgetView;
516
+ /** Connection status */
517
+ connectionStatus?: ConnectionStatus;
518
+ /** Typing indicator */
519
+ typingIndicator?: boolean;
520
+ /** Sound muted */
521
+ soundMuted?: boolean;
522
+ /** Widget dimensions */
523
+ dimensions?: { width: number; height: number };
524
+ /** Escalation status */
525
+ escalationStatus?: EscalationStatus | null;
526
+ /** Queue position */
527
+ queuePosition?: number | null;
528
+ /** User info */
529
+ userInfo?: UserInfo | null;
237
530
  }
238
531
 
532
+ // ============================================================================
533
+ // Events
534
+ // ============================================================================
535
+
239
536
  /**
240
537
  * Widget event types
241
538
  */
242
- export type WidgetEvent = 'ready' | 'open' | 'close' | 'message' | 'error' | 'connected' | 'disconnected' | 'newConversation';
539
+ export type WidgetEvent =
540
+ | 'ready'
541
+ | 'open'
542
+ | 'close'
543
+ | 'message'
544
+ | 'message:sent'
545
+ | 'message:received'
546
+ | 'error'
547
+ | 'connected'
548
+ | 'disconnected'
549
+ | 'connection:change'
550
+ | 'newConversation'
551
+ | 'escalation:start'
552
+ | 'escalation:end'
553
+ | 'survey:shown'
554
+ | 'survey:submitted'
555
+ | 'proactive:shown'
556
+ | 'proactive:clicked';
243
557
 
244
558
  /**
245
559
  * Event callback function type
246
560
  */
247
561
  export type EventCallback = (data?: unknown) => void;
248
562
 
563
+ // ============================================================================
564
+ // Conversation History
565
+ // ============================================================================
566
+
567
+ /**
568
+ * Conversation summary for history display
569
+ */
570
+ export interface ConversationSummary {
571
+ sessionId: string;
572
+ startTime: Date;
573
+ lastMessageTime: Date;
574
+ messageCount: number;
575
+ preview: string;
576
+ }
577
+
578
+ // ============================================================================
579
+ // Public API Interface
580
+ // ============================================================================
581
+
249
582
  /**
250
583
  * Public API interface for the Ihooman Chat Widget
251
584
  */
@@ -272,6 +605,11 @@ export interface IhoomanChatAPI {
272
605
  */
273
606
  toggle(): void;
274
607
 
608
+ /**
609
+ * Check if widget is open
610
+ */
611
+ isOpen?(): boolean;
612
+
275
613
  /**
276
614
  * Destroy the widget and clean up resources
277
615
  */
@@ -289,6 +627,11 @@ export interface IhoomanChatAPI {
289
627
  */
290
628
  setUser(user: UserInfo): void;
291
629
 
630
+ /**
631
+ * Clear user information
632
+ */
633
+ clearUser?(): void;
634
+
292
635
  /**
293
636
  * Clear chat history and start a new conversation
294
637
  */
@@ -314,6 +657,11 @@ export interface IhoomanChatAPI {
314
657
  */
315
658
  getState(): WidgetState;
316
659
 
660
+ /**
661
+ * Get current widget configuration
662
+ */
663
+ getConfig?(): WidgetConfig;
664
+
317
665
  /**
318
666
  * Widget version
319
667
  */
package/src/widget.ts CHANGED
@@ -275,9 +275,9 @@ function generateStyles(): string {
275
275
  .ihooman-toggle.open .ihooman-pulse { display: none; }
276
276
  .ihooman-badge { position: absolute; top: -4px; right: -4px; min-width: 20px; height: 20px; padding: 0 6px; background: #ef4444; color: white; font-size: 11px; font-weight: 600; border-radius: 10px; display: flex; align-items: center; justify-content: center; z-index: 2; }
277
277
  .ihooman-badge:empty { display: none; }
278
- .ihooman-window { position: fixed; ${positionRight ? 'right: 20px' : 'left: 20px'}; ${positionBottom ? 'bottom: 90px' : 'top: 90px'}; width: ${width}px; height: ${height}px; max-height: calc(100vh - 120px); z-index: ${(zIndex ?? 9999) - 1}; display: flex; flex-direction: column; opacity: 0; visibility: hidden; transform: translateY(20px) scale(0.95); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); overscroll-behavior: contain; }
278
+ .ihooman-window { position: fixed; ${positionRight ? 'right: 20px' : 'left: 20px'}; ${positionBottom ? 'bottom: 90px' : 'top: 90px'}; width: ${width}px; height: ${height}px; min-height: ${height}px; max-height: ${height}px; z-index: ${(zIndex ?? 9999) - 1}; display: flex; flex-direction: column; opacity: 0; visibility: hidden; transform: translateY(20px) scale(0.95); transition: opacity 0.3s, visibility 0.3s, transform 0.3s; overscroll-behavior: contain; }
279
279
  .ihooman-window.open { opacity: 1; visibility: visible; transform: translateY(0) scale(1); }
280
- .ihooman-container { position: relative; width: 100%; height: 100%; display: flex; flex-direction: column; border-radius: ${borderRadius}px; overflow: hidden; }
280
+ .ihooman-container { position: relative; width: 100%; height: 100%; display: flex; flex-direction: column; border-radius: ${borderRadius}px; overflow: hidden; flex-shrink: 0; }
281
281
  .ihooman-container::before { content: ''; position: absolute; inset: 0; background: ${bgColor}; opacity: 0.97; backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-radius: ${borderRadius}px; border: 1px solid ${borderColor}; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); }
282
282
  .ihooman-container > * { position: relative; z-index: 1; }
283
283
  .ihooman-header { padding: 16px 20px; background: linear-gradient(135deg, ${gradientFrom}, ${gradientTo}); color: white; display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
@@ -374,7 +374,7 @@ function generateStyles(): string {
374
374
  .ihooman-widget .ihooman-preset-btn { display: inline-flex !important; align-items: center !important; gap: 4px !important; padding: 6px 12px !important; border-radius: 6px !important; border: 1px solid ${borderColor} !important; background: ${isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.02)'} !important; color: ${textColor} !important; font-size: 12px !important; font-weight: 500 !important; cursor: pointer !important; transition: all 0.2s !important; white-space: nowrap !important; width: auto !important; height: auto !important; min-width: 0 !important; aspect-ratio: auto !important; }
375
375
  .ihooman-widget .ihooman-preset-btn:hover { background: ${isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.05)'} !important; border-color: ${primaryColor} !important; }
376
376
  .ihooman-widget .ihooman-preset-btn .icon { font-size: 12px !important; flex-shrink: 0 !important; }
377
- @media (max-width: 480px) { .ihooman-window { width: calc(100vw - 20px); height: calc(100vh - 100px); left: 10px; right: 10px; bottom: 80px; max-height: none; } .ihooman-toggle { ${positionRight ? 'right: 16px' : 'left: 16px'}; bottom: 16px; } }
377
+ @media (max-width: 480px) { .ihooman-window { width: calc(100vw - 20px); height: calc(100vh - 100px); min-height: 400px; max-height: calc(100vh - 100px); left: 10px; right: 10px; bottom: 80px; } .ihooman-toggle { ${positionRight ? 'right: 16px' : 'left: 16px'}; bottom: 16px; } }
378
378
  `;
379
379
  }
380
380