@ihoomanai/chat-widget 2.5.6 → 2.5.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ihoomanai/chat-widget",
3
- "version": "2.5.6",
3
+ "version": "2.5.7",
4
4
  "type": "module",
5
5
  "description": "Universal chat support widget for any website - secure Widget ID based initialization",
6
6
  "main": "dist/index.cjs.js",
package/src/types.ts CHANGED
@@ -60,6 +60,18 @@ export interface BrandingConfig {
60
60
  poweredBy?: boolean;
61
61
  }
62
62
 
63
+ /**
64
+ * Preset question for quick access
65
+ */
66
+ export interface PresetQuestion {
67
+ /** Unique identifier */
68
+ id: string;
69
+ /** Question text displayed to users */
70
+ text: string;
71
+ /** Optional emoji icon */
72
+ icon?: string;
73
+ }
74
+
63
75
  /**
64
76
  * Main widget configuration options
65
77
  */
package/src/widget.ts CHANGED
@@ -111,6 +111,7 @@ interface WidgetElements {
111
111
  historyList?: HTMLElement;
112
112
  historyNewBtn?: HTMLButtonElement;
113
113
  messages?: HTMLElement;
114
+ presetQuestions?: HTMLElement;
114
115
  input?: HTMLTextAreaElement;
115
116
  sendBtn?: HTMLButtonElement;
116
117
  attachBtn?: HTMLButtonElement | null;
@@ -367,6 +368,11 @@ function generateStyles(): string {
367
368
  .ihooman-history-preview { font-size: 13px; color: ${textColor}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
368
369
  .ihooman-history-meta { font-size: 11px; color: ${mutedColor}; margin-top: 4px; display: flex; justify-content: space-between; }
369
370
  .ihooman-history-empty { padding: 40px; text-align: center; color: ${mutedColor}; font-size: 14px; }
371
+ .ihooman-preset-questions { padding: 8px 16px; display: flex; flex-wrap: wrap; gap: 6px; background: ${bgColor}; border-top: 1px solid ${borderColor}; }
372
+ .ihooman-preset-questions:empty { display: none; }
373
+ .ihooman-preset-btn { display: inline-flex; align-items: center; gap: 4px; padding: 6px 12px; border-radius: 16px; border: 1px solid ${borderColor}; background: ${isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.02)'}; color: ${textColor}; font-size: 12px; cursor: pointer; transition: all 0.2s; white-space: nowrap; }
374
+ .ihooman-preset-btn:hover { background: ${isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.05)'}; border-color: ${primaryColor}; }
375
+ .ihooman-preset-btn .icon { font-size: 14px; }
370
376
  @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; } }
371
377
  `;
372
378
  }
@@ -415,6 +421,7 @@ function createWidget(): void {
415
421
  <div class="ihooman-chat-view">
416
422
  <div class="ihooman-status-bar"></div>
417
423
  <div class="ihooman-messages" role="log" aria-live="polite"></div>
424
+ <div class="ihooman-preset-questions"></div>
418
425
  <div class="ihooman-input-area">
419
426
  <div class="ihooman-input-wrapper">
420
427
  ${config.enableFileUpload ? `<button class="ihooman-input-btn attach" title="Attach file">${icons.attach}</button><input type="file" class="ihooman-file-input">` : ''}
@@ -463,6 +470,7 @@ function createWidget(): void {
463
470
  historyList: widget.querySelector('.ihooman-history-list') as HTMLElement,
464
471
  historyNewBtn: widget.querySelector('.ihooman-history-new') as HTMLButtonElement,
465
472
  messages: widget.querySelector('.ihooman-messages') as HTMLElement,
473
+ presetQuestions: widget.querySelector('.ihooman-preset-questions') as HTMLElement,
466
474
  input: widget.querySelector('.ihooman-input') as HTMLTextAreaElement,
467
475
  sendBtn: widget.querySelector('.ihooman-input-btn.send') as HTMLButtonElement,
468
476
  attachBtn: widget.querySelector('.ihooman-input-btn.attach') as HTMLButtonElement | null,
@@ -479,6 +487,9 @@ function createWidget(): void {
479
487
 
480
488
  // Set up event listeners
481
489
  setupEventListeners();
490
+
491
+ // Render preset questions
492
+ renderPresetQuestions();
482
493
  }
483
494
 
484
495
  /**
@@ -619,6 +630,54 @@ function addMessage(content: string, sender: 'user' | 'bot' = 'bot', metadata: M
619
630
  return message;
620
631
  }
621
632
 
633
+ /**
634
+ * Render preset questions in the widget
635
+ */
636
+ function renderPresetQuestions(): void {
637
+ if (!elements.presetQuestions || presetQuestions.length === 0) {
638
+ if (elements.presetQuestions) {
639
+ elements.presetQuestions.innerHTML = '';
640
+ }
641
+ return;
642
+ }
643
+
644
+ elements.presetQuestions.innerHTML = presetQuestions.map(q => `
645
+ <button class="ihooman-preset-btn" data-question-id="${escapeHtml(q.id)}" data-question-text="${escapeHtml(q.text)}">
646
+ ${q.icon ? `<span class="icon">${escapeHtml(q.icon)}</span>` : ''}
647
+ <span>${escapeHtml(q.text)}</span>
648
+ </button>
649
+ `).join('');
650
+
651
+ // Add click handlers
652
+ elements.presetQuestions.querySelectorAll('.ihooman-preset-btn').forEach(btn => {
653
+ btn.addEventListener('click', () => {
654
+ const questionText = (btn as HTMLElement).dataset.questionText;
655
+ if (questionText) {
656
+ handlePresetQuestionClick(questionText);
657
+ }
658
+ });
659
+ });
660
+ }
661
+
662
+ /**
663
+ * Handle preset question click - send the question as a message
664
+ */
665
+ function handlePresetQuestionClick(questionText: string): void {
666
+ // Add the question as a user message
667
+ addMessage(questionText, 'user');
668
+
669
+ // Show typing indicator
670
+ showTyping();
671
+
672
+ // Send to server
673
+ sendMessageToServer(questionText);
674
+
675
+ // Hide preset questions after first use (optional - can be removed if you want them to persist)
676
+ if (elements.presetQuestions) {
677
+ elements.presetQuestions.style.display = 'none';
678
+ }
679
+ }
680
+
622
681
  /**
623
682
  * Handle escalation action button clicks
624
683
  */
@@ -1618,6 +1677,11 @@ async function fetchWidgetConfig(widgetId: string, serverUrl: string): Promise<{
1618
1677
  }
1619
1678
  }
1620
1679
 
1680
+ /**
1681
+ * Preset questions from server config
1682
+ */
1683
+ let presetQuestions: Array<{ id: string; text: string; icon?: string }> = [];
1684
+
1621
1685
  /**
1622
1686
  * Apply server configuration to local config
1623
1687
  */
@@ -1630,6 +1694,7 @@ function applyServerConfig(serverConfig: {
1630
1694
  position: string;
1631
1695
  behavior: Record<string, boolean>;
1632
1696
  branding: Record<string, unknown>;
1697
+ presetQuestions?: Array<{ id: string; text: string; icon?: string }>;
1633
1698
  }): void {
1634
1699
  // Apply basic settings
1635
1700
  config.title = serverConfig.title || config.title;
@@ -1664,6 +1729,11 @@ function applyServerConfig(serverConfig: {
1664
1729
  config.avatarUrl = (serverConfig.branding.avatarUrl as string) || config.avatarUrl;
1665
1730
  config.poweredBy = serverConfig.branding.poweredBy as boolean ?? config.poweredBy;
1666
1731
  }
1732
+
1733
+ // Store preset questions
1734
+ if (serverConfig.presetQuestions && Array.isArray(serverConfig.presetQuestions)) {
1735
+ presetQuestions = serverConfig.presetQuestions;
1736
+ }
1667
1737
  }
1668
1738
 
1669
1739
  /**