@foisit/react-wrapper 2.0.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs ADDED
@@ -0,0 +1,1084 @@
1
+ import { jsx as u } from "react/jsx-runtime";
2
+ import { createContext as A, useState as x, useEffect as w, useContext as I } from "react";
3
+ const E = {};
4
+ function Y() {
5
+ return /* @__PURE__ */ u("div", { className: E.container, children: /* @__PURE__ */ u("h1", { children: "Welcome to ReactWrapper!" }) });
6
+ }
7
+ class L {
8
+ constructor() {
9
+ this.endpoint = "https://foisit-ninja.netlify.app/.netlify/functions/intent";
10
+ }
11
+ /**
12
+ * Determine the best matching command by calling the internalized proxy
13
+ */
14
+ async determineIntent(e, t, i) {
15
+ try {
16
+ const s = await fetch(this.endpoint, {
17
+ method: "POST",
18
+ headers: {
19
+ "Content-Type": "application/json"
20
+ },
21
+ body: JSON.stringify({
22
+ userInput: e,
23
+ context: i,
24
+ commands: t.map((c) => ({
25
+ id: c.id,
26
+ command: c.command,
27
+ description: c.description,
28
+ keywords: c.keywords,
29
+ parameters: c.parameters
30
+ }))
31
+ })
32
+ });
33
+ if (!s.ok)
34
+ throw new Error("Proxy API request failed");
35
+ return await s.json();
36
+ } catch (s) {
37
+ return console.error("Foisit AI Error:", s), { type: "unknown" };
38
+ }
39
+ }
40
+ }
41
+ class M {
42
+ constructor(e = !0) {
43
+ this.commands = /* @__PURE__ */ new Map(), this.pendingConfirmation = null, this.conversationContext = null, this.enableSmartIntent = !0, this.enableSmartIntent = e, this.aiService = new L();
44
+ }
45
+ /**
46
+ * Add a new command (supports simple string or rich object)
47
+ */
48
+ addCommand(e, t) {
49
+ let i;
50
+ if (typeof e == "string") {
51
+ if (!t)
52
+ throw new Error("Action is required when passing a command string.");
53
+ i = {
54
+ command: e,
55
+ action: t,
56
+ id: `cmd_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
57
+ // Auto-gen ID
58
+ };
59
+ } else
60
+ i = e, i.id || (i.id = `cmd_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`);
61
+ const s = i.command.toLowerCase();
62
+ this.commands.set(s, i);
63
+ }
64
+ /** Remove an existing command by trigger phrase */
65
+ removeCommand(e) {
66
+ const t = e.toLowerCase();
67
+ this.commands.has(t) && this.commands.delete(t);
68
+ }
69
+ /** Execute a command by matching input (string or parameter object) */
70
+ async executeCommand(e) {
71
+ var c;
72
+ if (typeof e == "object" && this.conversationContext) {
73
+ const o = Array.from(this.commands.values()).find(
74
+ (a) => {
75
+ var n;
76
+ return a.id === ((n = this.conversationContext) == null ? void 0 : n.commandId);
77
+ }
78
+ );
79
+ if (o) {
80
+ const a = { ...this.conversationContext.params, ...e };
81
+ return this.conversationContext = null, this.runAction(o, a);
82
+ }
83
+ }
84
+ const t = (typeof e == "string" ? e : "").toLowerCase().trim();
85
+ if (this.pendingConfirmation)
86
+ if (t === "yes" || t === "y" || t === "confirm") {
87
+ const o = this.pendingConfirmation;
88
+ return this.pendingConfirmation = null, this.runAction(o);
89
+ } else return t === "no" || t === "n" || t === "cancel" ? (this.pendingConfirmation = null, { type: "success", message: "Action cancelled." }) : {
90
+ type: "ambiguous",
91
+ message: `Please confirm: Are you sure you want to ${this.pendingConfirmation.description || this.pendingConfirmation.command}?`,
92
+ options: [
93
+ { label: "Yes", value: "yes" },
94
+ { label: "No", value: "no" }
95
+ ]
96
+ };
97
+ if (!this.conversationContext) {
98
+ const o = this.commands.get(t);
99
+ if (o) {
100
+ if (!o.parameters || o.parameters.length === 0)
101
+ return o.critical ? (this.pendingConfirmation = o, {
102
+ type: "ambiguous",
103
+ message: `Are you sure you want to ${o.description || o.command}?`,
104
+ options: [
105
+ { label: "Yes", value: "yes" },
106
+ { label: "No", value: "no" }
107
+ ]
108
+ }) : this.runAction(o);
109
+ this.conversationContext = {
110
+ commandId: o.id || "",
111
+ params: {}
112
+ };
113
+ const a = await Promise.all(
114
+ o.parameters.map(async (n) => {
115
+ let h = n.options;
116
+ if (n.getOptions)
117
+ try {
118
+ h = await n.getOptions();
119
+ } catch (m) {
120
+ console.error(`Error fetching options for ${n.name}`, m);
121
+ }
122
+ return {
123
+ name: n.name,
124
+ label: n.name.charAt(0).toUpperCase() + n.name.slice(1),
125
+ value: "",
126
+ required: n.required,
127
+ type: n.type || "string",
128
+ options: h
129
+ };
130
+ })
131
+ );
132
+ return {
133
+ type: "form",
134
+ message: o.description || `Please fill in the details for ${o.command}:`,
135
+ fields: a
136
+ };
137
+ }
138
+ }
139
+ const i = Array.from(this.commands.values());
140
+ if (this.enableSmartIntent) {
141
+ const o = await this.aiService.determineIntent(
142
+ t,
143
+ i,
144
+ this.conversationContext
145
+ );
146
+ if (o.type === "match" && o.match) {
147
+ const a = i.find((n) => n.id === o.match);
148
+ if (a) {
149
+ const n = {
150
+ ...((c = this.conversationContext) == null ? void 0 : c.params) || {},
151
+ ...o.params || {}
152
+ };
153
+ if (o.incomplete) {
154
+ if (this.conversationContext = {
155
+ commandId: a.id,
156
+ params: n
157
+ }, a.parameters && a.parameters.length > 0) {
158
+ const h = await Promise.all(
159
+ a.parameters.map(async (m) => {
160
+ let d = m.options;
161
+ if (m.getOptions)
162
+ try {
163
+ d = await m.getOptions();
164
+ } catch (g) {
165
+ console.error(`Error fetching options for ${m.name}`, g);
166
+ }
167
+ return {
168
+ name: m.name,
169
+ label: m.name.charAt(0).toUpperCase() + m.name.slice(1),
170
+ value: n[m.name] || "",
171
+ required: m.required,
172
+ type: m.type || "string",
173
+ options: d
174
+ };
175
+ })
176
+ );
177
+ return {
178
+ type: "form",
179
+ message: o.message || `Please fill in the details for ${a.command}:`,
180
+ fields: h
181
+ };
182
+ }
183
+ return {
184
+ type: "ambiguous",
185
+ message: o.message || `Need more info for ${a.command}...`
186
+ };
187
+ }
188
+ return this.conversationContext = null, a.critical ? (this.pendingConfirmation = {
189
+ ...a,
190
+ action: () => a.action(n)
191
+ }, {
192
+ type: "ambiguous",
193
+ message: `Are you sure you want to ${a.description || a.command}?`,
194
+ options: [
195
+ { label: "Yes", value: "yes" },
196
+ { label: "No", value: "no" }
197
+ ]
198
+ }) : this.runAction(a, n);
199
+ }
200
+ } else if (o.type === "ambiguous" && o.options)
201
+ return {
202
+ type: "ambiguous",
203
+ message: "Did you mean...",
204
+ options: o.options.map((a) => ({
205
+ label: a.label,
206
+ value: a.label
207
+ }))
208
+ };
209
+ }
210
+ return {
211
+ type: "ambiguous",
212
+ message: "I'm not sure what you mean. Here is what I can do:",
213
+ options: i.map((o) => ({
214
+ label: o.command,
215
+ value: o.command
216
+ }))
217
+ };
218
+ }
219
+ /** Run a command action and handle rich responses */
220
+ async runAction(e, t) {
221
+ try {
222
+ const i = await e.action(t);
223
+ return typeof i == "string" ? { type: "success", message: i } : i && i.type ? i : {
224
+ type: "success",
225
+ message: `Executed: ${e.command}`
226
+ };
227
+ } catch (i) {
228
+ return {
229
+ type: "error",
230
+ message: i.message || "An error occurred during execution."
231
+ };
232
+ }
233
+ }
234
+ /** List all registered commands */
235
+ getCommands() {
236
+ return Array.from(this.commands.keys());
237
+ }
238
+ }
239
+ class k {
240
+ constructor() {
241
+ this.synth = window.speechSynthesis;
242
+ }
243
+ speak(e, t) {
244
+ if (!this.synth) {
245
+ console.error("SpeechSynthesis API is not supported in this browser.");
246
+ return;
247
+ }
248
+ const i = new SpeechSynthesisUtterance(e);
249
+ t && (i.pitch = t.pitch || 1, i.rate = t.rate || 1, i.volume = t.volume || 1), i.onend = () => {
250
+ console.log("Speech finished.");
251
+ }, i.onerror = (s) => {
252
+ console.error("Error during speech synthesis:", s.error);
253
+ }, this.synth.speak(i);
254
+ }
255
+ stopSpeaking() {
256
+ this.synth && this.synth.cancel();
257
+ }
258
+ }
259
+ class P {
260
+ constructor() {
261
+ this.fallbackMessage = "Sorry, I didn’t understand that.";
262
+ }
263
+ setFallbackMessage(e) {
264
+ this.fallbackMessage = e;
265
+ }
266
+ handleFallback(e) {
267
+ console.log(this.fallbackMessage), new k().speak(this.fallbackMessage);
268
+ }
269
+ }
270
+ class T {
271
+ constructor(e = "en-US") {
272
+ this.isListening = !1, this.isStoppedSpeechRecog = !1, this.restartAllowed = !0;
273
+ }
274
+ /** Start listening for speech input */
275
+ startListening(e) {
276
+ console.warn("VoiceProcessor: Voice interaction is currently DISABLED.");
277
+ }
278
+ /** Stop listening for speech input */
279
+ stopListening() {
280
+ if (console.log("VoiceProcessor: Stopping listening..."), this.isStoppedSpeechRecog = !0, this.restartAllowed = !1, !this.isListening) {
281
+ console.warn("VoiceProcessor: Already stopped. Skipping stop...");
282
+ return;
283
+ }
284
+ try {
285
+ this.recognition.stop(), this.isListening = !1, console.log("VoiceProcessor: Listening stopped.");
286
+ } catch (e) {
287
+ console.error("VoiceProcessor: Failed to stop SpeechRecognition:", e);
288
+ }
289
+ }
290
+ /** Handle recognized speech results */
291
+ handleResult(e, t) {
292
+ }
293
+ /** Handle session end */
294
+ handleEnd() {
295
+ console.log("VoiceProcessor: Session ended."), this.isListening = !1, this.restartAllowed && !this.isStoppedSpeechRecog && (console.log(
296
+ "VoiceProcessor: Restarting session due to unexpected stop..."
297
+ ), setTimeout(() => this.startListening(() => {
298
+ }), 560));
299
+ }
300
+ /** Handle errors during speech recognition */
301
+ handleError(e) {
302
+ console.error("VoiceProcessor: Error occurred:", e.error), e.error === "no-speech" ? console.log("VoiceProcessor: No speech detected.") : e.error === "audio-capture" && console.log("VoiceProcessor: Microphone not detected."), this.isListening = !1;
303
+ }
304
+ }
305
+ class B {
306
+ constructor() {
307
+ this.lastTap = 0;
308
+ }
309
+ /**
310
+ * Sets up double-click and double-tap listeners
311
+ * @param onDoubleClickOrTap Callback to execute when a double-click or double-tap is detected
312
+ */
313
+ setupDoubleTapListener(e) {
314
+ document.addEventListener("dblclick", () => {
315
+ e();
316
+ }), document.addEventListener("touchend", (t) => {
317
+ const i = (/* @__PURE__ */ new Date()).getTime(), s = i - this.lastTap;
318
+ s < 300 && s > 0 && e(), this.lastTap = i;
319
+ });
320
+ }
321
+ }
322
+ function D() {
323
+ if (document.querySelector("#assistant-styles")) {
324
+ console.log("Styles already injected");
325
+ return;
326
+ }
327
+ const e = document.createElement("style");
328
+ e.id = "assistant-styles", e.innerHTML = `
329
+ /* Rounded shape with gradient animation */
330
+ .gradient-indicator {
331
+ position: fixed;
332
+ top: 20px;
333
+ right: 20px;
334
+ width: 60px;
335
+ height: 60px;
336
+ border-radius: 50%;
337
+ background: linear-gradient(135deg, #ff6ec4, #7873f5, #5e8cff, #6ed0f6);
338
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
339
+ animation: amoeba 5s infinite ease-in-out;
340
+ z-index: 9999; /* Ensure it's above all other elements */
341
+ }
342
+
343
+ /* Amoeba effect for the borders */
344
+ @keyframes amoeba {
345
+ 0% {
346
+ border-radius: 50%;
347
+ }
348
+ 25% {
349
+ border-radius: 40% 60% 60% 40%;
350
+ }
351
+ 50% {
352
+ border-radius: 60% 40% 40% 60%;
353
+ }
354
+ 75% {
355
+ border-radius: 40% 60% 60% 40%;
356
+ }
357
+ 100% {
358
+ border-radius: 50%;
359
+ }
360
+ }
361
+ `, document.head.appendChild(e), console.log("Gradient styles injected");
362
+ }
363
+ function R() {
364
+ if (document.querySelector("#gradient-indicator"))
365
+ return;
366
+ const r = document.createElement("div");
367
+ r.id = "gradient-indicator", D(), r.classList.add("gradient-indicator"), document.body.appendChild(r), console.log("Gradient indicator added to the DOM");
368
+ }
369
+ function H() {
370
+ const r = document.querySelector("#gradient-indicator");
371
+ r && (r.remove(), console.log("Gradient indicator removed from the DOM"));
372
+ }
373
+ class N {
374
+ constructor() {
375
+ this.state = "idle", this.subscribers = [];
376
+ }
377
+ getState() {
378
+ return this.state;
379
+ }
380
+ setState(e) {
381
+ this.state = e, this.notifySubscribers(), console.log("State updated:", e), e === "listening" ? R() : H();
382
+ }
383
+ // eslint-disable-next-line no-unused-vars
384
+ subscribe(e) {
385
+ this.subscribers.push(e);
386
+ }
387
+ notifySubscribers() {
388
+ this.subscribers.forEach((e) => e(this.state));
389
+ }
390
+ }
391
+ const l = class l {
392
+ constructor(e) {
393
+ this.isOpen = !1, this.submitCallback = null, this.closeCallback = null, this.chatContainer = null, this.config = {}, e && (this.config = e), this.injectStyles(), this.injectOverlay(), this.injectFloatingButton(), this.setupEventListeners(), this.chatContainer = document.getElementById(
394
+ "foisit-chat-history"
395
+ );
396
+ }
397
+ /**
398
+ * Cleanup everything from the DOM
399
+ */
400
+ destroy() {
401
+ const e = document.getElementById(l.OVERLAY_ID);
402
+ e && e.remove();
403
+ const t = document.getElementById(l.STYLES_ID);
404
+ t && t.remove();
405
+ const i = document.getElementById("foisit-floating-btn");
406
+ i && i.remove(), this.isOpen = !1, this.chatContainer = null, this.submitCallback = null, this.closeCallback = null;
407
+ }
408
+ /**
409
+ * Register callbacks for the overlay (used by floating button)
410
+ */
411
+ registerCallbacks(e, t) {
412
+ this.submitCallback = e, this.closeCallback = t || null;
413
+ }
414
+ /**
415
+ * Show the overlay and focus input
416
+ */
417
+ show(e, t) {
418
+ const i = document.getElementById(l.OVERLAY_ID), s = document.getElementById(
419
+ l.INPUT_ID
420
+ );
421
+ this.chatContainer = document.getElementById(
422
+ "foisit-chat-history"
423
+ ), i && s && (this.submitCallback = e, this.closeCallback = t || null, i.style.display = "flex", setTimeout(() => {
424
+ i.classList.add("visible"), s.focus(), s.focus(), s.value = "", this.chatContainer && (this.chatContainer.innerHTML = "");
425
+ }, 10), this.isOpen = !0);
426
+ }
427
+ /**
428
+ * Hide the overlay
429
+ */
430
+ hide() {
431
+ const e = document.getElementById(l.OVERLAY_ID);
432
+ e && (e.classList.remove("visible"), setTimeout(() => {
433
+ e.style.display = "none";
434
+ }, 300), this.isOpen = !1, this.closeCallback && this.closeCallback());
435
+ }
436
+ /**
437
+ * Toggle the overlay
438
+ */
439
+ toggle(e, t) {
440
+ this.isOpen ? this.hide() : this.show(e, t);
441
+ }
442
+ /**
443
+ * Add a message bubble to the chat
444
+ */
445
+ addMessage(e, t = "system") {
446
+ if (!this.chatContainer) return;
447
+ const i = document.createElement("div");
448
+ i.className = `foisit-bubble ${t}`, i.textContent = e, this.chatContainer.appendChild(i), this.scrollToBottom();
449
+ }
450
+ /**
451
+ * Add clickable options to the chat
452
+ */
453
+ addOptions(e) {
454
+ if (!this.chatContainer) return;
455
+ const t = document.createElement("div");
456
+ t.className = "foisit-options-container", e.forEach((i) => {
457
+ const s = document.createElement("button");
458
+ s.className = "foisit-option-chip", s.textContent = i.label, s.onclick = () => {
459
+ this.addMessage(i.label, "user"), this.submitCallback && this.submitCallback(i.value);
460
+ }, t.appendChild(s);
461
+ }), this.chatContainer.appendChild(t), this.scrollToBottom();
462
+ }
463
+ /**
464
+ * Inject the floating trigger button
465
+ */
466
+ injectFloatingButton() {
467
+ var s, c, o, a;
468
+ if (((s = this.config.floatingButton) == null ? void 0 : s.visible) === !1) return;
469
+ const e = document.getElementById("foisit-floating-btn");
470
+ e && e.remove();
471
+ const t = document.createElement("div");
472
+ t.id = "foisit-floating-btn", t.className = "foisit-floating-btn", t.title = ((c = this.config.floatingButton) == null ? void 0 : c.tooltip) || "Open Foisit Assistant";
473
+ const i = (o = this.config.floatingButton) == null ? void 0 : o.position;
474
+ i && (t.style.bottom = i.bottom, t.style.right = i.right), (a = this.config.floatingButton) != null && a.customHtml ? t.innerHTML = this.config.floatingButton.customHtml : t.innerHTML = `
475
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
476
+ <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 4C16.42 4 20 7.58 20 12C20 16.42 16.42 20 12 20C7.58 20 4 16.42 4 12C4 7.58 7.58 4 12 4Z" fill="white" fill-opacity="0.8"/>
477
+ <path d="M12 6C8.69 6 6 8.69 6 12C6 15.31 8.69 18 12 18C15.31 18 18 15.31 18 12C18 8.69 15.31 6 12 6ZM12 16C9.79 16 8 14.21 8 12C8 9.79 9.79 8 12 8C14.21 8 16 9.79 16 12C16 14.21 14.21 16 12 16Z" fill="white"/>
478
+ </svg>
479
+ `, t.onclick = () => {
480
+ this.submitCallback && this.toggle(this.submitCallback, this.closeCallback || void 0);
481
+ }, document.body.appendChild(t);
482
+ }
483
+ /**
484
+ * Add a dynamic form to the chat
485
+ */
486
+ addForm(e, t, i) {
487
+ if (!this.chatContainer) return;
488
+ const s = document.createElement("div");
489
+ s.className = "foisit-form-card";
490
+ const c = document.createElement("div");
491
+ c.className = "foisit-form-message", c.textContent = e, s.appendChild(c);
492
+ const o = {};
493
+ t.forEach((n) => {
494
+ var g, C;
495
+ const h = document.createElement("div");
496
+ h.className = "foisit-field-group";
497
+ const m = document.createElement("label");
498
+ m.textContent = n.label, h.appendChild(m);
499
+ let d;
500
+ if ((n.type === "select" || n.options) && ((g = n.options) != null && g.length) && n.options.length > 0) {
501
+ d = document.createElement("select"), d.className = "foisit-field-input";
502
+ const p = document.createElement("option");
503
+ p.value = "", p.textContent = `Select ${n.label}`, p.disabled = !0, p.selected = !n.value, d.appendChild(p), (C = n.options) == null || C.forEach((y) => {
504
+ const f = document.createElement("option");
505
+ f.value = y.value, f.textContent = y.label, n.value === y.value && (f.selected = !0), d.appendChild(f);
506
+ });
507
+ } else
508
+ d = document.createElement("input"), d.className = "foisit-field-input", d.placeholder = n.label, d.value = n.value || "", n.type === "date" ? d.type = "date" : n.type === "number" ? d.type = "number" : d.type = "text";
509
+ o[n.name] = d, h.appendChild(d), s.appendChild(h);
510
+ });
511
+ const a = document.createElement("button");
512
+ a.className = "foisit-form-submit", a.textContent = "Submit", a.onclick = () => {
513
+ const n = {};
514
+ Object.keys(o).forEach((h) => {
515
+ n[h] = o[h].value;
516
+ }), a.disabled = !0, a.textContent = "Submitted", s.style.opacity = "0.7", s.style.pointerEvents = "none", i(n);
517
+ }, s.appendChild(a), this.chatContainer.appendChild(s), this.scrollToBottom();
518
+ }
519
+ /**
520
+ * Show loading indicator
521
+ */
522
+ showLoading() {
523
+ if (!this.chatContainer || document.getElementById("foisit-loading-bubble")) return;
524
+ const e = document.createElement("div");
525
+ e.id = "foisit-loading-bubble", e.className = "foisit-bubble system loading", e.innerHTML = "<span>.</span><span>.</span><span>.</span>", this.chatContainer.appendChild(e), this.scrollToBottom();
526
+ }
527
+ /**
528
+ * Hide loading indicator
529
+ */
530
+ hideLoading() {
531
+ const e = document.getElementById("foisit-loading-bubble");
532
+ e && e.remove();
533
+ }
534
+ scrollToBottom() {
535
+ this.chatContainer && (this.chatContainer.scrollTop = this.chatContainer.scrollHeight);
536
+ }
537
+ injectStyles() {
538
+ if (document.getElementById(l.STYLES_ID)) return;
539
+ const e = document.createElement("style");
540
+ e.id = l.STYLES_ID, e.innerHTML = `
541
+ #${l.OVERLAY_ID} {
542
+ position: fixed;
543
+ top: 24px;
544
+ right: 24px;
545
+ width: 320px;
546
+ z-index: 99999;
547
+ display: none;
548
+ flex-direction: column;
549
+ opacity: 0;
550
+ transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
551
+ transform: translateY(-10px);
552
+ }
553
+
554
+ #${l.OVERLAY_ID}.visible {
555
+ opacity: 1;
556
+ transform: translateY(0);
557
+ }
558
+
559
+ .foisit-content {
560
+ width: 100%;
561
+ padding: 0;
562
+ border-radius: 16px;
563
+ overflow: hidden;
564
+ /* Stronger Frosted Look (User Provided) */
565
+ background: linear-gradient(
566
+ 135deg,
567
+ rgba(255, 255, 255, 0.25),
568
+ rgba(255, 255, 255, 0.05)
569
+ );
570
+ backdrop-filter: blur(20px);
571
+ -webkit-backdrop-filter: blur(20px);
572
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
573
+ border: 1px solid rgba(255, 255, 255, 0.4);
574
+ display: flex;
575
+ flex-direction: column;
576
+ }
577
+
578
+ #${l.INPUT_ID} {
579
+ width: 100%;
580
+ background: transparent;
581
+ border: none;
582
+ font-size: 16px;
583
+ color: #333;
584
+ padding: 18px 20px 12px 20px;
585
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
586
+ outline: none;
587
+ text-align: left;
588
+ resize: none;
589
+ min-height: 48px;
590
+ max-height: 200px;
591
+ overflow-y: auto;
592
+ }
593
+
594
+ #${l.INPUT_ID}::placeholder {
595
+ color: rgba(60, 60, 67, 0.7);
596
+ font-weight: 500;
597
+ }
598
+
599
+ @media (prefers-color-scheme: dark) {
600
+ .foisit-content {
601
+ background: linear-gradient(
602
+ 135deg,
603
+ rgba(40, 40, 40, 0.65),
604
+ rgba(40, 40, 40, 0.25)
605
+ );
606
+ border: 1px solid rgba(255, 255, 255, 0.1);
607
+ }
608
+ #${l.INPUT_ID} {
609
+ color: white;
610
+ }
611
+ #${l.INPUT_ID}::placeholder {
612
+ color: rgba(235, 235, 245, 0.6);
613
+ }
614
+ .foisit-watermark {
615
+ color: rgba(255, 255, 255, 0.5);
616
+ }
617
+ }
618
+
619
+ .foisit-watermark {
620
+ align-self: flex-end;
621
+ margin: 0 12px 10px auto;
622
+ padding: 4px 8px;
623
+ border-radius: 8px;
624
+
625
+ font-size: 9px;
626
+ font-weight: 600;
627
+ letter-spacing: 0.8px;
628
+ text-transform: capitalize;
629
+
630
+ background: rgba(0, 0, 0, 0.35);
631
+ backdrop-filter: blur(6px);
632
+ -webkit-backdrop-filter: blur(6px);
633
+
634
+ color: rgba(255, 255, 255, 0.85);
635
+ pointer-events: none;
636
+ }
637
+
638
+
639
+ /* Chat UI Styles */
640
+ #foisit-chat-history {
641
+ flex: 1;
642
+ overflow-y: auto;
643
+ padding: 16px;
644
+ display: flex;
645
+ flex-direction: column;
646
+ gap: 12px;
647
+ max-height: 400px;
648
+ }
649
+
650
+ .foisit-bubble {
651
+ max-width: 85%;
652
+ padding: 8px 12px;
653
+ border-radius: 12px;
654
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
655
+ font-size: 14px;
656
+ line-height: 1.4;
657
+ }
658
+
659
+ .foisit-bubble.user {
660
+ align-self: flex-end;
661
+ background: rgba(0, 0, 0, 0.05); /* Subtle dark for user */
662
+ color: #333;
663
+ border-bottom-right-radius: 4px;
664
+ }
665
+
666
+ .foisit-bubble.system {
667
+ align-self: flex-start;
668
+ background: rgba(255, 255, 255, 0.4); /* Glassy white */
669
+ color: #333;
670
+ border-bottom-left-radius: 4px;
671
+ }
672
+
673
+ .foisit-options-container {
674
+ display: flex;
675
+ flex-wrap: wrap;
676
+ gap: 8px;
677
+ margin-left: 4px;
678
+ }
679
+
680
+ .foisit-option-chip {
681
+ padding: 6px 12px;
682
+ background: rgba(255, 255, 255, 0.5);
683
+ border: 1px solid rgba(0, 0, 0, 0.1);
684
+ border-radius: 20px;
685
+ font-size: 13px;
686
+ color: #333;
687
+ cursor: pointer;
688
+ transition: all 0.2s;
689
+ }
690
+
691
+ .foisit-option-chip:hover {
692
+ background: rgba(255, 255, 255, 0.8);
693
+ transform: translateY(-1px);
694
+ box-shadow: 0 2px 5px rgba(0,0,0,0.05);
695
+ }
696
+
697
+ @media (prefers-color-scheme: dark) {
698
+ .foisit-bubble.user {
699
+ background: rgba(255, 255, 255, 0.1);
700
+ color: white;
701
+ }
702
+ .foisit-bubble.system {
703
+ background: rgba(255, 255, 255, 0.05);
704
+ color: rgba(255, 255, 255, 0.9);
705
+ }
706
+ .foisit-option-chip {
707
+ background: rgba(255, 255, 255, 0.1);
708
+ border-color: rgba(255, 255, 255, 0.2);
709
+ color: white;
710
+ }
711
+ .foisit-option-chip:hover {
712
+ background: rgba(255, 255, 255, 0.2);
713
+ }
714
+ /* Loading State */
715
+ .foisit-loading-dots {
716
+ display: inline-flex;
717
+ gap: 4px;
718
+ align-items: center;
719
+ padding: 4px 8px;
720
+ background: rgba(255, 255, 255, 0.4);
721
+ border-radius: 12px;
722
+ margin-left: 12px;
723
+ align-self: flex-start;
724
+ }
725
+ .foisit-dot {
726
+ width: 6px;
727
+ height: 6px;
728
+ background: #666;
729
+ border-radius: 50%;
730
+ animation: foisit-bounce 1.4s infinite ease-in-out both;
731
+ }
732
+ .foisit-dot:nth-child(1) { animation-delay: -0.32s; }
733
+ .foisit-dot:nth-child(2) { animation-delay: -0.16s; }
734
+
735
+ @keyframes foisit-bounce {
736
+ 0%, 80%, 100% { transform: scale(0); }
737
+ 40% { transform: scale(1); }
738
+ }
739
+
740
+ /* Floating Trigger Button - Glassmorphism Style */
741
+ .foisit-floating-btn {
742
+ position: fixed;
743
+ bottom: 20px;
744
+ right: 20px;
745
+ width: 52px;
746
+ height: 52px;
747
+ /* Frosted Glass Effect */
748
+ background: linear-gradient(
749
+ 135deg,
750
+ rgba(255, 255, 255, 0.25),
751
+ rgba(255, 255, 255, 0.08)
752
+ );
753
+ backdrop-filter: blur(16px);
754
+ -webkit-backdrop-filter: blur(16px);
755
+ border-radius: 50%;
756
+ display: flex;
757
+ align-items: center;
758
+ justify-content: center;
759
+ cursor: pointer;
760
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
761
+ border: 1px solid rgba(255, 255, 255, 0.35);
762
+ z-index: 9998;
763
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
764
+ }
765
+
766
+ .foisit-floating-btn:hover {
767
+ transform: scale(1.08);
768
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
769
+ }
770
+
771
+ /* Dark mode for floating button */
772
+ @media (prefers-color-scheme: dark) {
773
+ .foisit-floating-btn {
774
+ background: linear-gradient(
775
+ 135deg,
776
+ rgba(60, 60, 60, 0.6),
777
+ rgba(40, 40, 40, 0.35)
778
+ );
779
+ border-color: rgba(255, 255, 255, 0.15);
780
+ }
781
+ }
782
+
783
+ .foisit-floating-btn img {
784
+ width: 100%;
785
+ height: 100%;
786
+ object-fit: cover;
787
+ border-radius: 50%;
788
+ }
789
+
790
+ /* Dark mode support for inputs */
791
+ @media (prefers-color-scheme: dark) {
792
+ .foisit-field-input {
793
+ background: rgba(40, 40, 40, 0.6);
794
+ color: white;
795
+ border-color: rgba(255, 255, 255, 0.1);
796
+ }
797
+ }
798
+ .foisit-watermark {
799
+ color: rgba(255, 255, 255, 0.3);
800
+ }
801
+ }
802
+
803
+ /* Loading Animation */
804
+ .foisit-bubble.loading span {
805
+ animation: foisit-dots 1.4s infinite ease-in-out both;
806
+ font-size: 20px;
807
+ line-height: 10px;
808
+ margin: 0 1px;
809
+ }
810
+
811
+ .foisit-bubble.loading span:nth-child(1) { animation-delay: -0.32s; }
812
+ .foisit-bubble.loading span:nth-child(2) { animation-delay: -0.16s; }
813
+
814
+ @keyframes foisit-dots {
815
+ 0%, 80%, 100% { transform: scale(0); opacity: 0.5; }
816
+ 40% { transform: scale(1); opacity: 1; }
817
+ }
818
+
819
+ /* Form Styles */
820
+ .foisit-form-card {
821
+ align-self: flex-start;
822
+ background: rgba(255, 255, 255, 0.4);
823
+ padding: 16px;
824
+ border-radius: 12px;
825
+ width: 100%;
826
+ box-sizing: border-box;
827
+ border: 1px solid rgba(255, 255, 255, 0.2);
828
+ display: flex;
829
+ flex-direction: column;
830
+ gap: 12px;
831
+ }
832
+
833
+ .foisit-form-message {
834
+ font-family: -apple-system, sans-serif;
835
+ font-size: 14px;
836
+ color: #333;
837
+ margin-bottom: 4px;
838
+ font-weight: 500;
839
+ }
840
+
841
+ .foisit-field-group {
842
+ display: flex;
843
+ flex-direction: column;
844
+ gap: 4px;
845
+ }
846
+
847
+ .foisit-field-group label {
848
+ font-size: 11px;
849
+ font-weight: 600;
850
+ text-transform: uppercase;
851
+ color: rgba(0, 0, 0, 0.5);
852
+ }
853
+
854
+ .foisit-field-input {
855
+ background: rgba(255, 255, 255, 0.6);
856
+ border: 1px solid rgba(0, 0, 0, 0.1);
857
+ border-radius: 8px;
858
+ padding: 8px 12px;
859
+ font-size: 14px;
860
+ color: #333;
861
+ outline: none;
862
+ }
863
+
864
+ .foisit-field-input:focus {
865
+ border-color: rgba(0, 0, 0, 0.3);
866
+ }
867
+
868
+ .foisit-form-submit {
869
+ background: #000;
870
+ color: #fff;
871
+ border: none;
872
+ border-radius: 8px;
873
+ padding: 10px;
874
+ font-size: 14px;
875
+ font-weight: 500;
876
+ cursor: pointer;
877
+ transition: opacity 0.2s;
878
+ margin-top: 4px;
879
+ }
880
+
881
+ .foisit-form-submit:hover {
882
+ opacity: 0.8;
883
+ }
884
+
885
+ @media (prefers-color-scheme: dark) {
886
+ .foisit-form-card {
887
+ background: rgba(255, 255, 255, 0.05);
888
+ color: white;
889
+ }
890
+ .foisit-form-message {
891
+ color: white;
892
+ }
893
+ .foisit-field-group label {
894
+ color: rgba(255, 255, 255, 0.5);
895
+ }
896
+ .foisit-field-input {
897
+ background: rgba(0, 0, 0, 0.2);
898
+ border-color: rgba(255, 255, 255, 0.1);
899
+ color: white;
900
+ }
901
+ .foisit-form-submit {
902
+ background: #fff;
903
+ color: #000;
904
+ }
905
+ }
906
+
907
+ `, document.head.appendChild(e);
908
+ }
909
+ injectOverlay() {
910
+ if (document.getElementById(l.OVERLAY_ID)) return;
911
+ const e = this.config.inputPlaceholder || "How can I help you?", t = document.createElement("div");
912
+ t.id = l.OVERLAY_ID, t.innerHTML = `
913
+ <div class="foisit-content">
914
+ <div id="foisit-chat-history"></div>
915
+ <textarea id="${l.INPUT_ID}" placeholder="${e}" autocomplete="off" rows="1"></textarea>
916
+ <div class="foisit-watermark">Foisit</div>
917
+ </div>
918
+ `, document.body.appendChild(t);
919
+ }
920
+ setupEventListeners() {
921
+ const e = document.getElementById(l.OVERLAY_ID), t = document.getElementById(
922
+ l.INPUT_ID
923
+ );
924
+ !e || !t || (t.addEventListener("input", () => {
925
+ t.style.height = "auto", t.style.height = Math.min(t.scrollHeight, 200) + "px";
926
+ }), e.addEventListener("click", (i) => {
927
+ i.target === e && this.hide();
928
+ }), t.addEventListener("keydown", (i) => {
929
+ if (i.key === "Enter" && !i.shiftKey) {
930
+ i.preventDefault();
931
+ const s = t.value.trim();
932
+ s && this.submitCallback && (this.submitCallback(s), t.value = "", t.style.height = "auto");
933
+ }
934
+ i.key === "Escape" && this.hide();
935
+ }));
936
+ }
937
+ };
938
+ l.OVERLAY_ID = "foisit-assistant-overlay", l.INPUT_ID = "foisit-assistant-input", l.STYLES_ID = "foisit-assistant-styles";
939
+ let v = l;
940
+ class $ {
941
+ constructor(e) {
942
+ this.config = e, this.isActivated = !1, this.lastProcessedInput = "", this.processingLock = !1, this.defaultIntroMessage = "How can I help you?", this.commandHandler = new M(
943
+ this.config.enableSmartIntent !== !1
944
+ ), this.fallbackHandler = new P(), this.voiceProcessor = new T(), this.textToSpeech = new k(), this.stateManager = new N(), this.gestureHandler = new B(), this.overlayManager = new v({
945
+ floatingButton: this.config.floatingButton,
946
+ inputPlaceholder: this.config.inputPlaceholder
947
+ }), this.config.commands.forEach((t) => this.commandHandler.addCommand(t)), this.config.fallbackResponse && this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse), this.gestureHandler.setupDoubleTapListener(() => this.toggle()), this.overlayManager.registerCallbacks(
948
+ async (t) => {
949
+ this.overlayManager.addMessage(t, "user"), await this.handleCommand(t);
950
+ },
951
+ () => console.log("AssistantService: Overlay closed.")
952
+ );
953
+ }
954
+ /** Start listening for activation and commands */
955
+ startListening() {
956
+ console.log("AssistantService: Starting listening..."), this.voiceProcessor.startListening(async (e) => {
957
+ var s, c;
958
+ if (this.processingLock) return;
959
+ const t = e.toLowerCase().trim();
960
+ if (!t || t.length < 3 || t === this.lastProcessedInput) {
961
+ console.log("AssistantService: Ignoring irrelevant input.");
962
+ return;
963
+ }
964
+ if (this.lastProcessedInput = t, !this.isActivated) {
965
+ await this.processActivation(t);
966
+ return;
967
+ }
968
+ t === ((s = this.config.fallbackResponse) == null ? void 0 : s.toLowerCase()) || t === ((c = this.config.introMessage) == null ? void 0 : c.toLowerCase()) || t === this.defaultIntroMessage.toLowerCase() ? console.log("AssistantService: Ignoring fallback or intro message.") : await this.handleCommand(t), this.processingLock = !0, setTimeout(() => this.processingLock = !1, 1e3);
969
+ });
970
+ }
971
+ /** Stop listening */
972
+ stopListening() {
973
+ console.log("AssistantService: Stopping listening..."), this.voiceProcessor.stopListening(), this.isActivated = !1;
974
+ }
975
+ /** Process activation command */
976
+ async processActivation(e) {
977
+ var i;
978
+ const t = (i = this.config.activationCommand) == null ? void 0 : i.toLowerCase();
979
+ t && (e === t ? (console.log("AssistantService: Activation matched."), this.isActivated = !0, this.textToSpeech.speak(
980
+ this.config.introMessage || this.defaultIntroMessage
981
+ )) : console.log("AssistantService: Activation command not recognized."));
982
+ }
983
+ /** Handle recognized commands */
984
+ async handleCommand(e) {
985
+ this.overlayManager.showLoading();
986
+ const t = await this.commandHandler.executeCommand(e);
987
+ this.overlayManager.hideLoading(), t.message && this.overlayManager.addMessage(t.message, "system"), t.type === "form" && t.fields ? this.overlayManager.addForm(
988
+ t.message,
989
+ t.fields,
990
+ async (i) => {
991
+ this.overlayManager.showLoading();
992
+ const s = await this.commandHandler.executeCommand(i);
993
+ this.overlayManager.hideLoading(), this.processResponse(s);
994
+ }
995
+ ) : t.type === "ambiguous" && t.options ? this.overlayManager.addOptions(t.options) : t.type === "error" && this.fallbackHandler.handleFallback(e);
996
+ }
997
+ /**
998
+ * Cleanup resources
999
+ */
1000
+ destroy() {
1001
+ this.voiceProcessor.stopListening(), this.overlayManager.destroy();
1002
+ }
1003
+ /** Unified response processing */
1004
+ processResponse(e) {
1005
+ e.message && this.overlayManager.addMessage(e.message, "system"), e.type === "form" && e.fields ? this.overlayManager.addForm(
1006
+ e.message,
1007
+ e.fields,
1008
+ async (t) => {
1009
+ this.overlayManager.showLoading();
1010
+ const i = await this.commandHandler.executeCommand(t);
1011
+ this.overlayManager.hideLoading(), this.processResponse(i);
1012
+ }
1013
+ ) : e.type === "ambiguous" && e.options && this.overlayManager.addOptions(e.options);
1014
+ }
1015
+ /** Add a command dynamically (supports string or rich object) */
1016
+ addCommand(e, t) {
1017
+ console.log(typeof e == "string" ? `AssistantService: Adding command "${e}".` : `AssistantService: Adding rich command "${e.command}".`), this.commandHandler.addCommand(e, t);
1018
+ }
1019
+ /** Remove a command dynamically */
1020
+ removeCommand(e) {
1021
+ console.log(`AssistantService: Removing command "${e}".`), this.commandHandler.removeCommand(e);
1022
+ }
1023
+ /** Get all registered commands */
1024
+ getCommands() {
1025
+ return this.commandHandler.getCommands();
1026
+ }
1027
+ /** Toggle the assistant overlay */
1028
+ toggle(e, t) {
1029
+ console.log("AssistantService: Toggling overlay..."), this.overlayManager.toggle(
1030
+ async (i) => {
1031
+ this.overlayManager.addMessage(i, "user"), e && e(i), await this.handleCommand(i);
1032
+ },
1033
+ () => {
1034
+ console.log("AssistantService: Overlay closed."), t && t();
1035
+ }
1036
+ );
1037
+ }
1038
+ }
1039
+ const S = A(null);
1040
+ let b = null;
1041
+ const z = ({ config: r, children: e }) => {
1042
+ const [t, i] = x(null), [s, c] = x(!1);
1043
+ return w(() => {
1044
+ b ? console.warn("Multiple AssistantProvider instances detected. Reusing global AssistantService.") : (console.log("Initializing global AssistantService..."), b = new $(r));
1045
+ const o = b;
1046
+ return i(o), o.startListening(), c(!0), () => {
1047
+ var a;
1048
+ console.log("Cleaning up AssistantService..."), (a = o.destroy) == null || a.call(o), b = null;
1049
+ };
1050
+ }, [r]), !s || !t ? /* @__PURE__ */ u("div", { children: "Loading Assistant..." }) : /* @__PURE__ */ u(S.Provider, { value: t, children: e });
1051
+ }, F = () => {
1052
+ const r = I(S);
1053
+ if (console.log("assistant", r), !r)
1054
+ throw new Error("useAssistant must be used within an AssistantProvider");
1055
+ return r;
1056
+ }, U = ({
1057
+ label: r = "Activate Assistant",
1058
+ onActivate: e
1059
+ }) => {
1060
+ const t = F();
1061
+ return /* @__PURE__ */ u("button", { onClick: () => {
1062
+ e && e(), t.reactivate();
1063
+ }, className: "assistant-activator", children: r });
1064
+ }, j = (r) => {
1065
+ const [e, t] = x(r.getState());
1066
+ return w(() => {
1067
+ const i = (s) => {
1068
+ t(s);
1069
+ };
1070
+ return r.subscribe(i), () => {
1071
+ r.subscribe(() => {
1072
+ });
1073
+ };
1074
+ }, [r]), e;
1075
+ };
1076
+ export {
1077
+ U as AssistantActivator,
1078
+ S as AssistantContext,
1079
+ z as AssistantProvider,
1080
+ $ as AssistantService,
1081
+ Y as ReactWrapper,
1082
+ F as useAssistant,
1083
+ j as useAssistantState
1084
+ };