sagedesk 1.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.
@@ -0,0 +1,1478 @@
1
+ 'use client';
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
+
34
+ // src/core/embedder.ts
35
+ var XENOVA_IDS, _EmbedderRuntime, EmbedderRuntime;
36
+ var init_embedder = __esm({
37
+ "src/core/embedder.ts"() {
38
+ "use strict";
39
+ XENOVA_IDS = {
40
+ "all-MiniLM-L6-v2": "Xenova/all-MiniLM-L6-v2",
41
+ "bge-small-en-v1-5": "Xenova/bge-small-en-v1.5",
42
+ "paraphrase-multilingual-MiniLM-L12-v2": "Xenova/paraphrase-multilingual-MiniLM-L12-v2",
43
+ "all-mpnet-base-v2": "Xenova/all-mpnet-base-v2"
44
+ };
45
+ _EmbedderRuntime = class _EmbedderRuntime {
46
+ constructor() {
47
+ this._ready = false;
48
+ this._failed = false;
49
+ }
50
+ async load(model = "all-MiniLM-L6-v2") {
51
+ if (this._ready) return;
52
+ if (this._failed) throw new Error("EmbedderRuntime previously failed to load");
53
+ if (_EmbedderRuntime._loadingPromise) {
54
+ await _EmbedderRuntime._loadingPromise;
55
+ this._ready = true;
56
+ return;
57
+ }
58
+ const modelId = XENOVA_IDS[model];
59
+ _EmbedderRuntime._loadingPromise = (async () => {
60
+ try {
61
+ const { pipeline } = await import("@huggingface/transformers");
62
+ _EmbedderRuntime._pipelineInstance = await pipeline(
63
+ "feature-extraction",
64
+ modelId,
65
+ { dtype: "q8" }
66
+ );
67
+ } catch (err) {
68
+ _EmbedderRuntime._loadingPromise = null;
69
+ _EmbedderRuntime._pipelineInstance = null;
70
+ throw err;
71
+ }
72
+ })();
73
+ try {
74
+ await _EmbedderRuntime._loadingPromise;
75
+ this._ready = true;
76
+ } catch (err) {
77
+ this._failed = true;
78
+ throw err;
79
+ }
80
+ }
81
+ async embed(text) {
82
+ if (!_EmbedderRuntime._pipelineInstance) {
83
+ await this.load();
84
+ }
85
+ try {
86
+ const output = await _EmbedderRuntime._pipelineInstance(text, {
87
+ pooling: "mean",
88
+ normalize: true
89
+ });
90
+ return output.data;
91
+ } catch (err) {
92
+ throw new Error(`Embedding failed: ${String(err)}`);
93
+ }
94
+ }
95
+ get isReady() {
96
+ return this._ready;
97
+ }
98
+ get hasFailed() {
99
+ return this._failed;
100
+ }
101
+ /** @internal */
102
+ static _reset() {
103
+ _EmbedderRuntime._pipelineInstance = null;
104
+ _EmbedderRuntime._loadingPromise = null;
105
+ }
106
+ };
107
+ // Module-level singleton so the WASM model is loaded at most once per page,
108
+ // regardless of how many widget instances exist.
109
+ _EmbedderRuntime._pipelineInstance = null;
110
+ _EmbedderRuntime._loadingPromise = null;
111
+ EmbedderRuntime = _EmbedderRuntime;
112
+ }
113
+ });
114
+
115
+ // src/core/search.ts
116
+ function dotProduct(a, b) {
117
+ if (a.length !== b.length) {
118
+ throw new Error(`Vector dimension mismatch: query(${a.length}) vs index(${b.length})`);
119
+ }
120
+ let dot = 0;
121
+ for (let i = 0; i < a.length; i++) dot += a[i] * b[i];
122
+ return dot;
123
+ }
124
+ function search(queryVector, index, topK = 3, minScore = 0.42) {
125
+ const results = [];
126
+ for (const chunk of index) {
127
+ const score = dotProduct(queryVector, chunk.vector384);
128
+ if (score < minScore) continue;
129
+ if (results.length < topK) {
130
+ results.push({ chunk, score });
131
+ results.sort((a, b) => b.score - a.score);
132
+ } else if (score > results[topK - 1].score) {
133
+ results[topK - 1] = { chunk, score };
134
+ results.sort((a, b) => b.score - a.score);
135
+ }
136
+ }
137
+ return results;
138
+ }
139
+ function keywordSearch(query, index, topK = 3) {
140
+ const terms = query.toLowerCase().split(/\s+/).filter((w) => w.length > 2).map((w) => w.replace(/[^a-z0-9]/g, ""));
141
+ if (terms.length === 0) return [];
142
+ const results = [];
143
+ for (const chunk of index) {
144
+ const chunkLower = chunk.textLower || chunk.text.toLowerCase();
145
+ const matchCount = terms.filter((t) => chunkLower.includes(t)).length;
146
+ const score = matchCount / terms.length;
147
+ if (score <= 0) continue;
148
+ if (results.length < topK) {
149
+ results.push({ chunk, score });
150
+ results.sort((a, b) => b.score - a.score);
151
+ } else if (score > results[topK - 1].score) {
152
+ results[topK - 1] = { chunk, score };
153
+ results.sort((a, b) => b.score - a.score);
154
+ }
155
+ }
156
+ return results;
157
+ }
158
+ async function loadIndex(url) {
159
+ const res = await fetch(url);
160
+ if (!res.ok) {
161
+ throw new Error(`Failed to fetch index (HTTP ${res.status}): ${url}`);
162
+ }
163
+ const data = await res.json();
164
+ const chunks = Array.isArray(data) ? data : data.chunks;
165
+ for (const chunk of chunks) {
166
+ chunk.textLower = chunk.text.toLowerCase();
167
+ if (Array.isArray(chunk.vector384)) {
168
+ chunk.vector384 = new Float32Array(chunk.vector384);
169
+ }
170
+ if (Array.isArray(chunk.vector768)) {
171
+ chunk.vector768 = new Float32Array(chunk.vector768);
172
+ }
173
+ }
174
+ return chunks;
175
+ }
176
+ var init_search = __esm({
177
+ "src/core/search.ts"() {
178
+ "use strict";
179
+ }
180
+ });
181
+
182
+ // src/core/retriever.ts
183
+ async function fetchIndex(url) {
184
+ try {
185
+ return await loadIndex(url);
186
+ } catch (err) {
187
+ throw new Error(`Could not load knowledge index: ${String(err)}`);
188
+ }
189
+ }
190
+ async function retrieve(text, index, embedder, config) {
191
+ const topK = config?.topK ?? 3;
192
+ const minScore = config?.minScore ?? 0.42;
193
+ if (embedder.isReady) {
194
+ try {
195
+ const vector = await embedder.embed(text);
196
+ const results2 = search(vector, index, topK, minScore);
197
+ return { results: results2, mode: "vector" };
198
+ } catch {
199
+ }
200
+ }
201
+ const results = keywordSearch(text, index, topK);
202
+ return { results, mode: "keyword" };
203
+ }
204
+ var init_retriever = __esm({
205
+ "src/core/retriever.ts"() {
206
+ "use strict";
207
+ init_search();
208
+ }
209
+ });
210
+
211
+ // src/core/renderer.ts
212
+ function buildAnswer(results) {
213
+ if (results.length === 0) return "";
214
+ const seen = /* @__PURE__ */ new Set();
215
+ const parts = [];
216
+ for (const r of results) {
217
+ if (!seen.has(r.chunk.sourceId)) {
218
+ seen.add(r.chunk.sourceId);
219
+ parts.push(r.chunk.text);
220
+ }
221
+ }
222
+ return parts.join("\n\n");
223
+ }
224
+ function extractChips(index, override) {
225
+ if (override && override.length > 0) return override.slice(0, 5);
226
+ const chips = [];
227
+ const seenText = /* @__PURE__ */ new Set();
228
+ const seenSource = /* @__PURE__ */ new Set();
229
+ for (const chunk of index) {
230
+ if (chips.length >= 5) break;
231
+ if (chunk.sourceId) {
232
+ if (seenSource.has(chunk.sourceId)) continue;
233
+ seenSource.add(chunk.sourceId);
234
+ }
235
+ const candidate = chunk.question ?? extractFirstSentence(chunk.text);
236
+ if (candidate && !seenText.has(candidate)) {
237
+ seenText.add(candidate);
238
+ chips.push(candidate);
239
+ }
240
+ }
241
+ return chips;
242
+ }
243
+ function extractFirstSentence(text) {
244
+ const match = text.match(/^[^\n.!?]{10,80}[.!?\n]?/);
245
+ if (!match) return text.slice(0, 60);
246
+ return match[0].trim();
247
+ }
248
+ var init_renderer = __esm({
249
+ "src/core/renderer.ts"() {
250
+ "use strict";
251
+ }
252
+ });
253
+
254
+ // src/core/fallback.ts
255
+ function getFallback(config) {
256
+ const pool = config.fallbackPool && config.fallbackPool.length > 0 ? config.fallbackPool : config.fallback ? [config.fallback] : DEFAULT_POOL;
257
+ const message = pool[rotationIndex % pool.length];
258
+ rotationIndex = (rotationIndex + 1) % pool.length;
259
+ if (config.contactUrl) {
260
+ return `${message} You can reach us at: ${config.contactUrl}`;
261
+ }
262
+ return message;
263
+ }
264
+ var DEFAULT_POOL, rotationIndex;
265
+ var init_fallback = __esm({
266
+ "src/core/fallback.ts"() {
267
+ "use strict";
268
+ DEFAULT_POOL = [
269
+ "That one's a bit outside what I have notes on right now. Feel free to reach out directly and I'll make sure you get a proper answer.",
270
+ "Hmm, I don't have a great answer for that one yet. You're welcome to get in touch and a real person will help.",
271
+ "I want to give you the right answer, not a guess. If you reach out through the contact page someone will follow up with you."
272
+ ];
273
+ rotationIndex = 0;
274
+ }
275
+ });
276
+
277
+ // src/react/useSageDesk.ts
278
+ function reducer(state, action) {
279
+ switch (action.type) {
280
+ case "OPEN":
281
+ return { ...state, isOpen: true };
282
+ case "CLOSE":
283
+ return { ...state, isOpen: false };
284
+ case "ADD_MESSAGE":
285
+ return { ...state, messages: [...state.messages, action.payload] };
286
+ case "SET_TYPING":
287
+ return { ...state, isTyping: action.payload };
288
+ case "SET_ENGINE_STATUS":
289
+ return {
290
+ ...state,
291
+ engineStatus: action.payload.status,
292
+ engineError: action.payload.error ?? null
293
+ };
294
+ case "MARK_SENT":
295
+ return { ...state, hasSentMessage: true };
296
+ default:
297
+ return state;
298
+ }
299
+ }
300
+ function useSageDesk(config) {
301
+ const [state, dispatch] = (0, import_react.useReducer)(reducer, initialState);
302
+ const engineStatusRef = (0, import_react.useRef)("idle");
303
+ engineStatusRef.current = state.engineStatus;
304
+ const indexRef = (0, import_react.useRef)(null);
305
+ const embedderRef = (0, import_react.useRef)(null);
306
+ const engineStartedRef = (0, import_react.useRef)(false);
307
+ const msgCounterRef = (0, import_react.useRef)(0);
308
+ const [chips, setChips] = (0, import_react.useState)([]);
309
+ const makeId = () => `msg-${++msgCounterRef.current}`;
310
+ const addMessage = (0, import_react.useCallback)(
311
+ (msg) => {
312
+ dispatch({
313
+ type: "ADD_MESSAGE",
314
+ payload: { ...msg, id: makeId(), timestamp: /* @__PURE__ */ new Date() }
315
+ });
316
+ },
317
+ []
318
+ );
319
+ const startEngine = (0, import_react.useCallback)(async () => {
320
+ if (engineStartedRef.current) return;
321
+ engineStartedRef.current = true;
322
+ dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "loading-index" } });
323
+ try {
324
+ indexRef.current = await fetchIndex(config.indexUrl);
325
+ } catch (err) {
326
+ console.warn("[sagedesk] Failed to load knowledge index from", config.indexUrl, "-", err);
327
+ dispatch({
328
+ type: "SET_ENGINE_STATUS",
329
+ payload: { status: "error-index", error: String(err) }
330
+ });
331
+ addMessage({
332
+ role: "bot",
333
+ text: "I'm having trouble loading right now. Please try again in a moment."
334
+ });
335
+ return;
336
+ }
337
+ setChips(extractChips(indexRef.current, config.agent.suggestedChips));
338
+ dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "loading-model" } });
339
+ try {
340
+ embedderRef.current = new EmbedderRuntime();
341
+ await embedderRef.current.load(config.agent.model);
342
+ dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "ready" } });
343
+ } catch (err) {
344
+ console.warn("[sagedesk] WASM model failed to load, falling back to keyword search -", err);
345
+ embedderRef.current = new EmbedderRuntime();
346
+ dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "degraded" } });
347
+ }
348
+ }, [config.indexUrl, config.agent.suggestedChips, addMessage]);
349
+ const greetingShownRef = (0, import_react.useRef)(false);
350
+ const open = (0, import_react.useCallback)(() => {
351
+ dispatch({ type: "OPEN" });
352
+ if (!greetingShownRef.current) {
353
+ greetingShownRef.current = true;
354
+ addMessage({
355
+ role: "bot",
356
+ text: config.agent.greeting ?? "Hey, how can I help you today?"
357
+ });
358
+ }
359
+ startEngine();
360
+ }, [config.agent.greeting, addMessage, startEngine]);
361
+ const close = (0, import_react.useCallback)(() => {
362
+ dispatch({ type: "CLOSE" });
363
+ }, []);
364
+ const waitForEngine = (0, import_react.useCallback)(() => {
365
+ return new Promise((resolve) => {
366
+ const check = () => {
367
+ const s = engineStatusRef.current;
368
+ if (s === "ready" || s === "degraded" || s === "error-index" || s === "error-model") {
369
+ resolve();
370
+ } else {
371
+ setTimeout(check, 100);
372
+ }
373
+ };
374
+ check();
375
+ });
376
+ }, []);
377
+ const submit = (0, import_react.useCallback)(
378
+ async (text) => {
379
+ const trimmed = text.trim();
380
+ if (!trimmed) return;
381
+ const typingStart = Date.now();
382
+ dispatch({ type: "MARK_SENT" });
383
+ addMessage({ role: "user", text: trimmed });
384
+ dispatch({ type: "SET_TYPING", payload: true });
385
+ const currentStatus = engineStatusRef.current;
386
+ if (currentStatus !== "ready" && currentStatus !== "degraded" && currentStatus !== "error-index" && currentStatus !== "error-model") {
387
+ await waitForEngine();
388
+ }
389
+ let botText;
390
+ let isFallback = false;
391
+ let mode = "keyword";
392
+ if (!indexRef.current) {
393
+ botText = getFallback(config.agent);
394
+ isFallback = true;
395
+ } else {
396
+ try {
397
+ const res = await retrieve(
398
+ trimmed,
399
+ indexRef.current,
400
+ embedderRef.current,
401
+ config.search
402
+ );
403
+ mode = res.mode;
404
+ if (res.results.length > 0) {
405
+ botText = buildAnswer(res.results);
406
+ } else {
407
+ botText = getFallback(config.agent);
408
+ isFallback = true;
409
+ }
410
+ } catch (err) {
411
+ console.warn("[sagedesk] Query failed, showing fallback -", err);
412
+ botText = getFallback(config.agent);
413
+ isFallback = true;
414
+ }
415
+ }
416
+ const elapsed = Date.now() - typingStart;
417
+ const delayBase = mode === "keyword" || isFallback ? 800 : 3e3;
418
+ const minTypingMs = delayBase + Math.random() * 2e3;
419
+ const remaining = minTypingMs - elapsed;
420
+ if (remaining > 0) await new Promise((r) => setTimeout(r, remaining));
421
+ dispatch({ type: "SET_TYPING", payload: false });
422
+ addMessage({ role: "bot", text: botText, isFallback });
423
+ },
424
+ [addMessage, waitForEngine, config.agent, config.search]
425
+ );
426
+ (0, import_react.useEffect)(() => {
427
+ if (!state.isOpen) return;
428
+ const handler = (e) => {
429
+ if (e.key === "Escape") close();
430
+ };
431
+ document.addEventListener("keydown", handler);
432
+ return () => document.removeEventListener("keydown", handler);
433
+ }, [state.isOpen, close]);
434
+ const activeChips = (0, import_react.useMemo)(() => {
435
+ const askedTexts = new Set(
436
+ state.messages.filter((m) => m.role === "user").map((m) => m.text.toLowerCase().trim())
437
+ );
438
+ return chips.filter((chip) => !askedTexts.has(chip.toLowerCase().trim()));
439
+ }, [chips, state.messages]);
440
+ return { state, chips: activeChips, open, close, submit };
441
+ }
442
+ var import_react, initialState;
443
+ var init_useSageDesk = __esm({
444
+ "src/react/useSageDesk.ts"() {
445
+ "use strict";
446
+ import_react = require("react");
447
+ init_embedder();
448
+ init_retriever();
449
+ init_retriever();
450
+ init_renderer();
451
+ init_fallback();
452
+ initialState = {
453
+ messages: [],
454
+ isOpen: false,
455
+ isTyping: false,
456
+ engineStatus: "idle",
457
+ engineError: null,
458
+ hasSentMessage: false
459
+ };
460
+ }
461
+ });
462
+
463
+ // src/react/SageDeskWidget.tsx
464
+ var SageDeskWidget_exports = {};
465
+ __export(SageDeskWidget_exports, {
466
+ SageDeskWidget: () => SageDeskWidget
467
+ });
468
+ function injectStyles(theme) {
469
+ if (typeof document === "undefined") return;
470
+ const id = `${STYLE_ID}-${theme}`;
471
+ if (document.getElementById(id)) return;
472
+ const style = document.createElement("style");
473
+ style.id = id;
474
+ style.textContent = THEME_CSS[theme];
475
+ document.head.prepend(style);
476
+ }
477
+ function ClassicMessageBubble({ msg, accent }) {
478
+ const isBot = msg.role === "bot";
479
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: isBot ? "flex-start" : "flex-end", gap: "4px" }, children: [
480
+ msg.isFallback && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: "11px", fontWeight: 500, color: "#9b9aa3", margin: 0, padding: "0 4px", fontFamily: "inherit" }, children: "Not sure about that one" }),
481
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
482
+ maxWidth: "82%",
483
+ padding: "10px 14px",
484
+ fontSize: "14px",
485
+ lineHeight: 1.5,
486
+ borderRadius: isBot ? "16px 16px 16px 6px" : "16px 16px 6px 16px",
487
+ background: isBot ? "#fff" : accent,
488
+ color: isBot ? "#1a1a2e" : "#fff",
489
+ border: isBot ? "1px solid rgba(20,20,40,0.06)" : "none",
490
+ boxShadow: isBot ? "0 1px 2px rgba(20,20,40,0.04)" : `0 6px 16px -6px color-mix(in oklab, ${accent} 60%, transparent)`,
491
+ whiteSpace: "pre-wrap",
492
+ wordBreak: "break-word",
493
+ fontFamily: "inherit"
494
+ }, children: msg.text }),
495
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
496
+ fontSize: "11px",
497
+ color: "#a8a8b0",
498
+ marginTop: "2px",
499
+ padding: isBot ? "0 0 0 4px" : "0 4px 0 0",
500
+ fontVariantNumeric: "tabular-nums",
501
+ fontFamily: "inherit"
502
+ }, children: "just now" })
503
+ ] });
504
+ }
505
+ function ClassicTypingIndicator() {
506
+ const dot = { width: 6, height: 6, borderRadius: "50%", background: "#c8c8ce", display: "inline-block" };
507
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "4px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
508
+ padding: "10px 14px",
509
+ borderRadius: "16px 16px 16px 6px",
510
+ background: "#fff",
511
+ border: "1px solid rgba(20,20,40,0.06)",
512
+ boxShadow: "0 1px 2px rgba(20,20,40,0.04)",
513
+ display: "flex",
514
+ alignItems: "center",
515
+ gap: "4px"
516
+ }, children: [
517
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-1" }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-2" }),
519
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-3" })
520
+ ] }) });
521
+ }
522
+ function LightMessageBubble({ msg, accent, agentName }) {
523
+ const isBot = msg.role === "bot";
524
+ if (isBot) {
525
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
527
+ width: 28,
528
+ height: 28,
529
+ borderRadius: "50%",
530
+ background: `linear-gradient(135deg, ${accent}, color-mix(in oklab, ${accent} 60%, #fff))`,
531
+ flexShrink: 0,
532
+ marginTop: "2px"
533
+ } }),
534
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
535
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "baseline", gap: "8px", marginBottom: "4px" }, children: [
536
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "13px", fontWeight: 600, color: "#1a1a2e", fontFamily: "inherit" }, children: agentName }),
537
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "11px", color: "#a8a89e", fontVariantNumeric: "tabular-nums", fontFamily: "inherit" }, children: "just now" })
538
+ ] }),
539
+ msg.isFallback && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: "11px", color: "#9b9aa3", margin: "0 0 4px", fontFamily: "inherit" }, children: "Not sure about that one" }),
540
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "14px", lineHeight: 1.55, color: "#2a2a36", fontFamily: "inherit", whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: msg.text })
541
+ ] })
542
+ ] });
543
+ }
544
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", justifyContent: "flex-end" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
545
+ maxWidth: "78%",
546
+ padding: "11px 15px",
547
+ fontSize: "14px",
548
+ lineHeight: 1.5,
549
+ borderRadius: "16px 16px 4px 16px",
550
+ background: `color-mix(in oklab, ${accent} 10%, white)`,
551
+ color: accent,
552
+ border: `1px solid color-mix(in oklab, ${accent} 22%, transparent)`,
553
+ fontWeight: 500,
554
+ whiteSpace: "pre-wrap",
555
+ wordBreak: "break-word",
556
+ fontFamily: "inherit"
557
+ }, children: msg.text }) });
558
+ }
559
+ function LightTypingIndicator({ accent }) {
560
+ const dot = { width: 6, height: 6, borderRadius: "50%", background: "#c4c4be", display: "inline-block" };
561
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
562
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
563
+ width: 28,
564
+ height: 28,
565
+ borderRadius: "50%",
566
+ background: `linear-gradient(135deg, ${accent}, color-mix(in oklab, ${accent} 60%, #fff))`,
567
+ flexShrink: 0,
568
+ marginTop: "2px"
569
+ } }),
570
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
571
+ padding: "10px 14px",
572
+ borderRadius: "16px 16px 16px 4px",
573
+ background: "#fff",
574
+ border: "1px solid rgba(20,20,40,0.07)",
575
+ boxShadow: "0 1px 2px rgba(20,20,40,0.04)",
576
+ display: "inline-flex",
577
+ alignItems: "center",
578
+ gap: "4px"
579
+ }, children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-1" }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-2" }),
582
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-3" })
583
+ ] })
584
+ ] });
585
+ }
586
+ function DarkMessageBubble({ msg, accent }) {
587
+ const isBot = msg.role === "bot";
588
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
589
+ maxWidth: "85%",
590
+ padding: "12px 14px",
591
+ fontSize: "14px",
592
+ lineHeight: isBot ? 1.6 : 1.5,
593
+ borderRadius: isBot ? "14px 14px 14px 6px" : "14px 14px 6px 14px",
594
+ background: isBot ? "rgba(255,255,255,0.05)" : `linear-gradient(135deg, ${accent}, color-mix(in oklab, ${accent} 75%, #1a1340))`,
595
+ border: isBot ? "1px solid rgba(255,255,255,0.06)" : "none",
596
+ color: isBot ? "rgba(255,255,255,0.92)" : "#fff",
597
+ alignSelf: isBot ? "flex-start" : "flex-end",
598
+ boxShadow: isBot ? "none" : `0 8px 20px -8px color-mix(in oklab, ${accent} 70%, transparent)`,
599
+ whiteSpace: "pre-wrap",
600
+ wordBreak: "break-word",
601
+ fontFamily: "inherit"
602
+ }, children: [
603
+ msg.isFallback && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "11px", color: "rgba(255,255,255,0.5)", display: "block", marginBottom: "4px" }, children: "Not sure about that one" }),
604
+ msg.text
605
+ ] });
606
+ }
607
+ function DarkTypingIndicator() {
608
+ const dot = { width: 6, height: 6, borderRadius: "50%", background: "rgba(255,255,255,0.4)", display: "inline-block" };
609
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
610
+ maxWidth: "85%",
611
+ padding: "12px 14px",
612
+ borderRadius: "14px 14px 14px 6px",
613
+ background: "rgba(255,255,255,0.05)",
614
+ border: "1px solid rgba(255,255,255,0.06)",
615
+ alignSelf: "flex-start",
616
+ display: "flex",
617
+ alignItems: "center",
618
+ gap: "4px"
619
+ }, children: [
620
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-1" }),
621
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-2" }),
622
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-3" })
623
+ ] });
624
+ }
625
+ function renderClassic(p) {
626
+ const {
627
+ agent,
628
+ state,
629
+ chips,
630
+ accent,
631
+ isLeft,
632
+ inputValue,
633
+ setInputValue,
634
+ handleClose,
635
+ handleSubmit,
636
+ handleKeyDown,
637
+ isClosing,
638
+ panelClass,
639
+ showChips,
640
+ showPoweredBy,
641
+ threadRef,
642
+ inputRef,
643
+ triggerRef,
644
+ open,
645
+ submit
646
+ } = p;
647
+ const side = isLeft ? "left" : "right";
648
+ const triggerStyle = {
649
+ position: "fixed",
650
+ bottom: "28px",
651
+ [side]: "28px",
652
+ width: "56px",
653
+ height: "56px",
654
+ borderRadius: "50%",
655
+ background: `linear-gradient(135deg, ${accent} 0%, color-mix(in oklab, ${accent} 78%, #1a1340) 100%)`,
656
+ border: "none",
657
+ color: "#fff",
658
+ cursor: "pointer",
659
+ display: "grid",
660
+ placeItems: "center",
661
+ zIndex: 9999,
662
+ padding: 0,
663
+ transition: "transform 150ms ease",
664
+ boxShadow: `0 14px 28px -6px color-mix(in oklab, ${accent} 55%, transparent), 0 4px 10px rgba(40,30,90,0.15)`
665
+ };
666
+ const panelStyle = {
667
+ position: "fixed",
668
+ bottom: "96px",
669
+ [side]: "28px",
670
+ width: "380px",
671
+ height: "580px",
672
+ maxHeight: "580px",
673
+ borderRadius: "20px",
674
+ background: "#ffffff",
675
+ boxShadow: "0 1px 0 rgba(20,20,40,0.04), 0 24px 48px -16px rgba(40,30,90,0.22), 0 4px 14px rgba(40,30,90,0.08)",
676
+ border: "1px solid rgba(20,20,40,0.04)",
677
+ display: "flex",
678
+ flexDirection: "column",
679
+ overflow: "hidden",
680
+ zIndex: 9999,
681
+ transformOrigin: isLeft ? "bottom left" : "bottom right"
682
+ };
683
+ const headerGrad = `linear-gradient(135deg, ${accent} 0%, color-mix(in oklab, ${accent} 78%, #1a1340) 100%)`;
684
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
685
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
686
+ "button",
687
+ {
688
+ ref: triggerRef,
689
+ style: triggerStyle,
690
+ className: "sd-r-trigger",
691
+ onClick: state.isOpen ? handleClose : open,
692
+ "aria-label": "Open support chat",
693
+ "aria-expanded": state.isOpen,
694
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconChat, { size: 22 })
695
+ }
696
+ ),
697
+ (state.isOpen || isClosing) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelStyle, className: `sd-r-panel ${panelClass}`, role: "dialog", "aria-label": agent.name, children: [
698
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "18px 20px", background: headerGrad, color: "#fff", display: "flex", alignItems: "center", gap: "12px", flexShrink: 0 }, children: [
699
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative", width: 40, height: 40 }, children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: 40, height: 40, borderRadius: "50%", background: "rgba(255,255,255,0.18)", display: "grid", placeItems: "center", overflow: "hidden" }, children: agent.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: agent.avatarUrl, alt: agent.name, style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconPerson, { size: 20 }) }),
701
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", right: -1, bottom: -1, width: 12, height: 12, borderRadius: "50%", background: "#22c55e", boxShadow: `0 0 0 2.5px ${accent}` } })
702
+ ] }),
703
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
704
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "15px", fontWeight: 600, letterSpacing: "-0.01em" }, children: agent.name }),
705
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: "12px", opacity: 0.85, display: "flex", alignItems: "center", gap: "6px", marginTop: "3px" }, children: [
706
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 6, height: 6, borderRadius: "50%", background: "#4ade80", boxShadow: "0 0 0 2px rgba(74,222,128,0.25)" } }),
707
+ "Typically replies in under a minute"
708
+ ] })
709
+ ] }),
710
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "sd-r-close-btn", onClick: handleClose, "aria-label": "Close chat", style: {
711
+ background: "rgba(255,255,255,0.14)",
712
+ border: "none",
713
+ color: "#fff",
714
+ width: 30,
715
+ height: 30,
716
+ borderRadius: 8,
717
+ cursor: "pointer",
718
+ display: "grid",
719
+ placeItems: "center",
720
+ padding: 0,
721
+ transition: "background 120ms"
722
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconClose, { size: 14 }) })
723
+ ] }),
724
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: threadRef, role: "log", "aria-live": "polite", "aria-label": "Chat messages", style: {
725
+ flex: 1,
726
+ padding: "22px 18px 18px",
727
+ overflowY: "auto",
728
+ background: "#fbfbfa",
729
+ display: "flex",
730
+ flexDirection: "column",
731
+ gap: "18px",
732
+ scrollbarWidth: "thin",
733
+ overscrollBehavior: "contain"
734
+ }, children: [
735
+ state.messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClassicMessageBubble, { msg, accent }, msg.id)),
736
+ state.isTyping && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClassicTypingIndicator, {})
737
+ ] }),
738
+ showChips && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: state.hasSentMessage ? "0 0 16px" : "0 18px 16px", background: "#fbfbfa", flexShrink: 0 }, children: [
739
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
740
+ fontSize: "11px",
741
+ color: "#9b9aa3",
742
+ letterSpacing: "0.06em",
743
+ textTransform: "uppercase",
744
+ fontWeight: 500,
745
+ paddingLeft: state.hasSentMessage ? 18 : 4,
746
+ marginBottom: "6px"
747
+ }, children: "Suggested" }),
748
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: state.hasSentMessage ? "sd-r-scrollable" : "", style: {
749
+ display: "flex",
750
+ gap: "6px",
751
+ flexWrap: state.hasSentMessage ? "nowrap" : "wrap",
752
+ padding: state.hasSentMessage ? "0 18px" : 0
753
+ }, children: chips.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "sd-r-chip", onClick: () => {
754
+ setInputValue("");
755
+ submit(chip);
756
+ }, style: {
757
+ fontSize: "12.5px",
758
+ padding: "7px 12px",
759
+ borderRadius: "999px",
760
+ background: "#fff",
761
+ border: `1px solid color-mix(in oklab, ${accent} 24%, transparent)`,
762
+ color: accent,
763
+ cursor: "pointer",
764
+ fontWeight: 500,
765
+ fontFamily: "inherit",
766
+ letterSpacing: "-0.005em"
767
+ }, children: chip }, chip)) })
768
+ ] }),
769
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "14px 14px 16px", borderTop: "1px solid rgba(20,20,40,0.06)", background: "#fff", flexShrink: 0 }, children: [
770
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
771
+ display: "flex",
772
+ alignItems: "center",
773
+ gap: "6px",
774
+ background: "#f5f4f0",
775
+ borderRadius: "12px",
776
+ padding: "5px 6px 5px 14px",
777
+ border: `1px solid ${inputValue ? `color-mix(in oklab, ${accent} 30%, transparent)` : "transparent"}`,
778
+ boxShadow: inputValue ? `0 0 0 4px color-mix(in oklab, ${accent} 12%, transparent)` : "none",
779
+ transition: "border-color .15s, box-shadow .15s"
780
+ }, children: [
781
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
782
+ "input",
783
+ {
784
+ ref: inputRef,
785
+ value: inputValue,
786
+ onChange: (e) => setInputValue(e.target.value),
787
+ onKeyDown: handleKeyDown,
788
+ placeholder: "Write a message\u2026",
789
+ className: "sd-r-input",
790
+ "aria-label": "Type your question",
791
+ autoComplete: "off",
792
+ style: { flex: 1, background: "transparent", border: "none", outline: "none", fontSize: "14px", padding: "8px 0", fontFamily: "inherit", color: "#1a1a2e" }
793
+ }
794
+ ),
795
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "sd-r-send", onClick: handleSubmit, "aria-label": "Send message", style: {
796
+ width: 32,
797
+ height: 32,
798
+ borderRadius: 8,
799
+ padding: 0,
800
+ background: inputValue ? accent : `color-mix(in oklab, ${accent} 22%, #e5e3dc)`,
801
+ border: "none",
802
+ color: "#fff",
803
+ cursor: "pointer",
804
+ display: "grid",
805
+ placeItems: "center",
806
+ transition: "background .15s"
807
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSend, { size: 14 }) })
808
+ ] }),
809
+ showPoweredBy && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: "10px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PoweredBy, {}) })
810
+ ] })
811
+ ] })
812
+ ] });
813
+ }
814
+ function renderLight(p) {
815
+ const {
816
+ agent,
817
+ state,
818
+ chips,
819
+ accent,
820
+ isLeft,
821
+ inputValue,
822
+ setInputValue,
823
+ handleClose,
824
+ handleSubmit,
825
+ handleKeyDown,
826
+ isClosing,
827
+ panelClass,
828
+ showChips,
829
+ showPoweredBy,
830
+ threadRef,
831
+ inputRef,
832
+ triggerRef,
833
+ open,
834
+ submit
835
+ } = p;
836
+ const side = isLeft ? "left" : "right";
837
+ const triggerStyle = {
838
+ position: "fixed",
839
+ bottom: "28px",
840
+ [side]: "28px",
841
+ height: "52px",
842
+ padding: "0 8px 0 20px",
843
+ borderRadius: "999px",
844
+ background: "#fdfcf9",
845
+ border: "1px solid rgba(20,20,40,0.08)",
846
+ cursor: "pointer",
847
+ display: "flex",
848
+ alignItems: "center",
849
+ gap: "14px",
850
+ boxShadow: "0 12px 26px -8px rgba(40,30,90,0.18), 0 2px 8px rgba(40,30,90,0.06)",
851
+ zIndex: 9999,
852
+ fontFamily: "inherit",
853
+ transition: "box-shadow 150ms ease"
854
+ };
855
+ const panelStyle = {
856
+ position: "fixed",
857
+ bottom: "92px",
858
+ [side]: "28px",
859
+ width: "400px",
860
+ height: "580px",
861
+ maxHeight: "580px",
862
+ borderRadius: "22px",
863
+ background: "#fdfcf9",
864
+ boxShadow: "0 1px 0 rgba(20,20,40,0.04), 0 30px 60px -20px rgba(40,30,90,0.18), 0 6px 16px rgba(40,30,90,0.06)",
865
+ border: "1px solid rgba(20,20,40,0.05)",
866
+ display: "flex",
867
+ flexDirection: "column",
868
+ overflow: "hidden",
869
+ zIndex: 9999,
870
+ transformOrigin: isLeft ? "bottom left" : "bottom right"
871
+ };
872
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
874
+ "button",
875
+ {
876
+ ref: triggerRef,
877
+ style: triggerStyle,
878
+ className: "sd-r-trigger-light",
879
+ onClick: state.isOpen ? handleClose : open,
880
+ "aria-label": "Open support chat",
881
+ "aria-expanded": state.isOpen,
882
+ children: [
883
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { display: "flex", flexDirection: "column", alignItems: "flex-start", lineHeight: 1.2 }, children: [
884
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "14px", fontWeight: 600, color: "#1a1a2e" }, children: "Chat with us" }),
885
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "11px", color: "#9b9aa3", marginTop: "2px" }, children: "We typically reply in 1m" })
886
+ ] }),
887
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: "36px", height: "36px", borderRadius: "50%", background: accent, color: "#fff", display: "grid", placeItems: "center", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconChat, { size: 18 }) })
888
+ ]
889
+ }
890
+ ),
891
+ (state.isOpen || isClosing) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelStyle, className: `sd-r-panel ${panelClass}`, role: "dialog", "aria-label": agent.name, children: [
892
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "18px 20px 14px", borderBottom: "1px solid rgba(20,20,40,0.05)", display: "flex", alignItems: "center", gap: "12px", background: "#fdfcf9", flexShrink: 0 }, children: [
893
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
894
+ width: 36,
895
+ height: 36,
896
+ borderRadius: "50%",
897
+ flexShrink: 0,
898
+ background: `linear-gradient(135deg, ${accent}, color-mix(in oklab, ${accent} 55%, #fff))`,
899
+ display: "grid",
900
+ placeItems: "center",
901
+ overflow: "hidden",
902
+ color: "#fff"
903
+ }, children: agent.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: agent.avatarUrl, alt: agent.name, style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconPerson, { size: 16 }) }),
904
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
905
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "14.5px", fontWeight: 600, color: "#1a1a2e", letterSpacing: "-0.01em" }, children: agent.name }),
906
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: "12px", color: "#7a7a82", display: "flex", alignItems: "center", gap: "6px", marginTop: "2px" }, children: [
907
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 6, height: 6, borderRadius: "50%", background: "#22c55e" } }),
908
+ "Online \xB7 replies in under a minute"
909
+ ] })
910
+ ] }),
911
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: handleClose, "aria-label": "Close chat", style: {
912
+ background: "transparent",
913
+ border: "none",
914
+ color: "#9b9aa3",
915
+ width: 30,
916
+ height: 30,
917
+ borderRadius: 8,
918
+ cursor: "pointer",
919
+ display: "grid",
920
+ placeItems: "center",
921
+ padding: 0
922
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconClose, { size: 16 }) })
923
+ ] }),
924
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: threadRef, role: "log", "aria-live": "polite", "aria-label": "Chat messages", style: {
925
+ flex: 1,
926
+ padding: "22px 20px 16px",
927
+ overflowY: "auto",
928
+ display: "flex",
929
+ flexDirection: "column",
930
+ gap: "22px",
931
+ scrollbarWidth: "thin",
932
+ overscrollBehavior: "contain"
933
+ }, children: [
934
+ state.messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LightMessageBubble, { msg, accent, agentName: agent.name }, msg.id)),
935
+ state.isTyping && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LightTypingIndicator, { accent })
936
+ ] }),
937
+ showChips && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: state.hasSentMessage ? "sd-r-scrollable" : "", style: {
938
+ padding: "0 20px 14px",
939
+ display: "flex",
940
+ flexWrap: state.hasSentMessage ? "nowrap" : "wrap",
941
+ gap: "6px",
942
+ flexShrink: 0
943
+ }, children: chips.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "sd-r-chip-light", onClick: () => {
944
+ setInputValue("");
945
+ submit(chip);
946
+ }, style: {
947
+ fontSize: "12px",
948
+ padding: "5px 10px",
949
+ borderRadius: "6px",
950
+ background: "#f4f3ee",
951
+ border: "none",
952
+ color: "#5a5a64",
953
+ cursor: "pointer",
954
+ fontFamily: "inherit",
955
+ fontWeight: 500
956
+ }, children: chip }, chip)) }),
957
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "14px", borderTop: "1px solid rgba(20,20,40,0.05)", background: "#fdfcf9", flexShrink: 0 }, children: [
958
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
959
+ background: "#fff",
960
+ border: `1px solid ${inputValue ? `color-mix(in oklab, ${accent} 40%, transparent)` : "rgba(20,20,40,0.1)"}`,
961
+ borderRadius: "14px",
962
+ padding: "10px 12px",
963
+ transition: "border-color .15s, box-shadow .15s",
964
+ boxShadow: inputValue ? `0 0 0 4px color-mix(in oklab, ${accent} 12%, transparent)` : "none"
965
+ }, children: [
966
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
967
+ "input",
968
+ {
969
+ ref: inputRef,
970
+ value: inputValue,
971
+ onChange: (e) => setInputValue(e.target.value),
972
+ onKeyDown: handleKeyDown,
973
+ placeholder: "Write a message\u2026",
974
+ className: "sd-r-input",
975
+ "aria-label": "Type your question",
976
+ autoComplete: "off",
977
+ style: { width: "100%", background: "transparent", border: "none", outline: "none", fontSize: "14px", fontFamily: "inherit", color: "#1a1a2e" }
978
+ }
979
+ ),
980
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", marginTop: "8px", gap: "6px" }, children: [
981
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1 } }),
982
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "sd-r-send", onClick: handleSubmit, "aria-label": "Send message", style: {
983
+ width: 28,
984
+ height: 28,
985
+ borderRadius: 7,
986
+ padding: 0,
987
+ background: inputValue ? accent : "#e8e7e0",
988
+ color: inputValue ? "#fff" : "#a8a89e",
989
+ border: "none",
990
+ cursor: "pointer",
991
+ display: "grid",
992
+ placeItems: "center",
993
+ transition: "background .15s"
994
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSend, { size: 13 }) })
995
+ ] })
996
+ ] }),
997
+ showPoweredBy && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: "10px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PoweredBy, {}) })
998
+ ] })
999
+ ] })
1000
+ ] });
1001
+ }
1002
+ function renderDark(p) {
1003
+ const {
1004
+ agent,
1005
+ state,
1006
+ chips,
1007
+ accent,
1008
+ isLeft,
1009
+ inputValue,
1010
+ setInputValue,
1011
+ handleClose,
1012
+ handleSubmit,
1013
+ handleKeyDown,
1014
+ isClosing,
1015
+ panelClass,
1016
+ showChips,
1017
+ showPoweredBy,
1018
+ threadRef,
1019
+ inputRef,
1020
+ triggerRef,
1021
+ open,
1022
+ submit
1023
+ } = p;
1024
+ const side = isLeft ? "left" : "right";
1025
+ const triggerStyle = {
1026
+ position: "fixed",
1027
+ bottom: "28px",
1028
+ [side]: "28px",
1029
+ width: "60px",
1030
+ height: "60px",
1031
+ borderRadius: "50%",
1032
+ background: `linear-gradient(135deg, color-mix(in oklab, ${accent} 70%, #1a1340), #1a1a2e)`,
1033
+ border: "1px solid rgba(255,255,255,0.12)",
1034
+ color: "#fff",
1035
+ cursor: "pointer",
1036
+ display: "grid",
1037
+ placeItems: "center",
1038
+ zIndex: 9999,
1039
+ padding: 0,
1040
+ transition: "transform 150ms ease",
1041
+ boxShadow: "0 16px 32px -8px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1)"
1042
+ };
1043
+ const glowStyle = {
1044
+ position: "fixed",
1045
+ bottom: "18px",
1046
+ [side]: "18px",
1047
+ width: "80px",
1048
+ height: "80px",
1049
+ borderRadius: "50%",
1050
+ background: `radial-gradient(circle, color-mix(in oklab, ${accent} 50%, transparent), transparent 70%)`,
1051
+ filter: "blur(10px)",
1052
+ pointerEvents: "none",
1053
+ zIndex: 9998
1054
+ };
1055
+ const panelStyle = {
1056
+ position: "fixed",
1057
+ bottom: "100px",
1058
+ [side]: "28px",
1059
+ width: "380px",
1060
+ height: "580px",
1061
+ maxHeight: "580px",
1062
+ borderRadius: "22px",
1063
+ background: "rgba(18, 16, 32, 0.86)",
1064
+ backdropFilter: "blur(40px) saturate(180%)",
1065
+ WebkitBackdropFilter: "blur(40px) saturate(180%)",
1066
+ boxShadow: "0 30px 60px -20px rgba(0,0,0,0.4), 0 4px 14px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.06)",
1067
+ border: "1px solid rgba(255,255,255,0.08)",
1068
+ display: "flex",
1069
+ flexDirection: "column",
1070
+ overflow: "hidden",
1071
+ zIndex: 9999,
1072
+ color: "#fff",
1073
+ transformOrigin: isLeft ? "bottom left" : "bottom right"
1074
+ };
1075
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1076
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: glowStyle, "aria-hidden": "true" }),
1077
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1078
+ "button",
1079
+ {
1080
+ ref: triggerRef,
1081
+ style: triggerStyle,
1082
+ className: "sd-r-trigger",
1083
+ onClick: state.isOpen ? handleClose : open,
1084
+ "aria-label": "Open support chat",
1085
+ "aria-expanded": state.isOpen,
1086
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconBot, { size: 22 })
1087
+ }
1088
+ ),
1089
+ (state.isOpen || isClosing) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelStyle, className: `sd-r-panel ${panelClass}`, role: "dialog", "aria-label": agent.name, children: [
1090
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "aria-hidden": "true", style: {
1091
+ position: "absolute",
1092
+ top: 0,
1093
+ left: 0,
1094
+ right: 0,
1095
+ height: 200,
1096
+ pointerEvents: "none",
1097
+ background: `radial-gradient(ellipse 80% 100% at 50% 0%, color-mix(in oklab, ${accent} 40%, transparent) 0%, transparent 70%)`
1098
+ } }),
1099
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "20px 20px 16px", display: "flex", alignItems: "center", gap: "12px", position: "relative", zIndex: 1, flexShrink: 0 }, children: [
1100
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative" }, children: [
1101
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
1102
+ width: 38,
1103
+ height: 38,
1104
+ borderRadius: "50%",
1105
+ display: "grid",
1106
+ placeItems: "center",
1107
+ overflow: "hidden",
1108
+ background: `linear-gradient(135deg, ${accent}, color-mix(in oklab, ${accent} 50%, #fff))`,
1109
+ boxShadow: `0 0 24px color-mix(in oklab, ${accent} 50%, transparent)`
1110
+ }, children: agent.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: agent.avatarUrl, alt: agent.name, style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconBot, { size: 16 }) }),
1111
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", right: -2, bottom: -2, width: 12, height: 12, borderRadius: "50%", background: "#22c55e", boxShadow: "0 0 0 2.5px rgba(18,16,32,1)" } })
1112
+ ] }),
1113
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1 }, children: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "15px", fontWeight: 600, letterSpacing: "-0.01em" }, children: agent.name }),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: "12px", color: "rgba(255,255,255,0.55)", marginTop: "3px", display: "flex", alignItems: "center", gap: "6px" }, children: [
1116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 5, height: 5, borderRadius: "50%", background: "#4ade80", boxShadow: "0 0 6px #4ade80" } }),
1117
+ "Trained on this site \xB7 always on"
1118
+ ] })
1119
+ ] }),
1120
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: handleClose, "aria-label": "Close chat", style: {
1121
+ background: "rgba(255,255,255,0.06)",
1122
+ border: "1px solid rgba(255,255,255,0.08)",
1123
+ color: "rgba(255,255,255,0.7)",
1124
+ width: 30,
1125
+ height: 30,
1126
+ borderRadius: 8,
1127
+ cursor: "pointer",
1128
+ display: "grid",
1129
+ placeItems: "center",
1130
+ padding: 0
1131
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconClose, { size: 14 }) })
1132
+ ] }),
1133
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: threadRef, role: "log", "aria-live": "polite", "aria-label": "Chat messages", style: {
1134
+ flex: 1,
1135
+ padding: "8px 20px 16px",
1136
+ overflowY: "auto",
1137
+ display: "flex",
1138
+ flexDirection: "column",
1139
+ gap: "14px",
1140
+ position: "relative",
1141
+ zIndex: 1,
1142
+ scrollbarWidth: "thin",
1143
+ overscrollBehavior: "contain"
1144
+ }, children: [
1145
+ state.messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DarkMessageBubble, { msg, accent }, msg.id)),
1146
+ state.isTyping && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DarkTypingIndicator, {})
1147
+ ] }),
1148
+ showChips && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: state.hasSentMessage ? "0 0 16px" : "0 20px 16px", position: "relative", zIndex: 1, flexShrink: 0 }, children: [
1149
+ !state.hasSentMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "11px", color: "rgba(255,255,255,0.4)", letterSpacing: "0.08em", textTransform: "uppercase", fontWeight: 500, marginBottom: "8px" }, children: "Try asking" }),
1150
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: state.hasSentMessage ? "sd-r-scrollable" : "", style: {
1151
+ display: "flex",
1152
+ flexDirection: state.hasSentMessage ? "row" : "column",
1153
+ gap: "6px",
1154
+ padding: state.hasSentMessage ? "0 20px" : 0
1155
+ }, children: chips.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "sd-r-prompt", onClick: () => {
1156
+ setInputValue("");
1157
+ submit(chip);
1158
+ }, style: {
1159
+ textAlign: "left",
1160
+ padding: "10px 14px",
1161
+ borderRadius: "10px",
1162
+ background: "rgba(255,255,255,0.04)",
1163
+ border: "1px solid rgba(255,255,255,0.07)",
1164
+ color: "rgba(255,255,255,0.85)",
1165
+ cursor: "pointer",
1166
+ fontSize: "13px",
1167
+ fontFamily: "inherit",
1168
+ display: "flex",
1169
+ alignItems: "center",
1170
+ gap: "8px",
1171
+ transition: "background .12s",
1172
+ width: state.hasSentMessage ? "auto" : "100%",
1173
+ whiteSpace: state.hasSentMessage ? "nowrap" : "normal"
1174
+ }, children: [
1175
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 6l6 6-6 6", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) }),
1176
+ chip
1177
+ ] }, chip)) })
1178
+ ] }),
1179
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "14px", borderTop: "1px solid rgba(255,255,255,0.06)", position: "relative", zIndex: 1, flexShrink: 0 }, children: [
1180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
1181
+ display: "flex",
1182
+ alignItems: "center",
1183
+ gap: "8px",
1184
+ background: "rgba(255,255,255,0.05)",
1185
+ border: `1px solid ${inputValue ? `color-mix(in oklab, ${accent} 60%, transparent)` : "rgba(255,255,255,0.08)"}`,
1186
+ borderRadius: "12px",
1187
+ padding: "4px 4px 4px 14px",
1188
+ transition: "border-color .15s"
1189
+ }, children: [
1190
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1191
+ "input",
1192
+ {
1193
+ ref: inputRef,
1194
+ value: inputValue,
1195
+ onChange: (e) => setInputValue(e.target.value),
1196
+ onKeyDown: handleKeyDown,
1197
+ placeholder: "Write a message\u2026",
1198
+ className: "sd-r-input",
1199
+ "aria-label": "Type your question",
1200
+ autoComplete: "off",
1201
+ style: { flex: 1, background: "transparent", border: "none", outline: "none", fontSize: "14px", padding: "9px 0", fontFamily: "inherit", color: "#fff" }
1202
+ }
1203
+ ),
1204
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "sd-r-send", onClick: handleSubmit, "aria-label": "Send message", style: {
1205
+ width: 32,
1206
+ height: 32,
1207
+ borderRadius: 9,
1208
+ padding: 0,
1209
+ border: "none",
1210
+ cursor: "pointer",
1211
+ background: inputValue ? `linear-gradient(135deg, ${accent}, color-mix(in oklab, ${accent} 60%, #fff))` : "rgba(255,255,255,0.08)",
1212
+ color: inputValue ? "#fff" : "rgba(255,255,255,0.4)",
1213
+ display: "grid",
1214
+ placeItems: "center",
1215
+ transition: "background .15s",
1216
+ boxShadow: inputValue ? `0 4px 12px -2px color-mix(in oklab, ${accent} 60%, transparent)` : "none"
1217
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSend, { size: 14 }) })
1218
+ ] }),
1219
+ showPoweredBy && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: "10px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PoweredBy, { dark: true }) })
1220
+ ] })
1221
+ ] })
1222
+ ] });
1223
+ }
1224
+ function SageDeskWidget({ indexUrl, agent, search: search2 }) {
1225
+ if (!indexUrl) {
1226
+ throw new Error(
1227
+ '[sagedesk] Required prop "indexUrl" is missing. Run `npx sagedesk build` and pass the output path, e.g. indexUrl="/support-index.json".'
1228
+ );
1229
+ }
1230
+ if (!agent?.name) {
1231
+ throw new Error('[sagedesk] Required prop "agent.name" is missing.');
1232
+ }
1233
+ const config = { indexUrl, agent, search: search2 };
1234
+ const { state, chips, open, close, submit } = useSageDesk(config);
1235
+ const theme = agent.theme ?? "classic";
1236
+ const accent = agent.accentColor ?? "#534AB7";
1237
+ const position = agent.position ?? "bottom-right";
1238
+ const isLeft = position === "bottom-left";
1239
+ const [inputValue, setInputValue] = (0, import_react2.useState)("");
1240
+ const [isClosing, setIsClosing] = (0, import_react2.useState)(false);
1241
+ const threadRef = (0, import_react2.useRef)(null);
1242
+ const inputRef = (0, import_react2.useRef)(null);
1243
+ const triggerRef = (0, import_react2.useRef)(null);
1244
+ const [mounted, setMounted] = (0, import_react2.useState)(false);
1245
+ (0, import_react2.useEffect)(() => {
1246
+ if (!indexUrl.startsWith("/") && !indexUrl.startsWith("http")) {
1247
+ console.warn(
1248
+ `[sagedesk] indexUrl "${indexUrl}" looks like a relative path. It should start with "/" so it resolves correctly from any page.`
1249
+ );
1250
+ }
1251
+ setMounted(true);
1252
+ injectStyles(theme);
1253
+ }, []);
1254
+ (0, import_react2.useEffect)(() => {
1255
+ if (threadRef.current) {
1256
+ threadRef.current.scrollTop = threadRef.current.scrollHeight;
1257
+ }
1258
+ }, [state.messages, state.isTyping]);
1259
+ (0, import_react2.useEffect)(() => {
1260
+ if (state.isOpen) {
1261
+ setTimeout(() => inputRef.current?.focus(), 50);
1262
+ }
1263
+ }, [state.isOpen]);
1264
+ const handleClose = (0, import_react2.useCallback)(() => {
1265
+ setIsClosing(true);
1266
+ setTimeout(() => {
1267
+ setIsClosing(false);
1268
+ close();
1269
+ triggerRef.current?.focus();
1270
+ }, 150);
1271
+ }, [close]);
1272
+ const handleSubmit = (0, import_react2.useCallback)(() => {
1273
+ const text = inputValue.trim();
1274
+ if (!text) return;
1275
+ setInputValue("");
1276
+ submit(text);
1277
+ }, [inputValue, submit]);
1278
+ const handleKeyDown = (0, import_react2.useCallback)(
1279
+ (e) => {
1280
+ if (e.key === "Enter" && !e.shiftKey) {
1281
+ e.preventDefault();
1282
+ handleSubmit();
1283
+ }
1284
+ },
1285
+ [handleSubmit]
1286
+ );
1287
+ if (!mounted || typeof document === "undefined") return null;
1288
+ const showPoweredBy = agent.poweredBy !== false;
1289
+ const showChips = chips.length > 0;
1290
+ const panelClass = isClosing ? "sd-r-closing" : state.isOpen ? "sd-r-opening" : "";
1291
+ const props = {
1292
+ agent,
1293
+ state,
1294
+ chips,
1295
+ accent,
1296
+ isLeft,
1297
+ inputValue,
1298
+ setInputValue,
1299
+ handleClose,
1300
+ handleSubmit,
1301
+ handleKeyDown,
1302
+ isClosing,
1303
+ panelClass,
1304
+ showChips,
1305
+ showPoweredBy,
1306
+ threadRef,
1307
+ inputRef,
1308
+ triggerRef,
1309
+ open,
1310
+ submit
1311
+ };
1312
+ const content = theme === "dark" ? renderDark(props) : theme === "light" ? renderLight(props) : renderClassic(props);
1313
+ return (0, import_react_dom.createPortal)(content, document.body);
1314
+ }
1315
+ var import_react2, import_react_dom, import_jsx_runtime, STYLE_ID, SHARED, THEME_CSS, IconChat, IconSend, IconClose, IconBot, IconPerson, PoweredBy;
1316
+ var init_SageDeskWidget = __esm({
1317
+ "src/react/SageDeskWidget.tsx"() {
1318
+ "use strict";
1319
+ import_react2 = require("react");
1320
+ import_react_dom = require("react-dom");
1321
+ init_useSageDesk();
1322
+ import_jsx_runtime = require("react/jsx-runtime");
1323
+ STYLE_ID = "sagedesk-widget-styles";
1324
+ SHARED = `
1325
+ @keyframes sd-bounce {
1326
+ 0%, 60%, 100% { transform: translateY(0); }
1327
+ 30% { transform: translateY(-5px); }
1328
+ }
1329
+ @keyframes sd-panel-open {
1330
+ from { transform: scale(0.94) translateY(6px); opacity: 0; }
1331
+ to { transform: scale(1) translateY(0); opacity: 1; }
1332
+ }
1333
+ @keyframes sd-panel-close {
1334
+ from { transform: scale(1) translateY(0); opacity: 1; }
1335
+ to { transform: scale(0.94) translateY(6px); opacity: 0; }
1336
+ }
1337
+ .sd-r-opening { animation: sd-panel-open 200ms cubic-bezier(0.34,1.56,0.64,1) both; }
1338
+ .sd-r-closing { animation: sd-panel-close 150ms ease-in both; }
1339
+ .sd-r-dot-1 { animation: sd-bounce 1.2s ease-in-out infinite; }
1340
+ .sd-r-dot-2 { animation: sd-bounce 1.2s ease-in-out 0.2s infinite; }
1341
+ .sd-r-dot-3 { animation: sd-bounce 1.2s ease-in-out 0.4s infinite; }
1342
+ .sd-r-scrollable {
1343
+ flex-wrap: nowrap !important;
1344
+ overflow-x: auto !important;
1345
+ scrollbar-width: none !important;
1346
+ -ms-overflow-style: none !important;
1347
+ }
1348
+ .sd-r-scrollable::-webkit-scrollbar { display: none !important; }
1349
+ .sd-r-scrollable > * { flex-shrink: 0 !important; }
1350
+ @media (max-width: 420px) {
1351
+ .sd-r-panel {
1352
+ bottom: 0 !important; right: 0 !important; left: 0 !important;
1353
+ width: auto !important; max-width: 100% !important;
1354
+ border-radius: 20px 20px 0 0 !important;
1355
+ max-height: 85vh !important;
1356
+ transform-origin: bottom center !important;
1357
+ }
1358
+ }
1359
+ `;
1360
+ THEME_CSS = {
1361
+ classic: `${SHARED}
1362
+ .sd-r-trigger:hover { transform: scale(1.06) !important; }
1363
+ .sd-r-close-btn:hover { background: rgba(255,255,255,0.22) !important; }
1364
+ .sd-r-chip:hover { opacity: 0.8; }
1365
+ .sd-r-send:hover { opacity: 0.85; }
1366
+ .sd-r-send:active { transform: scale(0.95); }
1367
+ .sd-r-input:focus { outline: none; }
1368
+ .sd-r-input::placeholder { color: #a8a8b0; }
1369
+ `,
1370
+ light: `${SHARED}
1371
+ .sd-r-trigger-light:hover { box-shadow: 0 16px 32px -10px rgba(40,30,90,0.24),0 2px 10px rgba(40,30,90,0.08) !important; }
1372
+ .sd-r-chip-light:hover { opacity: 0.75; }
1373
+ .sd-r-send:hover { opacity: 0.85; }
1374
+ .sd-r-send:active { transform: scale(0.95); }
1375
+ .sd-r-input:focus { outline: none; }
1376
+ .sd-r-input::placeholder { color: #a8a89e; }
1377
+ `,
1378
+ dark: `${SHARED}
1379
+ @keyframes sd-blink { 0%,100%{opacity:1} 50%{opacity:0} }
1380
+ .sd-r-cursor { animation: sd-blink 1s infinite; }
1381
+ .sd-r-trigger:hover { transform: scale(1.04) !important; }
1382
+ .sd-r-prompt:hover { background: rgba(255,255,255,0.07) !important; }
1383
+ .sd-r-send:hover { opacity: 0.85; }
1384
+ .sd-r-send:active { transform: scale(0.95); }
1385
+ .sd-r-input:focus { outline: none; }
1386
+ .sd-r-input::placeholder { color: rgba(255,255,255,0.35); }
1387
+ `
1388
+ };
1389
+ IconChat = ({ size = 22 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1390
+ "path",
1391
+ {
1392
+ d: "M5 6.5A2.5 2.5 0 017.5 4h9A2.5 2.5 0 0119 6.5v7A2.5 2.5 0 0116.5 16H11l-4 3.5V16H7.5A2.5 2.5 0 015 13.5v-7z",
1393
+ stroke: "currentColor",
1394
+ strokeWidth: "1.6",
1395
+ strokeLinejoin: "round"
1396
+ }
1397
+ ) });
1398
+ IconSend = ({ size = 14 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 12L20 4l-4 16-4-7-8-1z", stroke: "currentColor", strokeWidth: "1.6", strokeLinejoin: "round" }) });
1399
+ IconClose = ({ size = 14 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 6l12 12M18 6L6 18", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }) });
1400
+ IconBot = ({ size = 22 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
1401
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "4", y: "8", width: "16", height: "12", rx: "3", stroke: "currentColor", strokeWidth: "1.6" }),
1402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9", cy: "13.5", r: "1.5", fill: "currentColor" }),
1403
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "15", cy: "13.5", r: "1.5", fill: "currentColor" }),
1404
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9.5 16.5h5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
1405
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 8V5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
1406
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "4", r: "1.2", fill: "currentColor" })
1407
+ ] });
1408
+ IconPerson = ({ size = 18 }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1409
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 12.5a4 4 0 100-8 4 4 0 000 8z" }),
1410
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 20.5c0-3.5 3.13-6 7-6s7 2.5 7 6" })
1411
+ ] });
1412
+ PoweredBy = ({ dark = false }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
1413
+ fontSize: "11px",
1414
+ color: dark ? "rgba(255,255,255,0.35)" : "#a8a8b0",
1415
+ display: "flex",
1416
+ alignItems: "center",
1417
+ justifyContent: "center",
1418
+ gap: "4px"
1419
+ }, children: [
1420
+ "Powered by",
1421
+ " ",
1422
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1423
+ "a",
1424
+ {
1425
+ href: "https://github.com/mzeeshanwahid/sagedesk",
1426
+ target: "_blank",
1427
+ rel: "noopener noreferrer",
1428
+ style: {
1429
+ color: dark ? "rgba(255,255,255,0.7)" : "#5a5a64",
1430
+ fontWeight: 500,
1431
+ textDecoration: "none"
1432
+ },
1433
+ children: "sagedesk"
1434
+ }
1435
+ )
1436
+ ] });
1437
+ }
1438
+ });
1439
+
1440
+ // src/next/index.ts
1441
+ var next_exports = {};
1442
+ __export(next_exports, {
1443
+ SageDeskNext: () => SageDeskNext
1444
+ });
1445
+ module.exports = __toCommonJS(next_exports);
1446
+
1447
+ // src/next/SageDeskNext.tsx
1448
+ var import_react3 = require("react");
1449
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1450
+ var LazyWidget = (0, import_react3.lazy)(
1451
+ () => Promise.resolve().then(() => (init_SageDeskWidget(), SageDeskWidget_exports)).then((mod) => ({ default: mod.SageDeskWidget })).catch((err) => {
1452
+ console.warn("[sagedesk] Failed to load widget bundle:", err);
1453
+ const Empty = () => null;
1454
+ return { default: Empty };
1455
+ })
1456
+ );
1457
+ function SageDeskNext(props) {
1458
+ const [mounted, setMounted] = (0, import_react3.useState)(false);
1459
+ (0, import_react3.useEffect)(() => {
1460
+ if (!props.indexUrl) {
1461
+ console.warn(
1462
+ '[sagedesk] Missing required prop: indexUrl. The widget will not load.\nMake sure you ran `npx sagedesk build` and are passing indexUrl="/support-index.json" (or wherever you placed the output file in public/).'
1463
+ );
1464
+ } else if (!props.indexUrl.startsWith("/") && !props.indexUrl.startsWith("http")) {
1465
+ console.warn(
1466
+ `[sagedesk] indexUrl "${props.indexUrl}" looks like a relative path. It should start with "/" (e.g. "/support-index.json") so it resolves correctly from any page.`
1467
+ );
1468
+ }
1469
+ setMounted(true);
1470
+ }, []);
1471
+ if (!mounted) return null;
1472
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LazyWidget, { ...props }) });
1473
+ }
1474
+ // Annotate the CommonJS export names for ESM import in node:
1475
+ 0 && (module.exports = {
1476
+ SageDeskNext
1477
+ });
1478
+ //# sourceMappingURL=index.cjs.map