@cloudflare/ai-search-snippet 0.0.23 → 0.0.25

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.
@@ -1,23 +1,35 @@
1
- var A = Object.defineProperty;
2
- var R = (o, i, e) => i in o ? A(o, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[i] = e;
3
- var r = (o, i, e) => R(o, typeof i != "symbol" ? i + "" : i, e);
4
- function T(o, i) {
1
+ var R = Object.defineProperty;
2
+ var H = (o, i, e) => i in o ? R(o, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[i] = e;
3
+ var a = (o, i, e) => H(o, typeof i != "symbol" ? i + "" : i, e);
4
+ const d = [
5
+ "Searching...",
6
+ "Digging through results...",
7
+ "Scanning the knowledge base...",
8
+ "Finding the best matches...",
9
+ "Sifting through the data...",
10
+ "Almost there...",
11
+ "Looking far and wide...",
12
+ "Connecting the dots...",
13
+ "Rummaging through pages...",
14
+ "Hunting down answers..."
15
+ ];
16
+ function A(o, i) {
5
17
  let e;
6
18
  return function(...s) {
7
- const a = () => {
19
+ const r = () => {
8
20
  clearTimeout(e), o(...s);
9
21
  };
10
- clearTimeout(e), e = setTimeout(a, i);
22
+ clearTimeout(e), e = setTimeout(r, i);
11
23
  };
12
24
  }
13
- function l(o) {
25
+ function h(o) {
14
26
  const i = document.createElement("div");
15
27
  return i.textContent = o, i.innerHTML;
16
28
  }
17
- function C(o) {
29
+ function S(o) {
18
30
  return new DOMParser().parseFromString(o, "text/html").documentElement.textContent || "";
19
31
  }
20
- function H(o) {
32
+ function N(o) {
21
33
  const i = new Date(o), t = (/* @__PURE__ */ new Date()).getTime() - i.getTime();
22
34
  if (t < 6e4)
23
35
  return "Just now";
@@ -36,13 +48,13 @@ function H(o) {
36
48
  minute: "2-digit"
37
49
  });
38
50
  }
39
- function S(o = "id") {
51
+ function E(o = "id") {
40
52
  return `${o}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
41
53
  }
42
- function u(o, i) {
54
+ function p(o, i) {
43
55
  return o !== null ? o : i;
44
56
  }
45
- function v(o, i) {
57
+ function m(o, i) {
46
58
  return o === null ? i : o === "true" || o === "";
47
59
  }
48
60
  function f(o, i) {
@@ -50,7 +62,7 @@ function f(o, i) {
50
62
  const e = Number.parseInt(o, 10);
51
63
  return Number.isNaN(e) ? i : e;
52
64
  }
53
- function m(o, i) {
65
+ function g(o, i) {
54
66
  return new CustomEvent(o, {
55
67
  detail: i,
56
68
  bubbles: !0,
@@ -63,10 +75,10 @@ function w(o) {
63
75
  throw new Error("API URL is required");
64
76
  return new P(o);
65
77
  }
66
- class N {
78
+ class _ {
67
79
  constructor(i) {
68
- r(this, "activeRequests", /* @__PURE__ */ new Map());
69
- r(this, "baseUrl");
80
+ a(this, "activeRequests", /* @__PURE__ */ new Map());
81
+ a(this, "baseUrl");
70
82
  this.baseUrl = i.replace(/\/$/, "");
71
83
  }
72
84
  search(i, e) {
@@ -85,7 +97,7 @@ class N {
85
97
  throw new Error("Not implemented");
86
98
  }
87
99
  }
88
- class P extends N {
100
+ class P extends _ {
89
101
  request(i = {}, e, t) {
90
102
  const s = e === "search" ? "snippet-search" : "snippet-chat-completions";
91
103
  return fetch(`${this.baseUrl}/${e}`, {
@@ -109,7 +121,7 @@ class P extends N {
109
121
  * Performs a search query with optional streaming
110
122
  */
111
123
  async search(i, e = {}) {
112
- const t = this.generateRequestId(), s = new AbortController(), a = e.signal || s.signal;
124
+ const t = this.generateRequestId(), s = new AbortController(), r = e.signal || s.signal;
113
125
  this.registerRequest(t, s);
114
126
  try {
115
127
  const n = await this.request(
@@ -119,38 +131,32 @@ class P extends N {
119
131
  maxResults: 30
120
132
  },
121
133
  "search",
122
- a
134
+ r
123
135
  );
124
136
  if (!n.ok)
125
137
  throw new Error(`HTTP error! status: ${n.status}`);
126
138
  if (!n.body)
127
139
  throw new Error("Response body is empty");
128
140
  const c = await n.json();
129
- if (c.success && c.result) {
130
- const h = /* @__PURE__ */ new Map();
131
- for (const d of c.result.chunks) {
132
- const g = d.item.key, p = d.scoring_details.vector_score;
133
- (!h.has(g) || (h.get(g)?.score ?? 0) < p) && h.set(g, { chunk: d, score: p });
134
- }
135
- return Array.from(h.values()).sort((d, g) => g.score - d.score).slice(0, 10).map(
136
- ({ chunk: d }) => ({
141
+ if (c.success && c.result)
142
+ return c.result.chunks.slice(0, 10).map(
143
+ (l) => ({
137
144
  type: "result",
138
- id: d.id,
139
- title: C(d.item.metadata.title),
140
- description: d.item.metadata.description ? C(d.item.metadata.description) : "",
141
- url: d.item.key,
142
- image: d.item.metadata.image || void 0,
143
- metadata: d.item.metadata
145
+ id: l.id,
146
+ title: S(l.item.metadata.title),
147
+ description: l.item.metadata.description ? S(l.item.metadata.description) : "",
148
+ url: l.item.key,
149
+ image: l.item.metadata.image || void 0,
150
+ metadata: l.item.metadata
144
151
  })
145
152
  );
146
- }
147
153
  throw c.success === !1 ? new Error(c.error) : new Error("Unknown error");
148
154
  } finally {
149
155
  this.unregisterRequest(t);
150
156
  }
151
157
  }
152
158
  async *searchStream(i, e) {
153
- const t = this.generateRequestId(), s = new AbortController(), a = e?.signal || s.signal;
159
+ const t = this.generateRequestId(), s = new AbortController(), r = e?.signal || s.signal;
154
160
  this.registerRequest(t, s);
155
161
  const n = await this.request(
156
162
  {
@@ -158,19 +164,19 @@ class P extends N {
158
164
  streaming: !0
159
165
  },
160
166
  "ai-search",
161
- a
167
+ r
162
168
  );
163
169
  if (!n.ok)
164
170
  throw new Error(`HTTP error! status: ${n.status}`);
165
171
  if (!n.body)
166
172
  throw new Error("Response body is empty");
167
173
  let c = "";
168
- const h = n.body.getReader(), d = new TextDecoder();
174
+ const l = n.body.getReader(), b = new TextDecoder();
169
175
  for (; ; ) {
170
- const { done: p, value: k } = await h.read();
171
- if (p)
176
+ const { done: u, value: C } = await l.read();
177
+ if (u)
172
178
  break;
173
- const B = d.decode(k, { stream: !0 });
179
+ const B = b.decode(C, { stream: !0 });
174
180
  c += B;
175
181
  }
176
182
  yield {
@@ -179,13 +185,13 @@ class P extends N {
179
185
  title: "",
180
186
  description: c.replaceAll("data: ", "").trim().split(`
181
187
 
182
- `).map((p) => JSON.parse(p)).map((p) => p.response).join(""),
188
+ `).map((u) => JSON.parse(u)).map((u) => u.response).join(""),
183
189
  url: "",
184
190
  metadata: {}
185
191
  };
186
192
  }
187
193
  async *chat(i, e) {
188
- const t = new AbortController(), s = e?.signal || t.signal, a = await this.request(
194
+ const t = new AbortController(), s = e?.signal || t.signal, r = await this.request(
189
195
  {
190
196
  query: i,
191
197
  streaming: !1
@@ -193,13 +199,13 @@ class P extends N {
193
199
  "chat/completions",
194
200
  s
195
201
  );
196
- if (!a.ok)
197
- throw new Error(`HTTP error! status: ${a.status}`);
198
- if (!a.body)
202
+ if (!r.ok)
203
+ throw new Error(`HTTP error! status: ${r.status}`);
204
+ if (!r.body)
199
205
  throw new Error("Response body is empty");
200
206
  yield {
201
207
  type: "text",
202
- message: (await a.json()).choices.map((c) => c.message.content).join("")
208
+ message: (await r.json()).choices.map((c) => c.message.content).join("")
203
209
  };
204
210
  }
205
211
  /**
@@ -239,10 +245,10 @@ class P extends N {
239
245
  return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
240
246
  }
241
247
  }
242
- const _ = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w3.org/2000/svg" aria-label="Cloudflare" role="img">
248
+ const V = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w3.org/2000/svg" aria-label="Cloudflare" role="img">
243
249
  <path fill="#f38020" d="m280.8395,183.31456c11,-26 -4,-38 -19,-38l-148,-2c-4,0 -4,-6 1,-7l150,-2c17,-1 37,-15 43,-33c0,0 10,-21 9,-24a97,97 0 0 0 -187,-11c-38,-25 -78,9 -69,46c-48,3 -65,46 -60,72c0,1 1,2 3,2l274,0c1,0 3,-1 3,-3z"/>
244
250
  <path fill="#faae40" d="m330.8395,81.31456c-4,0 -6,-1 -7,1l-5,21c-5,16 3,30 20,31l32,2c4,0 4,6 -1,7l-33,1c-36,4 -46,39 -46,39c0,2 0,3 2,3l113,0l3,-2a81,81 0 0 0 -78,-103"/>
245
- </svg>`, j = "https://search.ai.cloudflare.com", y = `Powered by <a href="${j}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${_}</a>`, $ = `
251
+ </svg>`, D = "https://search.ai.cloudflare.com", y = `Powered by <a href="${D}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${V}</a>`, $ = `
246
252
  /* Chat container */
247
253
  .chat-container {
248
254
  display: flex;
@@ -437,6 +443,10 @@ const _ = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
437
443
  }
438
444
  }
439
445
 
446
+ .chat-streaming .loading-text {
447
+ margin-left: var(--search-snippet-spacing-xs);
448
+ }
449
+
440
450
  /* Input area */
441
451
  .chat-input-area {
442
452
  padding: var(--search-snippet-spacing-md);
@@ -890,6 +900,27 @@ const _ = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
890
900
  to { transform: rotate(360deg); }
891
901
  }
892
902
 
903
+ /* Loading message animation */
904
+ @keyframes loading-message-in {
905
+ from {
906
+ opacity: 0;
907
+ transform: translateY(8px);
908
+ }
909
+ to {
910
+ opacity: 1;
911
+ transform: translateY(0);
912
+ }
913
+ }
914
+
915
+ .loading-text {
916
+ font-size: var(--search-snippet-font-size-sm);
917
+ color: var(--search-snippet-text-secondary);
918
+ }
919
+
920
+ .loading-text-animate {
921
+ animation: loading-message-in 0.3s ease-out;
922
+ }
923
+
893
924
  /* Error message */
894
925
  .error {
895
926
  padding: var(--search-snippet-spacing-md);
@@ -969,17 +1000,17 @@ const _ = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
969
1000
  text-align: center;
970
1001
  }
971
1002
  `;
972
- function K(o) {
1003
+ function O(o) {
973
1004
  let i = o;
974
- i = V(i), i = i.replace(/```([\s\S]*?)```/g, (n, c) => `<pre><code>${c.trim()}</code></pre>`);
1005
+ i = j(i), i = i.replace(/```([\s\S]*?)```/g, (n, c) => `<pre><code>${c.trim()}</code></pre>`);
975
1006
  const e = i.split(`
976
1007
  `), t = [];
977
- let s = !1, a = "";
1008
+ let s = !1, r = "";
978
1009
  for (let n = 0; n < e.length; n++) {
979
- const c = e[n], h = c.match(/^(#{1,6})\s+(.+)$/);
980
- if (h) {
981
- const p = h[1].length, k = h[2];
982
- t.push(`<h${p}>${b(k)}</h${p}>`);
1010
+ const c = e[n], l = c.match(/^(#{1,6})\s+(.+)$/);
1011
+ if (l) {
1012
+ const u = l[1].length, C = l[2];
1013
+ t.push(`<h${u}>${v(C)}</h${u}>`);
983
1014
  continue;
984
1015
  }
985
1016
  if (c.match(/^---+$/)) {
@@ -987,37 +1018,37 @@ function K(o) {
987
1018
  continue;
988
1019
  }
989
1020
  if (c.match(/^>\s+/)) {
990
- const p = c.replace(/^>\s+/, "");
991
- t.push(`<blockquote>${b(p)}</blockquote>`);
1021
+ const u = c.replace(/^>\s+/, "");
1022
+ t.push(`<blockquote>${v(u)}</blockquote>`);
992
1023
  continue;
993
1024
  }
994
- const d = c.match(/^[-*]\s+(.+)$/);
995
- if (d) {
996
- (!s || a !== "ul") && (s && t.push(`</${a}>`), t.push("<ul>"), s = !0, a = "ul"), t.push(`<li>${b(d[1])}</li>`);
1025
+ const b = c.match(/^[-*]\s+(.+)$/);
1026
+ if (b) {
1027
+ (!s || r !== "ul") && (s && t.push(`</${r}>`), t.push("<ul>"), s = !0, r = "ul"), t.push(`<li>${v(b[1])}</li>`);
997
1028
  continue;
998
1029
  }
999
- const g = c.match(/^\d+\.\s+(.+)$/);
1000
- if (g) {
1001
- (!s || a !== "ol") && (s && t.push(`</${a}>`), t.push("<ol>"), s = !0, a = "ol"), t.push(`<li>${b(g[1])}</li>`);
1030
+ const k = c.match(/^\d+\.\s+(.+)$/);
1031
+ if (k) {
1032
+ (!s || r !== "ol") && (s && t.push(`</${r}>`), t.push("<ol>"), s = !0, r = "ol"), t.push(`<li>${v(k[1])}</li>`);
1002
1033
  continue;
1003
1034
  }
1004
- if (s && (t.push(`</${a}>`), s = !1, a = ""), c.trim() === "") {
1035
+ if (s && (t.push(`</${r}>`), s = !1, r = ""), c.trim() === "") {
1005
1036
  t.push("<br />");
1006
1037
  continue;
1007
1038
  }
1008
- t.push(`<p>${b(c)}</p>`);
1039
+ t.push(`<p>${v(c)}</p>`);
1009
1040
  }
1010
- return s && t.push(`</${a}>`), t.join(`
1041
+ return s && t.push(`</${r}>`), t.join(`
1011
1042
  `);
1012
1043
  }
1013
- function b(o) {
1044
+ function v(o) {
1014
1045
  let i = o;
1015
1046
  return i = i.replace(/`([^`]+)`/g, "<code>$1</code>"), i = i.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>"), i = i.replace(/___(.+?)___/g, "<strong><em>$1</em></strong>"), i = i.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), i = i.replace(/__(.+?)__/g, "<strong>$1</strong>"), i = i.replace(/\*(.+?)\*/g, "<em>$1</em>"), i = i.replace(/_(.+?)_/g, "<em>$1</em>"), i = i.replace(
1016
1047
  /\[([^\]]+)\]\(([^)]+)\)/g,
1017
1048
  '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
1018
1049
  ), i;
1019
1050
  }
1020
- function V(o) {
1051
+ function j(o) {
1021
1052
  const i = {
1022
1053
  "&": "&amp;",
1023
1054
  "<": "&lt;",
@@ -1029,19 +1060,21 @@ function V(o) {
1029
1060
  }
1030
1061
  class q {
1031
1062
  constructor(i, e, t) {
1032
- r(this, "container");
1033
- r(this, "client");
1034
- r(this, "props");
1035
- r(this, "inputElement", null);
1036
- r(this, "messagesContainer", null);
1037
- r(this, "sendButton", null);
1038
- r(this, "messages", []);
1039
- r(this, "isStreaming", !1);
1040
- r(this, "currentStreamingMessageId", null);
1063
+ a(this, "container");
1064
+ a(this, "client");
1065
+ a(this, "props");
1066
+ a(this, "inputElement", null);
1067
+ a(this, "messagesContainer", null);
1068
+ a(this, "sendButton", null);
1069
+ a(this, "messages", []);
1070
+ a(this, "isStreaming", !1);
1071
+ a(this, "currentStreamingMessageId", null);
1072
+ a(this, "loadingMessageInterval", null);
1073
+ a(this, "loadingMessageIndex", 0);
1041
1074
  // Event handler references for cleanup
1042
- r(this, "handleInputResize", null);
1043
- r(this, "handleInputKeydown", null);
1044
- r(this, "handleSendClick", null);
1075
+ a(this, "handleInputResize", null);
1076
+ a(this, "handleInputKeydown", null);
1077
+ a(this, "handleSendClick", null);
1045
1078
  this.container = i, this.client = e, this.props = t, this.render(), this.attachEventListeners();
1046
1079
  }
1047
1080
  /**
@@ -1065,7 +1098,7 @@ class q {
1065
1098
  <div class="chat-input-wrapper">
1066
1099
  <textarea
1067
1100
  class="chat-input"
1068
- placeholder="${l(this.props.placeholder || "Type a message...")}"
1101
+ placeholder="${h(this.props.placeholder || "Type a message...")}"
1069
1102
  aria-label="Chat message input"
1070
1103
  style="height: 40px;"
1071
1104
  rows="1"
@@ -1104,13 +1137,13 @@ class q {
1104
1137
  */
1105
1138
  async sendMessage(i) {
1106
1139
  const e = {
1107
- id: S("msg"),
1140
+ id: E("msg"),
1108
1141
  role: "user",
1109
1142
  content: i,
1110
1143
  timestamp: Date.now()
1111
1144
  };
1112
1145
  this.addMessage(e), this.renderMessages(!0), this.setStreamingState(!0);
1113
- const t = S("msg"), s = {
1146
+ const t = E("msg"), s = {
1114
1147
  id: t,
1115
1148
  role: "assistant",
1116
1149
  content: "",
@@ -1118,22 +1151,22 @@ class q {
1118
1151
  };
1119
1152
  this.addMessage(s), this.currentStreamingMessageId = t, this.renderMessages(!0);
1120
1153
  try {
1121
- const a = this.client.chat(i);
1154
+ const r = this.client.chat(i);
1122
1155
  let n = "";
1123
- for await (const h of a)
1124
- if (h.type === "text" && h.message)
1125
- n += h.message, this.updateStreamingMessage(t, n);
1126
- else if (h.type === "error") {
1127
- this.showErrorInMessage(t, h.message || "Unknown error");
1156
+ for await (const l of r)
1157
+ if (l.type === "text" && l.message)
1158
+ n += l.message, this.updateStreamingMessage(t, n);
1159
+ else if (l.type === "error") {
1160
+ this.showErrorInMessage(t, l.message || "Unknown error");
1128
1161
  break;
1129
1162
  }
1130
- const c = this.messages.findIndex((h) => h.id === t);
1131
- c !== -1 && (this.messages[c].content = n), this.container.dispatchEvent(m("message", { message: s }));
1132
- } catch (a) {
1133
- this.showErrorInMessage(t, a.message), this.container.dispatchEvent(
1134
- m("error", {
1163
+ const c = this.messages.findIndex((l) => l.id === t);
1164
+ c !== -1 && (this.messages[c].content = n), this.container.dispatchEvent(g("message", { message: s }));
1165
+ } catch (r) {
1166
+ this.showErrorInMessage(t, r.message), this.container.dispatchEvent(
1167
+ g("error", {
1135
1168
  error: {
1136
- message: a.message,
1169
+ message: r.message,
1137
1170
  code: "CHAT_ERROR"
1138
1171
  }
1139
1172
  })
@@ -1196,11 +1229,11 @@ class q {
1196
1229
  <div class="chat-message-avatar">${s}</div>
1197
1230
  <div class="chat-message-content">
1198
1231
  <div class="chat-message-bubble">
1199
- ${i.content ? `<div class="chat-message-text">${K(i.content)}</div>` : ""}
1200
- ${e ? '<div class="chat-streaming"><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span></div>' : ""}
1232
+ ${i.content ? `<div class="chat-message-text">${O(i.content)}</div>` : ""}
1233
+ ${e ? `<div class="chat-streaming"><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="loading-text">${d[this.loadingMessageIndex]}</span></div>` : ""}
1201
1234
  </div>
1202
1235
  <div class="chat-message-metadata">
1203
- <span class="chat-message-time">${H(i.timestamp)}</span>
1236
+ <span class="chat-message-time">${N(i.timestamp)}</span>
1204
1237
  </div>
1205
1238
  </div>
1206
1239
  </div>
@@ -1218,7 +1251,15 @@ class q {
1218
1251
  * Set streaming state
1219
1252
  */
1220
1253
  setStreamingState(i) {
1221
- this.isStreaming = i, this.inputElement && (this.inputElement.disabled = i), this.sendButton && (this.sendButton.disabled = i, this.sendButton.innerHTML = i ? '<div class="loading"></div>' : "<span>Send</span>");
1254
+ this.isStreaming = i, this.inputElement && (this.inputElement.disabled = i), this.sendButton && (this.sendButton.disabled = i, this.sendButton.innerHTML = i ? '<div class="loading"></div>' : "<span>Send</span>"), i ? this.startLoadingMessages() : this.clearLoadingMessages();
1255
+ }
1256
+ startLoadingMessages() {
1257
+ this.loadingMessageIndex = Math.floor(Math.random() * d.length), this.loadingMessageInterval = setInterval(() => {
1258
+ this.loadingMessageIndex = (this.loadingMessageIndex + 1) % d.length, this.isStreaming && this.renderMessages(!0);
1259
+ }, 2500);
1260
+ }
1261
+ clearLoadingMessages() {
1262
+ this.loadingMessageInterval && (clearInterval(this.loadingMessageInterval), this.loadingMessageInterval = null);
1222
1263
  }
1223
1264
  /**
1224
1265
  * Get all messages
@@ -1242,31 +1283,31 @@ class q {
1242
1283
  * Destroy and cleanup
1243
1284
  */
1244
1285
  destroy() {
1245
- this.isStreaming && this.client.cancelAllRequests(), this.inputElement && (this.handleInputResize && this.inputElement.removeEventListener("input", this.handleInputResize), this.handleInputKeydown && this.inputElement.removeEventListener("keydown", this.handleInputKeydown)), this.sendButton && this.handleSendClick && this.sendButton.removeEventListener("click", this.handleSendClick), this.handleInputResize = null, this.handleInputKeydown = null, this.handleSendClick = null;
1286
+ this.clearLoadingMessages(), this.isStreaming && this.client.cancelAllRequests(), this.inputElement && (this.handleInputResize && this.inputElement.removeEventListener("input", this.handleInputResize), this.handleInputKeydown && this.inputElement.removeEventListener("keydown", this.handleInputKeydown)), this.sendButton && this.handleSendClick && this.sendButton.removeEventListener("click", this.handleSendClick), this.handleInputResize = null, this.handleInputKeydown = null, this.handleSendClick = null;
1246
1287
  }
1247
1288
  }
1248
- const E = "chat-bubble-snippet";
1249
- class O extends HTMLElement {
1289
+ const M = "chat-bubble-snippet";
1290
+ class K extends HTMLElement {
1250
1291
  constructor() {
1251
1292
  super();
1252
- r(this, "shadow");
1253
- r(this, "client", null);
1254
- r(this, "chatView", null);
1255
- r(this, "container", null);
1256
- r(this, "isExpanded", !1);
1257
- r(this, "isMinimized", !1);
1293
+ a(this, "shadow");
1294
+ a(this, "client", null);
1295
+ a(this, "chatView", null);
1296
+ a(this, "container", null);
1297
+ a(this, "isExpanded", !1);
1298
+ a(this, "isMinimized", !1);
1258
1299
  // Event handler references for cleanup
1259
- r(this, "handleBubbleClick", null);
1260
- r(this, "handleCloseClick", null);
1261
- r(this, "handleMinimizeClick", null);
1262
- r(this, "handleClearClick", null);
1300
+ a(this, "handleBubbleClick", null);
1301
+ a(this, "handleCloseClick", null);
1302
+ a(this, "handleMinimizeClick", null);
1303
+ a(this, "handleClearClick", null);
1263
1304
  this.shadow = this.attachShadow({ mode: "open" });
1264
1305
  }
1265
1306
  static get observedAttributes() {
1266
1307
  return ["api-url", "placeholder", "theme", "hide-branding"];
1267
1308
  }
1268
1309
  connectedCallback() {
1269
- this.render(), this.initializeClient(), this.dispatchEvent(m("ready", void 0));
1310
+ this.render(), this.initializeClient(), this.dispatchEvent(g("ready", void 0));
1270
1311
  }
1271
1312
  disconnectedCallback() {
1272
1313
  this.cleanup();
@@ -1276,10 +1317,10 @@ class O extends HTMLElement {
1276
1317
  }
1277
1318
  getProps() {
1278
1319
  return {
1279
- apiUrl: u(this.getAttribute("api-url"), "http://localhost:3000"),
1280
- placeholder: u(this.getAttribute("placeholder"), "Type a message..."),
1281
- theme: u(this.getAttribute("theme"), "auto"),
1282
- hideBranding: v(this.getAttribute("hide-branding"), !1)
1320
+ apiUrl: p(this.getAttribute("api-url"), "http://localhost:3000"),
1321
+ placeholder: p(this.getAttribute("placeholder"), "Type a message..."),
1322
+ theme: p(this.getAttribute("theme"), "auto"),
1323
+ hideBranding: m(this.getAttribute("hide-branding"), !1)
1283
1324
  };
1284
1325
  }
1285
1326
  initializeClient() {
@@ -1482,12 +1523,12 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1482
1523
  `;
1483
1524
  }
1484
1525
  attachEventListeners() {
1485
- const e = this.shadow.querySelector(".bubble-button"), t = this.shadow.querySelector(".close-button"), s = this.shadow.querySelector(".minimize-button"), a = this.shadow.querySelector(".clear-button");
1486
- this.handleBubbleClick = () => this.toggleChat(), this.handleCloseClick = () => this.closeChat(), this.handleMinimizeClick = () => this.toggleMinimize(), this.handleClearClick = () => this.clearChat(), e?.addEventListener("click", this.handleBubbleClick), t?.addEventListener("click", this.handleCloseClick), s?.addEventListener("click", this.handleMinimizeClick), a?.addEventListener("click", this.handleClearClick);
1526
+ const e = this.shadow.querySelector(".bubble-button"), t = this.shadow.querySelector(".close-button"), s = this.shadow.querySelector(".minimize-button"), r = this.shadow.querySelector(".clear-button");
1527
+ this.handleBubbleClick = () => this.toggleChat(), this.handleCloseClick = () => this.closeChat(), this.handleMinimizeClick = () => this.toggleMinimize(), this.handleClearClick = () => this.clearChat(), e?.addEventListener("click", this.handleBubbleClick), t?.addEventListener("click", this.handleCloseClick), s?.addEventListener("click", this.handleMinimizeClick), r?.addEventListener("click", this.handleClearClick);
1487
1528
  }
1488
1529
  removeEventListeners() {
1489
- const e = this.shadow.querySelector(".bubble-button"), t = this.shadow.querySelector(".close-button"), s = this.shadow.querySelector(".minimize-button"), a = this.shadow.querySelector(".clear-button");
1490
- this.handleBubbleClick && e?.removeEventListener("click", this.handleBubbleClick), this.handleCloseClick && t?.removeEventListener("click", this.handleCloseClick), this.handleMinimizeClick && s?.removeEventListener("click", this.handleMinimizeClick), this.handleClearClick && a?.removeEventListener("click", this.handleClearClick), this.handleBubbleClick = null, this.handleCloseClick = null, this.handleMinimizeClick = null, this.handleClearClick = null;
1530
+ const e = this.shadow.querySelector(".bubble-button"), t = this.shadow.querySelector(".close-button"), s = this.shadow.querySelector(".minimize-button"), r = this.shadow.querySelector(".clear-button");
1531
+ this.handleBubbleClick && e?.removeEventListener("click", this.handleBubbleClick), this.handleCloseClick && t?.removeEventListener("click", this.handleCloseClick), this.handleMinimizeClick && s?.removeEventListener("click", this.handleMinimizeClick), this.handleClearClick && r?.removeEventListener("click", this.handleClearClick), this.handleBubbleClick = null, this.handleCloseClick = null, this.handleMinimizeClick = null, this.handleClearClick = null;
1491
1532
  }
1492
1533
  toggleChat() {
1493
1534
  this.isExpanded = !this.isExpanded;
@@ -1528,31 +1569,31 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1528
1569
  return this.chatView?.getMessages() || [];
1529
1570
  }
1530
1571
  }
1531
- customElements.get(E) || customElements.define(E, O);
1532
- const M = "chat-page-snippet", L = "chat-page-sessions";
1533
- class D extends HTMLElement {
1572
+ customElements.get(M) || customElements.define(M, K);
1573
+ const L = "chat-page-snippet", I = "chat-page-sessions";
1574
+ class U extends HTMLElement {
1534
1575
  constructor() {
1535
1576
  super();
1536
- r(this, "shadow");
1537
- r(this, "client", null);
1538
- r(this, "chatView", null);
1539
- r(this, "container", null);
1540
- r(this, "sessions", []);
1541
- r(this, "currentSessionId", null);
1542
- r(this, "sidebarCollapsed", !1);
1577
+ a(this, "shadow");
1578
+ a(this, "client", null);
1579
+ a(this, "chatView", null);
1580
+ a(this, "container", null);
1581
+ a(this, "sessions", []);
1582
+ a(this, "currentSessionId", null);
1583
+ a(this, "sidebarCollapsed", !1);
1543
1584
  // Event handler references for cleanup
1544
- r(this, "handleClearClick", null);
1545
- r(this, "handleNewChatClick", null);
1546
- r(this, "handleToggleSidebarClick", null);
1547
- r(this, "handleChatListClick", null);
1548
- r(this, "handleMessageEvent", null);
1585
+ a(this, "handleClearClick", null);
1586
+ a(this, "handleNewChatClick", null);
1587
+ a(this, "handleToggleSidebarClick", null);
1588
+ a(this, "handleChatListClick", null);
1589
+ a(this, "handleMessageEvent", null);
1549
1590
  this.shadow = this.attachShadow({ mode: "open" }), this.loadSessions();
1550
1591
  }
1551
1592
  static get observedAttributes() {
1552
1593
  return ["api-url", "placeholder", "theme", "hide-branding"];
1553
1594
  }
1554
1595
  connectedCallback() {
1555
- this.render(), this.initializeClient(), this.setupView(), this.dispatchEvent(m("ready", void 0));
1596
+ this.render(), this.initializeClient(), this.setupView(), this.dispatchEvent(g("ready", void 0));
1556
1597
  }
1557
1598
  disconnectedCallback() {
1558
1599
  this.saveCurrentSession(), this.cleanup();
@@ -1562,10 +1603,10 @@ class D extends HTMLElement {
1562
1603
  }
1563
1604
  getProps() {
1564
1605
  return {
1565
- apiUrl: u(this.getAttribute("api-url"), "http://localhost:3000"),
1566
- placeholder: u(this.getAttribute("placeholder"), "Type a message..."),
1567
- theme: u(this.getAttribute("theme"), "auto"),
1568
- hideBranding: v(this.getAttribute("hide-branding"), !1)
1606
+ apiUrl: p(this.getAttribute("api-url"), "http://localhost:3000"),
1607
+ placeholder: p(this.getAttribute("placeholder"), "Type a message..."),
1608
+ theme: p(this.getAttribute("theme"), "auto"),
1609
+ hideBranding: m(this.getAttribute("hide-branding"), !1)
1569
1610
  };
1570
1611
  }
1571
1612
  initializeClient() {
@@ -1908,12 +1949,12 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1908
1949
  `;
1909
1950
  }
1910
1951
  attachEventListeners() {
1911
- const e = this.shadow.querySelector(".clear-button"), t = this.shadow.querySelector(".new-chat-button"), s = this.shadow.querySelector(".toggle-sidebar-button"), a = this.shadow.querySelector(".chat-list");
1912
- this.handleClearClick = () => this.clearCurrentChat(), this.handleNewChatClick = () => this.createNewChat(), this.handleToggleSidebarClick = () => this.toggleSidebar(), this.handleChatListClick = (n) => this.onChatListClick(n), e?.addEventListener("click", this.handleClearClick), t?.addEventListener("click", this.handleNewChatClick), s?.addEventListener("click", this.handleToggleSidebarClick), a?.addEventListener("click", this.handleChatListClick);
1952
+ const e = this.shadow.querySelector(".clear-button"), t = this.shadow.querySelector(".new-chat-button"), s = this.shadow.querySelector(".toggle-sidebar-button"), r = this.shadow.querySelector(".chat-list");
1953
+ this.handleClearClick = () => this.clearCurrentChat(), this.handleNewChatClick = () => this.createNewChat(), this.handleToggleSidebarClick = () => this.toggleSidebar(), this.handleChatListClick = (n) => this.onChatListClick(n), e?.addEventListener("click", this.handleClearClick), t?.addEventListener("click", this.handleNewChatClick), s?.addEventListener("click", this.handleToggleSidebarClick), r?.addEventListener("click", this.handleChatListClick);
1913
1954
  }
1914
1955
  removeEventListeners() {
1915
- const e = this.shadow.querySelector(".clear-button"), t = this.shadow.querySelector(".new-chat-button"), s = this.shadow.querySelector(".toggle-sidebar-button"), a = this.shadow.querySelector(".chat-list"), n = this.shadow.querySelector(".container");
1916
- this.handleClearClick && e?.removeEventListener("click", this.handleClearClick), this.handleNewChatClick && t?.removeEventListener("click", this.handleNewChatClick), this.handleToggleSidebarClick && s?.removeEventListener("click", this.handleToggleSidebarClick), this.handleChatListClick && a?.removeEventListener("click", this.handleChatListClick), this.handleMessageEvent && n && n.removeEventListener("message", this.handleMessageEvent), this.handleClearClick = null, this.handleNewChatClick = null, this.handleToggleSidebarClick = null, this.handleChatListClick = null, this.handleMessageEvent = null;
1956
+ const e = this.shadow.querySelector(".clear-button"), t = this.shadow.querySelector(".new-chat-button"), s = this.shadow.querySelector(".toggle-sidebar-button"), r = this.shadow.querySelector(".chat-list"), n = this.shadow.querySelector(".container");
1957
+ this.handleClearClick && e?.removeEventListener("click", this.handleClearClick), this.handleNewChatClick && t?.removeEventListener("click", this.handleNewChatClick), this.handleToggleSidebarClick && s?.removeEventListener("click", this.handleToggleSidebarClick), this.handleChatListClick && r?.removeEventListener("click", this.handleChatListClick), this.handleMessageEvent && n && n.removeEventListener("message", this.handleMessageEvent), this.handleClearClick = null, this.handleNewChatClick = null, this.handleToggleSidebarClick = null, this.handleChatListClick = null, this.handleMessageEvent = null;
1917
1958
  }
1918
1959
  setupView() {
1919
1960
  if (!this.client) return;
@@ -1935,7 +1976,7 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1935
1976
  }
1936
1977
  loadSessions() {
1937
1978
  try {
1938
- const e = localStorage.getItem(L);
1979
+ const e = localStorage.getItem(I);
1939
1980
  e && (this.sessions = JSON.parse(e), this.sessions.sort((t, s) => s.updatedAt - t.updatedAt));
1940
1981
  } catch (e) {
1941
1982
  console.error("Failed to load chat sessions:", e);
@@ -1943,7 +1984,7 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1943
1984
  }
1944
1985
  saveSessions() {
1945
1986
  try {
1946
- localStorage.setItem(L, JSON.stringify(this.sessions));
1987
+ localStorage.setItem(I, JSON.stringify(this.sessions));
1947
1988
  } catch (e) {
1948
1989
  console.error("Failed to save chat sessions:", e);
1949
1990
  }
@@ -1998,9 +2039,9 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1998
2039
  n && this.deleteSession(n);
1999
2040
  return;
2000
2041
  }
2001
- const a = t.closest(".chat-list-item");
2002
- if (a) {
2003
- const n = a.getAttribute("data-session-id");
2042
+ const r = t.closest(".chat-list-item");
2043
+ if (r) {
2044
+ const n = r.getAttribute("data-session-id");
2004
2045
  n && this.switchToSession(n);
2005
2046
  }
2006
2047
  }
@@ -2031,7 +2072,7 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
2031
2072
  `;
2032
2073
  }
2033
2074
  formatDate(e) {
2034
- const t = new Date(e), a = (/* @__PURE__ */ new Date()).getTime() - t.getTime(), n = Math.floor(a / (1e3 * 60 * 60 * 24));
2075
+ const t = new Date(e), r = (/* @__PURE__ */ new Date()).getTime() - t.getTime(), n = Math.floor(r / (1e3 * 60 * 60 * 24));
2035
2076
  return n === 0 ? t.toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" }) : n === 1 ? "Yesterday" : n < 7 ? t.toLocaleDateString(void 0, { weekday: "long" }) : t.toLocaleDateString(void 0, { month: "short", day: "numeric" });
2036
2077
  }
2037
2078
  escapeHTML(e) {
@@ -2061,8 +2102,8 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
2061
2102
  return this.sessions.find((e) => e.id === this.currentSessionId) || null;
2062
2103
  }
2063
2104
  }
2064
- customElements.get(M) || customElements.define(M, D);
2065
- const U = `
2105
+ customElements.get(L) || customElements.define(L, U);
2106
+ const G = `
2066
2107
  /* Search view states */
2067
2108
  .search-view {
2068
2109
  transition: var(--search-snippet-transition-slow);
@@ -2398,19 +2439,21 @@ a.search-result-item:focus-visible {
2398
2439
  class F extends HTMLElement {
2399
2440
  constructor() {
2400
2441
  super();
2401
- r(this, "shadow");
2402
- r(this, "client", null);
2403
- r(this, "container", null);
2404
- r(this, "inputElement", null);
2405
- r(this, "resultsContainer", null);
2406
- r(this, "searchButton", null);
2407
- r(this, "debouncedSearch", null);
2408
- r(this, "currentSearchController", null);
2442
+ a(this, "shadow");
2443
+ a(this, "client", null);
2444
+ a(this, "container", null);
2445
+ a(this, "inputElement", null);
2446
+ a(this, "resultsContainer", null);
2447
+ a(this, "searchButton", null);
2448
+ a(this, "debouncedSearch", null);
2449
+ a(this, "currentSearchController", null);
2450
+ a(this, "loadingMessageInterval", null);
2451
+ a(this, "loadingMessageIndex", 0);
2409
2452
  // Event handler references for cleanup
2410
- r(this, "handleInputChange", null);
2411
- r(this, "handleInputKeydownEnter", null);
2412
- r(this, "handleInputKeydownEscape", null);
2413
- r(this, "handleSearchButtonClick", null);
2453
+ a(this, "handleInputChange", null);
2454
+ a(this, "handleInputKeydownEnter", null);
2455
+ a(this, "handleInputKeydownEscape", null);
2456
+ a(this, "handleSearchButtonClick", null);
2414
2457
  this.shadow = this.attachShadow({ mode: "open" });
2415
2458
  }
2416
2459
  static get observedAttributes() {
@@ -2425,7 +2468,7 @@ class F extends HTMLElement {
2425
2468
  ];
2426
2469
  }
2427
2470
  connectedCallback() {
2428
- this.initializeClient(), this.render(), this.dispatchEvent(m("ready", void 0));
2471
+ this.initializeClient(), this.render(), this.dispatchEvent(g("ready", void 0));
2429
2472
  }
2430
2473
  disconnectedCallback() {
2431
2474
  this.cleanup();
@@ -2435,13 +2478,13 @@ class F extends HTMLElement {
2435
2478
  }
2436
2479
  getProps() {
2437
2480
  return {
2438
- apiUrl: u(this.getAttribute("api-url"), "http://localhost:3000"),
2439
- placeholder: u(this.getAttribute("placeholder"), "Search..."),
2481
+ apiUrl: p(this.getAttribute("api-url"), "http://localhost:3000"),
2482
+ placeholder: p(this.getAttribute("placeholder"), "Search..."),
2440
2483
  maxResults: f(this.getAttribute("max-results"), 10),
2441
2484
  debounceMs: f(this.getAttribute("debounce-ms"), 300),
2442
- theme: u(this.getAttribute("theme"), "auto"),
2443
- hideBranding: v(this.getAttribute("hide-branding"), !1),
2444
- showUrl: v(this.getAttribute("show-url"), !1)
2485
+ theme: p(this.getAttribute("theme"), "auto"),
2486
+ hideBranding: m(this.getAttribute("hide-branding"), !1),
2487
+ showUrl: m(this.getAttribute("show-url"), !1)
2445
2488
  };
2446
2489
  }
2447
2490
  initializeClient() {
@@ -2457,14 +2500,14 @@ class F extends HTMLElement {
2457
2500
  }
2458
2501
  }
2459
2502
  render() {
2460
- const e = this.getProps(), t = (a) => this.performSearch(a);
2461
- this.debouncedSearch = T(
2503
+ const e = this.getProps(), t = (r) => this.performSearch(r);
2504
+ this.debouncedSearch = A(
2462
2505
  t,
2463
2506
  e.debounceMs || 400
2464
2507
  );
2465
2508
  const s = document.createElement("style");
2466
2509
  s.textContent = `${x}
2467
- ${U}`, this.container = document.createElement("div"), this.container.className = "container", this.container.innerHTML = `
2510
+ ${G}`, this.container = document.createElement("div"), this.container.className = "container", this.container.innerHTML = `
2468
2511
  <div class="search-view">
2469
2512
  <div class="search-input-wrapper">
2470
2513
  <svg xmlns="http://www.w3.org/2000/svg" class="search-icon" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>
@@ -2472,7 +2515,7 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2472
2515
  type="text"
2473
2516
  name="search-input"
2474
2517
  class="search-input"
2475
- placeholder="${l(e.placeholder || "Search...")}"
2518
+ placeholder="${h(e.placeholder || "Search...")}"
2476
2519
  aria-label="Search input"
2477
2520
  autocomplete="off"
2478
2521
  />
@@ -2523,17 +2566,17 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2523
2566
  }
2524
2567
  }
2525
2568
  displayResults(e, t) {
2526
- if (!this.resultsContainer) return;
2569
+ if (this.clearLoadingInterval(), !this.resultsContainer) return;
2527
2570
  if (e.length === 0) {
2528
2571
  this.showNoResultsState(t);
2529
2572
  return;
2530
2573
  }
2531
- const a = this.getProps().hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = `
2574
+ const r = this.getProps().hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = `
2532
2575
  <div class="search-header">
2533
2576
  <div class="search-count">
2534
2577
  Found ${e.length} result${e.length === 1 ? "" : "s"}
2535
2578
  </div>
2536
- ${a}
2579
+ ${r}
2537
2580
  </div>
2538
2581
  <div class="search-results">
2539
2582
  ${e.map((c) => this.renderResult(c)).join("")}
@@ -2544,12 +2587,12 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2544
2587
  renderResult(e) {
2545
2588
  const t = this.getProps(), s = this.renderResultImage(e.image, e.title);
2546
2589
  return `
2547
- <a href="${e.url ? l(e.url) : "#"}" class="search-result-item" data-result-id="${l(e.url || "")}">
2590
+ <a href="${e.url ? h(e.url) : "#"}" class="search-result-item" data-result-id="${h(e.url || "")}">
2548
2591
  ${s}
2549
2592
  <div class="search-result-content">
2550
- <div class="search-result-title">${l(e.title || "")}</div>
2551
- <div class="search-result-snippet">${l(e.description || "")}</div>
2552
- ${t.showUrl && e.url ? `<span class="search-result-url">${l(e.url)}</span>` : ""}
2593
+ <div class="search-result-title">${h(e.title || "")}</div>
2594
+ <div class="search-result-snippet">${h(e.description || "")}</div>
2595
+ ${t.showUrl && e.url ? `<span class="search-result-url">${h(e.url)}</span>` : ""}
2553
2596
  </div>
2554
2597
  </a>
2555
2598
  `;
@@ -2562,8 +2605,8 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2562
2605
  <div class="search-result-image-placeholder" style="display: none;">${s}</div>
2563
2606
  <img
2564
2607
  class="search-result-image"
2565
- src="${l(e)}"
2566
- alt="${l(t)}"
2608
+ src="${h(e)}"
2609
+ alt="${h(t)}"
2567
2610
  loading="lazy"
2568
2611
  />
2569
2612
  </div>
@@ -2584,9 +2627,9 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2584
2627
  s.addEventListener("load", () => {
2585
2628
  s.classList.add("loaded"), s.closest(".search-result-image-container")?.querySelector(".search-result-image-loading")?.remove();
2586
2629
  }), s.addEventListener("error", () => {
2587
- const a = s.closest(".search-result-image-container");
2588
- a?.querySelector(".search-result-image-loading")?.remove();
2589
- const n = a?.querySelector(
2630
+ const r = s.closest(".search-result-image-container");
2631
+ r?.querySelector(".search-result-image-loading")?.remove();
2632
+ const n = r?.querySelector(
2590
2633
  ".search-result-image-placeholder"
2591
2634
  );
2592
2635
  n && (n.style.display = "flex"), s.style.display = "none";
@@ -2594,15 +2637,25 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2594
2637
  });
2595
2638
  }
2596
2639
  showLoadingState() {
2597
- this.resultsContainer && (this.resultsContainer.innerHTML = `
2640
+ this.resultsContainer && (this.clearLoadingInterval(), this.loadingMessageIndex = Math.floor(Math.random() * d.length), this.resultsContainer.innerHTML = `
2598
2641
  <div class="search-loading">
2599
2642
  <div class="loading" aria-label="Loading"></div>
2600
- <div>Searching...</div>
2643
+ <div class="loading-text loading-text-animate">${d[this.loadingMessageIndex]}</div>
2601
2644
  </div>
2602
- `);
2645
+ `, this.startLoadingInterval());
2646
+ }
2647
+ startLoadingInterval() {
2648
+ this.loadingMessageInterval = setInterval(() => {
2649
+ this.loadingMessageIndex = (this.loadingMessageIndex + 1) % d.length;
2650
+ const e = this.resultsContainer?.querySelector(".loading-text");
2651
+ e && (e.classList.remove("loading-text-animate"), e.offsetWidth, e.textContent = d[this.loadingMessageIndex], e.classList.add("loading-text-animate"));
2652
+ }, 2500);
2653
+ }
2654
+ clearLoadingInterval() {
2655
+ this.loadingMessageInterval && (clearInterval(this.loadingMessageInterval), this.loadingMessageInterval = null);
2603
2656
  }
2604
2657
  showEmptyState() {
2605
- this.resultsContainer && (this.resultsContainer.innerHTML = `
2658
+ this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = `
2606
2659
  <div class="search-empty">
2607
2660
  <svg class="search-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
2608
2661
  <circle cx="11" cy="11" r="8"></circle>
@@ -2616,7 +2669,7 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2616
2669
  `);
2617
2670
  }
2618
2671
  showNoResultsState(e) {
2619
- this.resultsContainer && (this.resultsContainer.innerHTML = `
2672
+ this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = `
2620
2673
  <div class="search-empty">
2621
2674
  <svg class="search-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
2622
2675
  <circle cx="11" cy="11" r="8"></circle>
@@ -2624,15 +2677,15 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2624
2677
  </svg>
2625
2678
  <div class="search-empty-title">No Results Found</div>
2626
2679
  <div class="search-empty-description">
2627
- No results found for "${l(e)}"
2680
+ No results found for "${h(e)}"
2628
2681
  </div>
2629
2682
  </div>
2630
2683
  `);
2631
2684
  }
2632
2685
  showErrorState(e) {
2633
- this.resultsContainer && (this.resultsContainer.innerHTML = `
2686
+ this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = `
2634
2687
  <div class="error">
2635
- <strong>Error:</strong> ${l(e)}
2688
+ <strong>Error:</strong> ${h(e)}
2636
2689
  </div>
2637
2690
  `);
2638
2691
  }
@@ -2641,7 +2694,7 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2641
2694
  t === "auto" ? this.removeAttribute("theme") : this.setAttribute("theme", t);
2642
2695
  }
2643
2696
  cleanup() {
2644
- this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.client && this.client.cancelAllRequests(), this.inputElement && (this.handleInputChange && this.inputElement.removeEventListener("input", this.handleInputChange), this.handleInputKeydownEnter && this.inputElement.removeEventListener("keydown", this.handleInputKeydownEnter), this.handleInputKeydownEscape && window.removeEventListener("keydown", this.handleInputKeydownEscape)), this.searchButton && this.handleSearchButtonClick && this.searchButton.removeEventListener("click", this.handleSearchButtonClick), this.handleInputChange = null, this.handleInputKeydownEnter = null, this.handleInputKeydownEscape = null, this.handleSearchButtonClick = null;
2697
+ this.clearLoadingInterval(), this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.client && this.client.cancelAllRequests(), this.inputElement && (this.handleInputChange && this.inputElement.removeEventListener("input", this.handleInputChange), this.handleInputKeydownEnter && this.inputElement.removeEventListener("keydown", this.handleInputKeydownEnter), this.handleInputKeydownEscape && window.removeEventListener("keydown", this.handleInputKeydownEscape)), this.searchButton && this.handleSearchButtonClick && this.searchButton.removeEventListener("click", this.handleSearchButtonClick), this.handleInputChange = null, this.handleInputKeydownEnter = null, this.handleInputKeydownEscape = null, this.handleSearchButtonClick = null;
2645
2698
  }
2646
2699
  // Public API
2647
2700
  async search(e) {
@@ -2649,7 +2702,7 @@ ${U}`, this.container = document.createElement("div"), this.container.className
2649
2702
  }
2650
2703
  }
2651
2704
  customElements.get(z) || customElements.define(z, F);
2652
- const G = `
2705
+ const Y = `
2653
2706
  /* Modal backdrop */
2654
2707
  .modal-backdrop {
2655
2708
  position: fixed;
@@ -3048,30 +3101,32 @@ a.modal-result-item:focus-visible {
3048
3101
  .modal-container.open {
3049
3102
  animation: modal-slide-in var(--search-snippet-transition) ease-out;
3050
3103
  }
3051
- `, I = "search-modal-snippet";
3052
- class Y extends HTMLElement {
3104
+ `, T = "search-modal-snippet";
3105
+ class W extends HTMLElement {
3053
3106
  constructor() {
3054
3107
  super();
3055
- r(this, "shadow");
3056
- r(this, "client", null);
3057
- r(this, "backdrop", null);
3058
- r(this, "modal", null);
3059
- r(this, "inputElement", null);
3060
- r(this, "resultsContainer", null);
3061
- r(this, "footerCount", null);
3062
- r(this, "isOpen", !1);
3063
- r(this, "results", []);
3064
- r(this, "activeIndex", -1);
3065
- r(this, "debouncedSearch", null);
3066
- r(this, "currentSearchController", null);
3108
+ a(this, "shadow");
3109
+ a(this, "client", null);
3110
+ a(this, "backdrop", null);
3111
+ a(this, "modal", null);
3112
+ a(this, "inputElement", null);
3113
+ a(this, "resultsContainer", null);
3114
+ a(this, "footerCount", null);
3115
+ a(this, "isOpen", !1);
3116
+ a(this, "results", []);
3117
+ a(this, "activeIndex", -1);
3118
+ a(this, "debouncedSearch", null);
3119
+ a(this, "currentSearchController", null);
3120
+ a(this, "loadingMessageInterval", null);
3121
+ a(this, "loadingMessageIndex", 0);
3067
3122
  // Event handler references for cleanup
3068
- r(this, "handleGlobalKeydown", null);
3069
- r(this, "handleInputChange", null);
3070
- r(this, "handleInputKeydown", null);
3071
- r(this, "handleBackdropClick", null);
3123
+ a(this, "handleGlobalKeydown", null);
3124
+ a(this, "handleInputChange", null);
3125
+ a(this, "handleInputKeydown", null);
3126
+ a(this, "handleBackdropClick", null);
3072
3127
  // Scroll lock state
3073
- r(this, "savedBodyStyles", null);
3074
- r(this, "savedHtmlOverflow", null);
3128
+ a(this, "savedBodyStyles", null);
3129
+ a(this, "savedHtmlOverflow", null);
3075
3130
  this.shadow = this.attachShadow({ mode: "open" });
3076
3131
  }
3077
3132
  static get observedAttributes() {
@@ -3088,7 +3143,7 @@ class Y extends HTMLElement {
3088
3143
  ];
3089
3144
  }
3090
3145
  connectedCallback() {
3091
- this.initializeClient(), this.render(), this.attachGlobalKeyboardShortcut(), this.dispatchEvent(m("ready", void 0));
3146
+ this.initializeClient(), this.render(), this.attachGlobalKeyboardShortcut(), this.dispatchEvent(g("ready", void 0));
3092
3147
  }
3093
3148
  disconnectedCallback() {
3094
3149
  this.cleanup();
@@ -3098,15 +3153,15 @@ class Y extends HTMLElement {
3098
3153
  }
3099
3154
  getProps() {
3100
3155
  return {
3101
- apiUrl: u(this.getAttribute("api-url"), "http://localhost:3000"),
3102
- placeholder: u(this.getAttribute("placeholder"), "Search..."),
3156
+ apiUrl: p(this.getAttribute("api-url"), "http://localhost:3000"),
3157
+ placeholder: p(this.getAttribute("placeholder"), "Search..."),
3103
3158
  maxResults: f(this.getAttribute("max-results"), 10),
3104
3159
  debounceMs: f(this.getAttribute("debounce-ms"), 300),
3105
- theme: u(this.getAttribute("theme"), "auto"),
3106
- shortcut: u(this.getAttribute("shortcut"), "k"),
3160
+ theme: p(this.getAttribute("theme"), "auto"),
3161
+ shortcut: p(this.getAttribute("shortcut"), "k"),
3107
3162
  useMetaKey: this.getAttribute("use-meta-key") !== "false",
3108
- hideBranding: v(this.getAttribute("hide-branding"), !1),
3109
- showUrl: v(this.getAttribute("show-url"), !1)
3163
+ hideBranding: m(this.getAttribute("hide-branding"), !1),
3164
+ showUrl: m(this.getAttribute("show-url"), !1)
3110
3165
  };
3111
3166
  }
3112
3167
  initializeClient() {
@@ -3123,14 +3178,14 @@ class Y extends HTMLElement {
3123
3178
  }
3124
3179
  render() {
3125
3180
  const e = this.getProps(), t = (c) => this.performSearch(c);
3126
- this.debouncedSearch = T(
3181
+ this.debouncedSearch = A(
3127
3182
  t,
3128
3183
  e.debounceMs || 300
3129
3184
  );
3130
3185
  const s = document.createElement("style");
3131
3186
  s.textContent = `${x}
3132
- ${G}`;
3133
- const a = e.hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = document.createElement("div");
3187
+ ${Y}`;
3188
+ const r = e.hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = document.createElement("div");
3134
3189
  n.innerHTML = `
3135
3190
  <div class="modal-backdrop" role="presentation"></div>
3136
3191
  <div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-title">
@@ -3141,7 +3196,7 @@ ${G}`;
3141
3196
  <input
3142
3197
  type="text"
3143
3198
  class="modal-search-input"
3144
- placeholder="${l(e.placeholder || "Search...")}"
3199
+ placeholder="${h(e.placeholder || "Search...")}"
3145
3200
  aria-label="Search"
3146
3201
  aria-autocomplete="list"
3147
3202
  aria-controls="modal-results-list"
@@ -3171,7 +3226,7 @@ ${G}`;
3171
3226
  <span>Close</span>
3172
3227
  </div>
3173
3228
  </div>
3174
- ${a}
3229
+ ${r}
3175
3230
  </div>
3176
3231
  </div>
3177
3232
  `, this.shadow.innerHTML = "", this.shadow.appendChild(s), this.shadow.appendChild(n), this.backdrop = this.shadow.querySelector(".modal-backdrop"), this.modal = this.shadow.querySelector(".modal-container"), this.inputElement = this.shadow.querySelector(".modal-search-input"), this.resultsContainer = this.shadow.querySelector(".modal-results"), this.footerCount = this.shadow.querySelector(".modal-results-count"), this.attachEventListeners();
@@ -3224,7 +3279,7 @@ ${G}`;
3224
3279
  }
3225
3280
  const e = this.results[this.activeIndex];
3226
3281
  this.dispatchEvent(
3227
- m("result-select", {
3282
+ g("result-select", {
3228
3283
  result: e,
3229
3284
  index: this.activeIndex
3230
3285
  })
@@ -3253,32 +3308,32 @@ ${G}`;
3253
3308
  }
3254
3309
  }
3255
3310
  displayResults(e, t) {
3256
- if (!this.resultsContainer) return;
3311
+ if (this.clearLoadingInterval(), !this.resultsContainer) return;
3257
3312
  if (e.length === 0) {
3258
3313
  this.showNoResultsState(t);
3259
3314
  return;
3260
3315
  }
3261
- const s = e.map((a, n) => this.renderResult(a, n)).join("");
3316
+ const s = e.map((r, n) => this.renderResult(r, n)).join("");
3262
3317
  this.resultsContainer.innerHTML = s, this.footerCount && (this.footerCount.textContent = `${e.length} result${e.length === 1 ? "" : "s"}`), this.inputElement && this.inputElement.setAttribute("aria-expanded", "true"), this.attachResultHandlers(), this.updateActiveResult();
3263
3318
  }
3264
3319
  renderResult(e, t) {
3265
- const s = this.getProps(), a = this.renderResultImage(e.image, e.title);
3320
+ const s = this.getProps(), r = this.renderResultImage(e.image, e.title);
3266
3321
  return `
3267
3322
  <a
3268
- href="${e.url ? l(e.url) : "#"}"
3323
+ href="${e.url ? h(e.url) : "#"}"
3269
3324
  class="modal-result-item${t === this.activeIndex ? " active" : ""}"
3270
3325
  role="option"
3271
3326
  id="result-${t}"
3272
3327
  aria-selected="${t === this.activeIndex}"
3273
3328
  tabindex="-1"
3274
3329
  data-index="${t}"
3275
- data-url="${l(e.url || "")}"
3330
+ data-url="${h(e.url || "")}"
3276
3331
  >
3277
- ${a}
3332
+ ${r}
3278
3333
  <div class="modal-result-content">
3279
- <div class="modal-result-title">${l(e.title || "")}</div>
3280
- ${e.description ? `<div class="modal-result-description">${l(e.description)}</div>` : ""}
3281
- ${s.showUrl && e.url ? `<span class="modal-result-url">${l(e.url)}</span>` : ""}
3334
+ <div class="modal-result-title">${h(e.title || "")}</div>
3335
+ ${e.description ? `<div class="modal-result-description">${h(e.description)}</div>` : ""}
3336
+ ${s.showUrl && e.url ? `<span class="modal-result-url">${h(e.url)}</span>` : ""}
3282
3337
  </div>
3283
3338
  </a>
3284
3339
  `;
@@ -3291,8 +3346,8 @@ ${G}`;
3291
3346
  <div class="modal-result-image-placeholder" style="display: none;">${s}</div>
3292
3347
  <img
3293
3348
  class="modal-result-image"
3294
- src="${l(e)}"
3295
- alt="${l(t)}"
3349
+ src="${h(e)}"
3350
+ alt="${h(t)}"
3296
3351
  loading="lazy"
3297
3352
  />
3298
3353
  </div>
@@ -3305,19 +3360,19 @@ ${G}`;
3305
3360
  attachResultHandlers() {
3306
3361
  const e = this.resultsContainer?.querySelectorAll(".modal-result-item");
3307
3362
  if (!e) return;
3308
- e.forEach((s, a) => {
3363
+ e.forEach((s, r) => {
3309
3364
  s.getAttribute("href") === "#" && s.addEventListener("click", (c) => {
3310
3365
  c.preventDefault();
3311
3366
  }), s.addEventListener("mouseenter", () => {
3312
- this.activeIndex = a, this.updateActiveResult();
3367
+ this.activeIndex = r, this.updateActiveResult();
3313
3368
  });
3314
3369
  }), this.resultsContainer?.querySelectorAll(".modal-result-image")?.forEach((s) => {
3315
3370
  s.addEventListener("load", () => {
3316
3371
  s.classList.add("loaded"), s.closest(".modal-result-image-container")?.querySelector(".modal-result-image-loading")?.remove();
3317
3372
  }), s.addEventListener("error", () => {
3318
- const a = s.closest(".modal-result-image-container");
3319
- a?.querySelector(".modal-result-image-loading")?.remove();
3320
- const n = a?.querySelector(
3373
+ const r = s.closest(".modal-result-image-container");
3374
+ r?.querySelector(".modal-result-image-loading")?.remove();
3375
+ const n = r?.querySelector(
3321
3376
  ".modal-result-image-placeholder"
3322
3377
  );
3323
3378
  n && (n.style.display = "flex"), s.style.display = "none";
@@ -3336,32 +3391,42 @@ ${G}`;
3336
3391
  `;
3337
3392
  }
3338
3393
  showEmptyState() {
3339
- this.resultsContainer && (this.resultsContainer.innerHTML = this.renderEmptyState(), this.footerCount && (this.footerCount.textContent = ""), this.inputElement && this.inputElement.setAttribute("aria-expanded", "false"));
3394
+ this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = this.renderEmptyState(), this.footerCount && (this.footerCount.textContent = ""), this.inputElement && this.inputElement.setAttribute("aria-expanded", "false"));
3340
3395
  }
3341
3396
  showLoadingState() {
3342
- this.resultsContainer && (this.resultsContainer.innerHTML = `
3397
+ this.resultsContainer && (this.clearLoadingInterval(), this.loadingMessageIndex = Math.floor(Math.random() * d.length), this.resultsContainer.innerHTML = `
3343
3398
  <div class="modal-loading">
3344
3399
  <div class="loading" aria-label="Loading"></div>
3345
- <div>Searching...</div>
3400
+ <div class="loading-text loading-text-animate">${d[this.loadingMessageIndex]}</div>
3346
3401
  </div>
3347
- `, this.footerCount && (this.footerCount.textContent = "Searching..."));
3402
+ `, this.footerCount && (this.footerCount.textContent = d[this.loadingMessageIndex]), this.startLoadingInterval());
3403
+ }
3404
+ startLoadingInterval() {
3405
+ this.loadingMessageInterval = setInterval(() => {
3406
+ this.loadingMessageIndex = (this.loadingMessageIndex + 1) % d.length;
3407
+ const e = this.resultsContainer?.querySelector(".loading-text");
3408
+ e && (e.classList.remove("loading-text-animate"), e.offsetWidth, e.textContent = d[this.loadingMessageIndex], e.classList.add("loading-text-animate")), this.footerCount && (this.footerCount.textContent = d[this.loadingMessageIndex]);
3409
+ }, 2500);
3410
+ }
3411
+ clearLoadingInterval() {
3412
+ this.loadingMessageInterval && (clearInterval(this.loadingMessageInterval), this.loadingMessageInterval = null);
3348
3413
  }
3349
3414
  showNoResultsState(e) {
3350
- this.resultsContainer && (this.resultsContainer.innerHTML = `
3415
+ this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = `
3351
3416
  <div class="modal-empty">
3352
3417
  <svg class="modal-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
3353
3418
  <circle cx="11" cy="11" r="8"></circle>
3354
3419
  <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
3355
3420
  </svg>
3356
3421
  <div class="modal-empty-title">No results found</div>
3357
- <div class="modal-empty-description">No results for "${l(e)}"</div>
3422
+ <div class="modal-empty-description">No results for "${h(e)}"</div>
3358
3423
  </div>
3359
3424
  `, this.footerCount && (this.footerCount.textContent = "0 results"), this.inputElement && this.inputElement.setAttribute("aria-expanded", "false"));
3360
3425
  }
3361
3426
  showErrorState(e) {
3362
- this.resultsContainer && (this.resultsContainer.innerHTML = `
3427
+ this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = `
3363
3428
  <div class="error">
3364
- <strong>Error:</strong> ${l(e)}
3429
+ <strong>Error:</strong> ${h(e)}
3365
3430
  </div>
3366
3431
  `, this.footerCount && (this.footerCount.textContent = "Error"));
3367
3432
  }
@@ -3384,7 +3449,7 @@ ${G}`;
3384
3449
  document.documentElement.style.overflow = this.savedHtmlOverflow || "", document.body.style.overflow = this.savedBodyStyles.overflow, document.body.style.position = this.savedBodyStyles.position, document.body.style.top = this.savedBodyStyles.top, document.body.style.width = this.savedBodyStyles.width, window.scrollTo(0, e), this.savedBodyStyles = null, this.savedHtmlOverflow = null;
3385
3450
  }
3386
3451
  cleanup() {
3387
- this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.handleGlobalKeydown && (document.removeEventListener("keydown", this.handleGlobalKeydown), this.handleGlobalKeydown = null), this.inputElement && (this.handleInputChange && this.inputElement.removeEventListener("input", this.handleInputChange), this.handleInputKeydown && this.inputElement.removeEventListener("keydown", this.handleInputKeydown)), this.backdrop && this.handleBackdropClick && this.backdrop.removeEventListener("click", this.handleBackdropClick), this.handleInputChange = null, this.handleInputKeydown = null, this.handleBackdropClick = null, this.client && this.client.cancelAllRequests();
3452
+ this.clearLoadingInterval(), this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.handleGlobalKeydown && (document.removeEventListener("keydown", this.handleGlobalKeydown), this.handleGlobalKeydown = null), this.inputElement && (this.handleInputChange && this.inputElement.removeEventListener("input", this.handleInputChange), this.handleInputKeydown && this.inputElement.removeEventListener("keydown", this.handleInputKeydown)), this.backdrop && this.handleBackdropClick && this.backdrop.removeEventListener("click", this.handleBackdropClick), this.handleInputChange = null, this.handleInputKeydown = null, this.handleBackdropClick = null, this.client && this.client.cancelAllRequests();
3388
3453
  }
3389
3454
  // Public API
3390
3455
  /**
@@ -3395,13 +3460,13 @@ ${G}`;
3395
3460
  requestAnimationFrame(() => {
3396
3461
  this.inputElement?.focus();
3397
3462
  });
3398
- }), this.lockBodyScroll(), this.dispatchEvent(m("open", void 0)));
3463
+ }), this.lockBodyScroll(), this.dispatchEvent(g("open", void 0)));
3399
3464
  }
3400
3465
  /**
3401
3466
  * Close the search modal
3402
3467
  */
3403
3468
  close() {
3404
- this.isOpen && (this.isOpen = !1, this.backdrop?.classList.remove("open"), this.modal?.classList.remove("open"), this.inputElement && (this.inputElement.value = ""), this.results = [], this.activeIndex = -1, this.showEmptyState(), this.unlockBodyScroll(), this.dispatchEvent(m("close", void 0)));
3469
+ this.isOpen && (this.isOpen = !1, this.backdrop?.classList.remove("open"), this.modal?.classList.remove("open"), this.inputElement && (this.inputElement.value = ""), this.results = [], this.activeIndex = -1, this.showEmptyState(), this.unlockBodyScroll(), this.dispatchEvent(g("close", void 0)));
3405
3470
  }
3406
3471
  /**
3407
3472
  * Toggle the search modal open/closed
@@ -3428,13 +3493,13 @@ ${G}`;
3428
3493
  return this.isOpen;
3429
3494
  }
3430
3495
  }
3431
- customElements.get(I) || customElements.define(I, Y);
3496
+ customElements.get(T) || customElements.define(T, W);
3432
3497
  export {
3433
3498
  P as AISearchClient,
3434
- O as ChatBubbleSnippet,
3435
- D as ChatPageSnippet,
3499
+ K as ChatBubbleSnippet,
3500
+ U as ChatPageSnippet,
3436
3501
  F as SearchBarSnippet,
3437
- Y as SearchModalSnippet,
3502
+ W as SearchModalSnippet,
3438
3503
  F as default
3439
3504
  };
3440
3505
  //# sourceMappingURL=search-snippet.es.js.map