@crestapps/ai-chat-ui 1.0.0-preview.23 → 1.0.0-preview.34

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.
@@ -33,8 +33,8 @@ window.chatInteractionManager = function () {
33
33
  downloadChartButtonText: 'Download',
34
34
  codeCopiedText: 'Copied!',
35
35
  assistantLabel: 'Assistant',
36
- messageTemplate: "\n <div class=\"ai-chat-messages\">\n <div v-for=\"(message, index) in messages\" :key=\"index\" class=\"ai-chat-message-item\">\n <div>\n <div v-if=\"message.role === 'user'\" class=\"ai-chat-msg-role ai-chat-msg-role-user\">You</div>\n <div v-else-if=\"message.role !== 'indicator'\" :class=\"getAssistantRoleClasses(message)\">\n <span :class=\"getAssistantIconClasses(message, index)\"><span :class=\"getAssistantIcon(message)\"></span></span>\n {{ getAssistantLabel(message) }}\n </div>\n <div class=\"ai-chat-message-body lh-base\">\n <h4 v-if=\"message.title\">{{ message.title }}</h4>\n <div v-html=\"message.htmlContent\"></div>\n <ol v-if=\"message.citationReferences && message.citationReferences.length\" class=\"ai-chat-citation-list\">\n <li v-for=\"citation in message.citationReferences\" :key=\"'citation-' + (citation.referenceKey || citation.displayIndex)\" class=\"ai-chat-citation-item\">\n <a v-if=\"citation.link\" :href=\"citation.link\" :target=\"citation.isDownload ? null : '_blank'\" :rel=\"citation.isDownload ? null : 'noopener noreferrer'\">{{ citation.label }}</a>\n <span v-else>{{ citation.label }}</span>\n </li>\n </ol>\n <span class=\"message-buttons-container\" v-if=\"!isIndicator(message)\">\n <button v-if=\"textToSpeechEnabled && !isConversationMode && message.role === 'assistant' && !message.isStreaming\" class=\"btn btn-sm btn-link text-secondary p-0 me-1 button-message-toolbox\" :class=\"{ 'tts-playing': ttsPlayingMessageIndex === index }\" :data-tts-message-index=\"index\" @click=\"toggleMessageTts(message, index)\" :title=\"ttsPlayingMessageIndex === index ? 'Pause audio' : 'Read aloud'\">\n <span :class=\"ttsPlayingMessageIndex === index ? 'fa-solid fa-circle-pause' : 'fa-solid fa-circle-play'\"></span>\n </button>\n <button class=\"btn btn-sm btn-link text-secondary p-0 button-message-toolbox\" @click=\"copyResponse(message)\" title=\"Click here to copy response to clipboard.\">\n <span class=\"fa-solid fa-copy\"></span>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div v-for=\"notification in notifications\" :key=\"'notif-' + notification.type\" class=\"ai-chat-notification\" :class=\"'ai-chat-notification-' + (notification.type || 'info') + ' ' + (notification.cssClass || '')\">\n <div class=\"ai-chat-notification-content\">\n <span v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></span>\n <span class=\"ai-chat-notification-text\">{{ notification.content }}</span>\n <button v-if=\"notification.dismissible\" class=\"btn btn-sm btn-link p-0 ms-2 ai-chat-notification-dismiss\" @click=\"dismissNotification(notification.type)\" title=\"Dismiss\">\n <span class=\"fa-solid fa-xmark\"></span>\n </button>\n </div>\n <div v-if=\"notification.actions && notification.actions.length\" class=\"ai-chat-notification-actions\">\n <button v-for=\"action in notification.actions\" :key=\"action.name\" class=\"btn btn-sm\" :class=\"action.cssClass || 'btn-outline-secondary'\" @click=\"handleNotificationAction(notification.type, action.name)\">\n <span v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></span>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
37
- indicatorTemplate: "\n <div class=\"ai-chat-msg-role ai-chat-msg-role-assistant\">\n <span class=\"ai-streaming-icon\"><span class=\"fa fa-robot\" style=\"display: inline-block;\"></span></span>\n Assistant\n </div>\n ",
36
+ messageTemplate: "\n <div class=\"ai-chat-messages\">\n <div v-for=\"(message, index) in messages\" :key=\"index\" class=\"ai-chat-message-item\">\n <div>\n <div v-if=\"message.role === 'user'\" class=\"ai-chat-msg-role ai-chat-msg-role-user\">You</div>\n <div v-else-if=\"message.role !== 'indicator'\" :class=\"getAssistantRoleClasses(message)\">\n <span :class=\"getAssistantIconClasses(message, index)\"><i :class=\"getAssistantIcon(message)\"></i></span>\n {{ getAssistantLabel(message) }}\n </div>\n <div class=\"ai-chat-message-body lh-base\">\n <h4 v-if=\"message.title\">{{ message.title }}</h4>\n <div v-html=\"message.htmlContent\"></div>\n <ol v-if=\"message.citationReferences && message.citationReferences.length\" class=\"ai-chat-citation-list\">\n <li v-for=\"citation in message.citationReferences\" :key=\"'citation-' + (citation.referenceKey || citation.displayIndex)\" class=\"ai-chat-citation-item\">\n <a v-if=\"citation.link\" :href=\"citation.link\" :target=\"citation.isDownload ? null : '_blank'\" :rel=\"citation.isDownload ? null : 'noopener noreferrer'\">{{ citation.label }}</a>\n <span v-else>{{ citation.label }}</span>\n </li>\n </ol>\n <span class=\"message-buttons-container\" v-if=\"!isIndicator(message)\">\n <button v-if=\"textToSpeechEnabled && !isConversationMode && message.role === 'assistant' && !message.isStreaming\" class=\"btn btn-sm btn-link text-secondary p-0 me-1 button-message-toolbox\" :class=\"{ 'tts-playing': ttsPlayingMessageIndex === index }\" :data-tts-message-index=\"index\" @click=\"toggleMessageTts(message, index)\" :title=\"ttsPlayingMessageIndex === index ? 'Pause audio' : 'Read aloud'\">\n <i :class=\"ttsPlayingMessageIndex === index ? 'fa-solid fa-circle-pause' : 'fa-solid fa-circle-play'\"></i>\n </button>\n <button class=\"btn btn-sm btn-link text-secondary p-0 button-message-toolbox\" @click=\"copyResponse(message)\" title=\"Click here to copy response to clipboard.\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div v-for=\"notification in notifications\" :key=\"'notif-' + notification.type\" class=\"ai-chat-notification\" :class=\"'ai-chat-notification-' + (notification.type || 'info') + ' ' + (notification.cssClass || '')\">\n <div class=\"ai-chat-notification-content\">\n <i v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></i>\n <span class=\"ai-chat-notification-text\">{{ notification.content }}</span>\n <button v-if=\"notification.dismissible\" class=\"btn btn-sm btn-link p-0 ms-2 ai-chat-notification-dismiss\" @click=\"dismissNotification(notification.type)\" title=\"Dismiss\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div v-if=\"notification.actions && notification.actions.length\" class=\"ai-chat-notification-actions\">\n <button v-for=\"action in notification.actions\" :key=\"action.name\" class=\"btn btn-sm\" :class=\"action.cssClass || 'btn-outline-secondary'\" @click=\"handleNotificationAction(notification.type, action.name)\">\n <i v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></i>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
37
+ indicatorTemplate: "\n <div class=\"ai-chat-msg-role ai-chat-msg-role-assistant\">\n <span class=\"ai-streaming-icon\"><i class=\"fa fa-robot\" style=\"display: inline-block;\"></i></span>\n Assistant\n </div>\n ",
38
38
  // Localizable strings
39
39
  untitledText: 'Untitled',
40
40
  clearHistoryTitle: 'Clear History',
@@ -59,6 +59,42 @@ window.chatInteractionManager = function () {
59
59
  span.textContent = text;
60
60
  return span.innerHTML;
61
61
  }
62
+ function containsFontAwesomePlaceholders(root) {
63
+ if (!root || root.nodeType !== 1) {
64
+ return false;
65
+ }
66
+ var selector = 'i[class*="fa-"],i.fa,i.fas,i.far,i.fab';
67
+ if (typeof root.matches === 'function' && root.matches(selector)) {
68
+ return true;
69
+ }
70
+ return typeof root.querySelector === 'function' && !!root.querySelector(selector);
71
+ }
72
+ function refreshFontAwesomeIcons(root) {
73
+ var fontAwesome = window.FontAwesome;
74
+ if (!containsFontAwesomePlaceholders(root) || !fontAwesome || !fontAwesome.dom || typeof fontAwesome.dom.i2svg !== 'function') {
75
+ return;
76
+ }
77
+ fontAwesome.dom.i2svg({
78
+ node: root
79
+ });
80
+ }
81
+ function observeFontAwesomeIcons(root) {
82
+ if (!root || typeof MutationObserver === 'undefined') {
83
+ return null;
84
+ }
85
+ var observer = new MutationObserver(function (mutations) {
86
+ mutations.forEach(function (mutation) {
87
+ mutation.addedNodes.forEach(function (node) {
88
+ refreshFontAwesomeIcons(node);
89
+ });
90
+ });
91
+ });
92
+ observer.observe(root, {
93
+ childList: true,
94
+ subtree: true
95
+ });
96
+ return observer;
97
+ }
62
98
  function normalizeReference(reference) {
63
99
  var _ref, _normalized$index, _ref2, _normalized$text, _ref3, _normalized$title, _ref4, _normalized$link, _ref5, _normalized$reference;
64
100
  if (!reference || _typeof(reference) !== 'object') {
@@ -247,7 +283,7 @@ window.chatInteractionManager = function () {
247
283
  highlighted = escapeHtmlEntities(code);
248
284
  }
249
285
  var langDisplay = lang ? escapeHtmlEntities(lang) : 'code';
250
- return "<div class=\"ai-code-block\"><div class=\"ai-code-header\"><span class=\"ai-code-lang\"><span class=\"fa-solid fa-code\"></span> ".concat(langDisplay, "</span><button type=\"button\" class=\"ai-code-copy-btn\" title=\"Copy code\"><span class=\"fa-regular fa-copy\"></span></button></div><pre><code class=\"hljs").concat(lang ? ' language-' + lang : '', "\">").concat(highlighted, "</code></pre></div>");
286
+ return "<div class=\"ai-code-block\"><div class=\"ai-code-header\"><span class=\"ai-code-lang\"><i class=\"fa-solid fa-code\"></i> ".concat(langDisplay, "</span><button type=\"button\" class=\"ai-code-copy-btn\" title=\"Copy code\"><i class=\"fa-regular fa-copy\"></i></button></div><pre><code class=\"hljs").concat(lang ? ' language-' + lang : '', "\">").concat(highlighted, "</code></pre></div>");
251
287
  };
252
288
 
253
289
  // Custom image renderer for generated images with thumbnail styling and download button.
@@ -257,7 +293,7 @@ window.chatInteractionManager = function () {
257
293
  if (!src) return '';
258
294
  var alt = data.text || defaultConfig.generatedImageAltText;
259
295
  var maxWidth = defaultConfig.generatedImageMaxWidth;
260
- return "<div class=\"generated-image-container\">\n <img src=\"".concat(src, "\" alt=\"").concat(alt, "\" class=\"img-thumbnail\" style=\"max-width: ").concat(maxWidth, "px; height: auto;\" />\n <div class=\"mt-2\">\n <a href=\"").concat(src, "\" target=\"_blank\" download=\"").concat(alt, "\" title=\"").concat(defaultConfig.downloadImageTitle, "\" class=\"btn btn-sm btn-outline-secondary ai-download-image\">\n <span class=\"fa-solid fa-download\"></span>\n </a>\n </div>\n </div>");
296
+ return "<div class=\"generated-image-container\">\n <img src=\"".concat(src, "\" alt=\"").concat(alt, "\" class=\"img-thumbnail\" style=\"max-width: ").concat(maxWidth, "px; height: auto;\" />\n <div class=\"mt-2\">\n <a href=\"").concat(src, "\" target=\"_blank\" download=\"").concat(alt, "\" title=\"").concat(defaultConfig.downloadImageTitle, "\" class=\"btn btn-sm btn-outline-secondary ai-download-image\">\n <i class=\"fa-solid fa-download\"></i>\n </a>\n </div>\n </div>");
261
297
  };
262
298
 
263
299
  // Chart counter for unique IDs
@@ -269,7 +305,7 @@ window.chatInteractionManager = function () {
269
305
  // Global chart config map shared with ai-chat.js
270
306
  window.__chartConfigs = window.__chartConfigs || {};
271
307
  function createChartHtml(chartId) {
272
- return "<div class=\"chart-container\" style=\"position: relative; width: 100%; max-width: 560px; min-height: 420px;\">" + "<canvas id=\"".concat(chartId, "\"></canvas>") + "</div>" + "<div class=\"mt-2\">" + "<button type=\"button\" class=\"btn btn-sm btn-outline-secondary download-chart-btn\" data-chart-id=\"".concat(chartId, "\" title=\"").concat(defaultConfig.downloadChartTitle, "\">") + "<span class=\"fa-solid fa-download\"></span> ".concat(defaultConfig.downloadChartButtonText) + "</button>" + "</div>";
308
+ return "<div class=\"chart-container\" style=\"position: relative; width: 100%; max-width: 560px; min-height: 420px;\">" + "<canvas id=\"".concat(chartId, "\"></canvas>") + "</div>" + "<div class=\"mt-2\">" + "<button type=\"button\" class=\"btn btn-sm btn-outline-secondary download-chart-btn\" data-chart-id=\"".concat(chartId, "\" title=\"").concat(defaultConfig.downloadChartTitle, "\">") + "<i class=\"fa-solid fa-download\"></i> ".concat(defaultConfig.downloadChartButtonText) + "</button>" + "</div>";
273
309
  }
274
310
 
275
311
  // Register [chart:{...json...}] as a native marked block extension so the
@@ -1063,7 +1099,7 @@ window.chatInteractionManager = function () {
1063
1099
  buttons.forEach(function (button) {
1064
1100
  var buttonIndex = Number(button.getAttribute('data-tts-message-index'));
1065
1101
  var isPlaying = buttonIndex === _this7.ttsPlayingMessageIndex;
1066
- var iconHtml = isPlaying ? '<span class="fa-solid fa-circle-pause"></span>' : '<span class="fa-solid fa-circle-play"></span>';
1102
+ var iconHtml = isPlaying ? '<i class="fa-solid fa-circle-pause"></i>' : '<i class="fa-solid fa-circle-play"></i>';
1067
1103
  button.classList.toggle('tts-playing', isPlaying);
1068
1104
  button.setAttribute('title', isPlaying ? 'Pause audio' : 'Read aloud');
1069
1105
  button.replaceChildren(DOMPurify.sanitize(iconHtml, {
@@ -1792,9 +1828,9 @@ window.chatInteractionManager = function () {
1792
1828
  if (codeEl) {
1793
1829
  navigator.clipboard.writeText(codeEl.textContent);
1794
1830
  var copiedText = config.codeCopiedText || 'Copied!';
1795
- btn.innerHTML = '<span class="fa-solid fa-check"></span> ' + copiedText;
1831
+ btn.innerHTML = '<i class="fa-solid fa-check"></i> ' + copiedText;
1796
1832
  setTimeout(function () {
1797
- btn.innerHTML = '<span class="fa-regular fa-copy"></span>';
1833
+ btn.innerHTML = '<i class="fa-regular fa-copy"></i>';
1798
1834
  }, 2000);
1799
1835
  }
1800
1836
  });
@@ -2093,10 +2129,10 @@ window.chatInteractionManager = function () {
2093
2129
  }
2094
2130
  if (this.isRecording) {
2095
2131
  this.micButton.classList.add('stt-recording');
2096
- this.micButton.innerHTML = '<span class="fa-solid fa-stop"></span>';
2132
+ this.micButton.innerHTML = '<i class="fa-solid fa-stop"></i>';
2097
2133
  } else {
2098
2134
  this.micButton.classList.remove('stt-recording');
2099
- this.micButton.innerHTML = '<span class="fa-solid fa-microphone"></span>';
2135
+ this.micButton.innerHTML = '<i class="fa-solid fa-microphone"></i>';
2100
2136
  }
2101
2137
  }
2102
2138
  },
@@ -2130,6 +2166,10 @@ window.chatInteractionManager = function () {
2130
2166
  return _this21.startConnection();
2131
2167
  case 1:
2132
2168
  _this21.initializeApp();
2169
+ _this21.$nextTick(function () {
2170
+ refreshFontAwesomeIcons(_this21.$el);
2171
+ _this21.fontAwesomeObserver = observeFontAwesomeIcons(_this21.$el);
2172
+ });
2133
2173
  case 2:
2134
2174
  return _context5.a(2);
2135
2175
  }
@@ -2141,6 +2181,10 @@ window.chatInteractionManager = function () {
2141
2181
  beforeUnmount: function beforeUnmount() {
2142
2182
  window.removeEventListener('beforeunload', this.handleBeforeUnload);
2143
2183
  window.removeEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
2184
+ if (this.fontAwesomeObserver) {
2185
+ this.fontAwesomeObserver.disconnect();
2186
+ this.fontAwesomeObserver = null;
2187
+ }
2144
2188
  this.stopAudio(false);
2145
2189
  if (this.stream) {
2146
2190
  this.stream.dispose();