@foisit/react-wrapper 2.1.2 → 2.4.1

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 CHANGED
@@ -1,253 +1,314 @@
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!" }) });
1
+ import { jsx as k } from "react/jsx-runtime";
2
+ import { createContext as F, useState as R, useEffect as P, useContext as N } from "react";
3
+ const W = {};
4
+ function J() {
5
+ return /* @__PURE__ */ k("div", { className: W.container, children: /* @__PURE__ */ k("h1", { children: "Welcome to ReactWrapper!" }) });
6
6
  }
7
- class L {
8
- constructor() {
9
- this.endpoint = "https://foisit-ninja.netlify.app/.netlify/functions/intent";
7
+ class M {
8
+ constructor(t) {
9
+ this.endpoint = t || "https://foisit-ninja.netlify.app/.netlify/functions/intent";
10
10
  }
11
- /**
12
- * Determine the best matching command by calling the internalized proxy
13
- */
14
- async determineIntent(e, t, i) {
11
+ async determineIntent(t, e, i) {
15
12
  try {
16
- const s = await fetch(this.endpoint, {
13
+ const s = {
14
+ userInput: t,
15
+ commands: e.map((r) => ({
16
+ id: r.id,
17
+ command: r.command,
18
+ description: r.description,
19
+ parameters: r.parameters
20
+ // Send param schemas to AI
21
+ })),
22
+ context: i
23
+ }, n = await fetch(this.endpoint, {
17
24
  method: "POST",
18
25
  headers: {
19
26
  "Content-Type": "application/json"
20
27
  },
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
- })
28
+ body: JSON.stringify(s)
32
29
  });
33
- if (!s.ok)
34
- throw new Error("Proxy API request failed");
35
- return await s.json();
30
+ if (!n.ok)
31
+ throw new Error(`Proxy API Error: ${n.statusText}`);
32
+ return await n.json();
36
33
  } catch (s) {
37
- return console.error("Foisit AI Error:", s), { type: "unknown" };
34
+ return console.error("OpenAIService Error:", s), { type: "unknown" };
38
35
  }
39
36
  }
40
37
  }
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();
38
+ class B {
39
+ constructor(t = !0) {
40
+ if (this.commands = /* @__PURE__ */ new Map(), this.openAIService = null, this.context = null, this.pendingConfirmation = null, this.enableSmartIntent = !0, this.selectOptionsCache = /* @__PURE__ */ new Map(), typeof t == "boolean") {
41
+ this.enableSmartIntent = t, this.enableSmartIntent && (this.openAIService = new M());
42
+ return;
43
+ }
44
+ this.enableSmartIntent = t.enableSmartIntent ?? !0, this.enableSmartIntent && (this.openAIService = new M(t.intentEndpoint));
44
45
  }
45
- /**
46
- * Add a new command (supports simple string or rich object)
47
- */
48
- addCommand(e, t) {
46
+ /** Add a new command (string or object) */
47
+ addCommand(t, e) {
49
48
  let i;
50
- if (typeof e == "string") {
51
- if (!t)
52
- throw new Error("Action is required when passing a command string.");
49
+ if (typeof t == "string") {
50
+ if (!e)
51
+ throw new Error("Action required when adding command by string.");
53
52
  i = {
54
- command: e,
55
- action: t,
56
- id: `cmd_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
57
- // Auto-gen ID
53
+ id: t.toLowerCase().replace(/\s+/g, "_"),
54
+ command: t.toLowerCase(),
55
+ action: e
58
56
  };
59
57
  } 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);
58
+ i = { ...t }, i.id || (i.id = i.command.toLowerCase().replace(/\s+/g, "_"));
59
+ this.commands.set(i.command.toLowerCase(), i), i.id && (i.id, i.command);
60
+ }
61
+ /** Remove an existing command */
62
+ removeCommand(t) {
63
+ this.commands.delete(t.toLowerCase());
64
+ }
65
+ /** Execute a command by matching input */
66
+ async executeCommand(t) {
67
+ if (typeof t == "object" && t !== null) {
68
+ if (this.isStructured(t)) {
69
+ const c = String(t.commandId), f = t.params ?? {}, o = this.getCommandById(c);
70
+ if (!o) return { message: "That command is not available.", type: "error" };
71
+ const p = this.sanitizeParamsForCommand(o, f), h = (o.parameters ?? []).filter((C) => C.required).filter((C) => p[C.name] == null || p[C.name] === "");
72
+ return h.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(o), params: p }, {
73
+ message: `Please provide the required details for "${o.command}".`,
74
+ type: "form",
75
+ fields: h
76
+ }) : o.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(o), params: p }, this.buildConfirmResponse(o)) : this.safeRunAction(o, p);
82
77
  }
78
+ if (!this.context)
79
+ return { message: "Session expired or invalid context.", type: "error" };
80
+ const n = this.getCommandById(this.context.commandId);
81
+ if (!n)
82
+ return this.context = null, { message: "Session expired or invalid context.", type: "error" };
83
+ if (Array.isArray(t))
84
+ return { message: "Invalid form payload.", type: "error" };
85
+ const a = {
86
+ ...this.context.params,
87
+ ...t
88
+ };
89
+ if (n.critical)
90
+ return this.context = null, this.pendingConfirmation = {
91
+ commandId: this.getCommandIdentifier(n),
92
+ params: a
93
+ }, this.buildConfirmResponse(n);
94
+ const r = await this.safeRunAction(n, a);
95
+ return this.context = null, this.normalizeResponse(r);
83
96
  }
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}?`,
97
+ const e = t.trim().toLowerCase();
98
+ if (this.pendingConfirmation) {
99
+ const n = e;
100
+ if (["yes", "y", "confirm", "ok", "okay"].includes(n)) {
101
+ const { commandId: a, params: r } = this.pendingConfirmation;
102
+ this.pendingConfirmation = null;
103
+ const c = this.getCommandById(a);
104
+ return c ? this.safeRunAction(c, r) : { message: "That action is no longer available.", type: "error" };
105
+ }
106
+ return ["no", "n", "cancel", "stop"].includes(n) ? (this.pendingConfirmation = null, { message: "✅ Cancelled.", type: "success" }) : {
107
+ message: "Please confirm: Yes or No.",
108
+ type: "confirm",
92
109
  options: [
93
110
  { label: "Yes", value: "yes" },
94
111
  { label: "No", value: "no" }
95
112
  ]
96
113
  };
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
114
  }
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
115
+ const i = this.commands.get(e);
116
+ if (i) {
117
+ const n = i, a = (n.parameters ?? []).filter((r) => r.required);
118
+ return a.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
119
+ message: `Please provide the required details for "${n.command}".`,
120
+ type: "form",
121
+ fields: a
122
+ }) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
123
+ }
124
+ const s = await this.tryDeterministicMatch(e);
125
+ if (s) return s;
126
+ if (this.enableSmartIntent && this.openAIService) {
127
+ const n = await this.getCommandsForAI(), a = await this.openAIService.determineIntent(
128
+ e,
129
+ n,
130
+ this.context
145
131
  );
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 || {}
132
+ return this.handleAIResult(a);
133
+ }
134
+ return this.enableSmartIntent ? this.listAllCommands() : { message: "I'm not sure what you mean.", type: "error" };
135
+ }
136
+ async handleAIResult(t) {
137
+ if (t.type === "match" && t.match) {
138
+ const e = this.getCommandById(t.match);
139
+ if (!e)
140
+ return { message: "I'm not sure what you mean.", type: "error" };
141
+ const i = t.params ?? {}, s = this.sanitizeParamsForCommand(e, i), a = (e.parameters ?? []).filter((c) => c.required).filter((c) => s[c.name] == null || s[c.name] === "");
142
+ if (t.incomplete || a.length > 0) {
143
+ this.context = { commandId: this.getCommandIdentifier(e), params: s };
144
+ const c = a.some((f) => f.type === "select");
145
+ if (a.length <= 2 && !c) {
146
+ const f = a.map((o) => o.name).join(" and ");
147
+ return {
148
+ message: t.message || `Please provide ${f}.`,
149
+ type: "question"
152
150
  };
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
151
  }
200
- } else if (o.type === "ambiguous" && o.options)
201
152
  return {
202
- type: "ambiguous",
203
- message: "Did you mean...",
204
- options: o.options.map((a) => ({
205
- label: a.label,
206
- value: a.label
207
- }))
153
+ message: t.message || `Please fill in the missing details for "${e.command}".`,
154
+ type: "form",
155
+ fields: a
208
156
  };
157
+ }
158
+ if (e.critical)
159
+ return this.pendingConfirmation = {
160
+ commandId: this.getCommandIdentifier(e),
161
+ params: s
162
+ }, this.buildConfirmResponse(e);
163
+ const r = await e.action(s);
164
+ return this.normalizeResponse(r);
209
165
  }
210
- return {
166
+ return t.type === "ambiguous" && t.options && t.options.length ? {
167
+ message: t.message || "Did you mean one of these?",
211
168
  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
169
+ options: t.options.map((e) => ({
170
+ label: e.label,
171
+ value: e.commandId ?? e.label,
172
+ commandId: e.commandId
216
173
  }))
174
+ } : this.listAllCommands();
175
+ }
176
+ sanitizeParamsForCommand(t, e) {
177
+ const i = { ...e ?? {} };
178
+ for (const s of t.parameters ?? [])
179
+ if (s.type === "date") {
180
+ const n = i[s.name];
181
+ if (typeof n == "string") {
182
+ const a = n.trim();
183
+ this.isIsoDateString(a) || delete i[s.name];
184
+ }
185
+ }
186
+ return i;
187
+ }
188
+ isIsoDateString(t) {
189
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(t)) return !1;
190
+ const e = /* @__PURE__ */ new Date(`${t}T00:00:00Z`);
191
+ return !Number.isNaN(e.getTime());
192
+ }
193
+ buildConfirmResponse(t) {
194
+ return {
195
+ message: `⚠️ Are you sure you want to run "${t.command}"?`,
196
+ type: "confirm",
197
+ options: [
198
+ { label: "Yes", value: "yes" },
199
+ { label: "No", value: "no" }
200
+ ]
217
201
  };
218
202
  }
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) {
203
+ async tryDeterministicMatch(t) {
204
+ const e = [];
205
+ for (const r of this.commands.values()) {
206
+ let c = 0;
207
+ const f = r.command.toLowerCase();
208
+ t.includes(f) && (c += 5);
209
+ const o = r.keywords ?? [];
210
+ for (const p of o) {
211
+ const b = p.toLowerCase().trim();
212
+ b && (t === b ? c += 4 : t.includes(b) && (c += 3));
213
+ }
214
+ c > 0 && e.push({ cmd: r, score: c });
215
+ }
216
+ if (e.length === 0) return null;
217
+ e.sort((r, c) => c.score - r.score);
218
+ const i = e[0].score, s = e.filter((r) => r.score === i).slice(0, 3);
219
+ if (s.length > 1)
228
220
  return {
229
- type: "error",
230
- message: i.message || "An error occurred during execution."
221
+ message: "I think you mean one of these. Which one should I run?",
222
+ type: "ambiguous",
223
+ options: s.map((r) => ({
224
+ label: r.cmd.command,
225
+ value: r.cmd.command,
226
+ commandId: r.cmd.id
227
+ }))
231
228
  };
229
+ const n = s[0].cmd, a = (n.parameters ?? []).filter((r) => r.required);
230
+ return a.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
231
+ message: `Please provide the required details for "${n.command}".`,
232
+ type: "form",
233
+ fields: a
234
+ }) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
235
+ }
236
+ async safeRunAction(t, e) {
237
+ try {
238
+ const i = await t.action(e ?? {});
239
+ return this.normalizeResponse(i);
240
+ } catch {
241
+ return { message: "Something went wrong while running that command.", type: "error" };
232
242
  }
233
243
  }
244
+ async getCommandsForAI() {
245
+ const t = Array.from(this.commands.values()).map((e) => ({
246
+ ...e,
247
+ parameters: e.parameters ? e.parameters.map((i) => ({ ...i })) : void 0
248
+ }));
249
+ return await Promise.all(
250
+ t.map(async (e) => {
251
+ e.parameters && await Promise.all(
252
+ e.parameters.map(async (i) => {
253
+ if (i.type !== "select" || !i.getOptions || i.options && i.options.length) return;
254
+ const s = `${e.id ?? e.command}:${i.name}`, n = this.selectOptionsCache.get(s), a = Date.now();
255
+ if (n && a - n.ts < 6e4) {
256
+ i.options = n.options;
257
+ return;
258
+ }
259
+ try {
260
+ const r = await i.getOptions();
261
+ this.selectOptionsCache.set(s, { options: r, ts: a }), i.options = r;
262
+ } catch {
263
+ }
264
+ })
265
+ );
266
+ })
267
+ ), t;
268
+ }
269
+ getCommandById(t) {
270
+ for (const e of this.commands.values())
271
+ if (e.id === t) return e;
272
+ }
273
+ listAllCommands() {
274
+ return {
275
+ message: "Here are the available commands:",
276
+ type: "ambiguous",
277
+ options: Array.from(this.commands.values()).map((e) => ({
278
+ label: e.command,
279
+ value: e.id ?? e.command,
280
+ commandId: e.id ?? e.command
281
+ }))
282
+ };
283
+ }
284
+ normalizeResponse(t) {
285
+ return typeof t == "string" ? { message: t, type: "success" } : t && typeof t == "object" ? t : { message: "Done", type: "success" };
286
+ }
287
+ isStructured(t) {
288
+ return typeof t.commandId == "string";
289
+ }
290
+ getCommandIdentifier(t) {
291
+ return t.id || (t.id = t.command.toLowerCase().replace(/\s+/g, "_")), t.id;
292
+ }
234
293
  /** List all registered commands */
235
294
  getCommands() {
236
295
  return Array.from(this.commands.keys());
237
296
  }
238
297
  }
239
- class k {
298
+ class H {
240
299
  constructor() {
241
300
  this.synth = window.speechSynthesis;
242
301
  }
243
- speak(e, t) {
302
+ speak(t, e) {
244
303
  if (!this.synth) {
245
304
  console.error("SpeechSynthesis API is not supported in this browser.");
246
305
  return;
247
306
  }
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.");
307
+ const i = new SpeechSynthesisUtterance(t);
308
+ e && (i.pitch = e.pitch || 1, i.rate = e.rate || 1, i.volume = e.volume || 1), i.onstart = () => {
309
+ window.dispatchEvent(new CustomEvent("foisit:tts-start"));
310
+ }, i.onend = () => {
311
+ console.log("Speech finished."), window.dispatchEvent(new CustomEvent("foisit:tts-end"));
251
312
  }, i.onerror = (s) => {
252
313
  console.error("Error during speech synthesis:", s.error);
253
314
  }, this.synth.speak(i);
@@ -256,53 +317,191 @@ class k {
256
317
  this.synth && this.synth.cancel();
257
318
  }
258
319
  }
259
- class P {
320
+ class O {
260
321
  constructor() {
261
322
  this.fallbackMessage = "Sorry, I didn’t understand that.";
262
323
  }
263
- setFallbackMessage(e) {
264
- this.fallbackMessage = e;
324
+ setFallbackMessage(t) {
325
+ this.fallbackMessage = t;
265
326
  }
266
- handleFallback(e) {
267
- console.log(this.fallbackMessage), new k().speak(this.fallbackMessage);
327
+ handleFallback(t) {
328
+ t && console.log(`Fallback triggered for: "${t}"`), console.log(this.fallbackMessage), new H().speak(this.fallbackMessage);
329
+ }
330
+ getFallbackMessage() {
331
+ return this.fallbackMessage;
268
332
  }
269
333
  }
270
- class T {
271
- constructor(e = "en-US") {
272
- this.isListening = !1, this.isStoppedSpeechRecog = !1, this.restartAllowed = !0;
334
+ const T = () => {
335
+ const d = window;
336
+ return d.SpeechRecognition ?? d.webkitSpeechRecognition ?? null;
337
+ };
338
+ class z {
339
+ constructor(t = "en-US", e = {}) {
340
+ this.recognition = null, this.isListening = !1, this.engineActive = !1, this.intentionallyStopped = !1, this.restartAllowed = !0, this.lastStart = 0, this.backoffMs = 250, this.destroyed = !1, this.resultCallback = null, this.ttsSpeaking = !1, this.debugEnabled = !0, this.restartTimer = null, this.prewarmed = !1, this.hadResultThisSession = !1, this.onTTSStart = () => {
341
+ var s;
342
+ this.ttsSpeaking = !0;
343
+ try {
344
+ (s = this.recognition) == null || s.stop();
345
+ } catch {
346
+ }
347
+ this.isListening && this.emitStatus("speaking");
348
+ }, this.onTTSEnd = () => {
349
+ this.ttsSpeaking = !1, this.isListening && this.restartAllowed ? this.safeRestart() : this.emitStatus(this.isListening ? "listening" : "idle");
350
+ };
351
+ const i = T();
352
+ if (i) {
353
+ this.recognition = new i(), this.recognition.lang = t, this.recognition.interimResults = e.interimResults ?? !0, this.recognition.continuous = e.continuous ?? !0, this.recognition.onresult = (n) => this.handleResult(n, e), this.recognition.onend = () => this.handleEnd(), this.recognition.onstart = () => {
354
+ this.log("recognition onstart"), this.engineActive = !0, this.hadResultThisSession = !1, this.restartTimer && (clearTimeout(this.restartTimer), this.restartTimer = null), this.backoffMs = 250, this.isListening && !this.ttsSpeaking && this.emitStatus("listening");
355
+ };
356
+ const s = this.recognition;
357
+ s.onaudiostart = () => this.log("onaudiostart"), s.onsoundstart = () => this.log("onsoundstart"), s.onspeechstart = () => this.log("onspeechstart"), s.onspeechend = () => this.log("onspeechend"), s.onsoundend = () => this.log("onsoundend"), s.onaudioend = () => this.log("onaudioend"), this.recognition.onerror = (n) => this.handleError(n);
358
+ } else
359
+ this.recognition = null, this.emitStatus("unsupported");
360
+ window.addEventListener("foisit:tts-start", this.onTTSStart), window.addEventListener("foisit:tts-end", this.onTTSEnd), this.visibilityHandler = () => {
361
+ var s;
362
+ if (document.hidden) {
363
+ try {
364
+ (s = this.recognition) == null || s.stop();
365
+ } catch {
366
+ }
367
+ this.emitStatus(this.ttsSpeaking ? "speaking" : "idle");
368
+ } else this.isListening && !this.ttsSpeaking && this.safeRestart();
369
+ }, document.addEventListener("visibilitychange", this.visibilityHandler);
370
+ }
371
+ // Debug logger helpers
372
+ log(t) {
373
+ this.debugEnabled && t && console.log("[VoiceProcessor]", t);
374
+ }
375
+ warn(t) {
376
+ this.debugEnabled && t && console.warn("[VoiceProcessor]", t);
377
+ }
378
+ error(t) {
379
+ this.debugEnabled && t && console.error("[VoiceProcessor]", t);
380
+ }
381
+ /** Check if SpeechRecognition is available */
382
+ isSupported() {
383
+ return T() !== null;
384
+ }
385
+ /** Allow consumers (wrappers) to observe status changes */
386
+ onStatusChange(t) {
387
+ this.statusCallback = t;
273
388
  }
274
389
  /** Start listening for speech input */
275
- startListening(e) {
276
- console.warn("VoiceProcessor: Voice interaction is currently DISABLED.");
390
+ startListening(t) {
391
+ if (!this.isSupported() || !this.recognition) {
392
+ this.warn("VoiceProcessor: SpeechRecognition is not supported in this browser."), this.emitStatus("unsupported");
393
+ return;
394
+ }
395
+ if (this.isListening) {
396
+ this.warn("VoiceProcessor: Already listening."), this.resultCallback = t;
397
+ return;
398
+ }
399
+ this.resultCallback = t, this.intentionallyStopped = !1, this.restartAllowed = !0, this.isListening = !0, this.emitStatus("listening"), this.prewarmAudio().finally(() => {
400
+ this.safeRestart();
401
+ });
277
402
  }
278
403
  /** Stop listening for speech input */
279
404
  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
- }
405
+ var t;
406
+ this.intentionallyStopped = !0, this.restartAllowed = !1, this.isListening = !1, this.emitStatus(this.ttsSpeaking ? "speaking" : "idle");
284
407
  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);
408
+ (t = this.recognition) == null || t.stop();
409
+ } catch {
288
410
  }
289
411
  }
412
+ /** Clean up listeners */
413
+ destroy() {
414
+ this.destroyed = !0, this.stopListening(), this.resultCallback = null, window.removeEventListener("foisit:tts-start", this.onTTSStart), window.removeEventListener("foisit:tts-end", this.onTTSEnd), this.visibilityHandler && (document.removeEventListener("visibilitychange", this.visibilityHandler), this.visibilityHandler = void 0);
415
+ }
290
416
  /** Handle recognized speech results */
291
- handleResult(e, t) {
417
+ handleResult(t, e) {
418
+ var s, n;
419
+ if (!this.resultCallback) return;
420
+ const i = e.confidenceThreshold ?? 0.6;
421
+ for (let a = t.resultIndex; a < t.results.length; a++) {
422
+ const r = t.results[a], c = r && r[0], f = ((n = (s = c == null ? void 0 : c.transcript) == null ? void 0 : s.trim) == null ? void 0 : n.call(s)) || "", o = (c == null ? void 0 : c.confidence) ?? 0;
423
+ if (f && !(!r.isFinal && e.interimResults === !1) && !(r.isFinal && o < i))
424
+ try {
425
+ this.hadResultThisSession = !0, this.resultCallback(f, !!r.isFinal);
426
+ } catch {
427
+ this.error("VoiceProcessor: result callback error");
428
+ }
429
+ }
292
430
  }
293
431
  /** Handle session end */
294
432
  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));
433
+ if (this.log("recognition onend"), this.engineActive = !1, this.destroyed || this.intentionallyStopped || !this.restartAllowed || this.ttsSpeaking) {
434
+ this.ttsSpeaking || (this.isListening = !1, this.emitStatus("idle"));
435
+ return;
436
+ }
437
+ this.isListening = !0, this.scheduleRestart();
299
438
  }
300
439
  /** 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;
440
+ handleError(t) {
441
+ const e = t == null ? void 0 : t.error;
442
+ if (this.warn(`Error occurred: ${e ?? "unknown"}`), e && ["not-allowed", "service-not-allowed", "bad-grammar", "language-not-supported"].includes(e)) {
443
+ this.intentionallyStopped = !0, this.restartAllowed = !1, this.isListening = !1, this.emitStatus("error", { error: e });
444
+ return;
445
+ }
446
+ this.scheduleRestart();
447
+ }
448
+ safeRestart() {
449
+ if (!this.recognition) return;
450
+ if (this.engineActive) {
451
+ this.log("safeRestart: engine already active, skipping start");
452
+ return;
453
+ }
454
+ const t = Date.now();
455
+ if (t - this.lastStart < 300) {
456
+ setTimeout(() => this.safeRestart(), 300);
457
+ return;
458
+ }
459
+ this.lastStart = t;
460
+ try {
461
+ this.log("calling recognition.start()"), this.recognition.start(), this.backoffMs = 250, this.isListening && !this.ttsSpeaking && this.emitStatus("listening");
462
+ } catch {
463
+ this.error("recognition.start() threw; scheduling restart"), this.scheduleRestart();
464
+ }
465
+ }
466
+ scheduleRestart() {
467
+ if (this.destroyed || this.intentionallyStopped || !this.restartAllowed || this.ttsSpeaking) return;
468
+ if (this.engineActive) {
469
+ this.log("scheduleRestart: engine active, not scheduling");
470
+ return;
471
+ }
472
+ const t = Math.min(this.backoffMs, 2e3);
473
+ if (this.log(`scheduleRestart in ${t}ms`), this.restartTimer) {
474
+ this.log("scheduleRestart: restart already scheduled");
475
+ return;
476
+ }
477
+ this.restartTimer = setTimeout(() => {
478
+ this.restartTimer = null, !(this.destroyed || this.intentionallyStopped || !this.restartAllowed || this.ttsSpeaking) && this.safeRestart();
479
+ }, t), this.backoffMs = Math.min(this.backoffMs * 2, 2e3);
480
+ }
481
+ async prewarmAudio() {
482
+ if (!this.prewarmed)
483
+ try {
484
+ if (typeof navigator > "u" || !("mediaDevices" in navigator)) return;
485
+ const t = navigator.mediaDevices;
486
+ if (!(t != null && t.getUserMedia)) return;
487
+ this.log("prewarmAudio: requesting mic");
488
+ const e = await t.getUserMedia({ audio: !0 });
489
+ for (const i of e.getTracks()) i.stop();
490
+ this.prewarmed = !0, this.log("prewarmAudio: mic ready");
491
+ } catch {
492
+ this.warn("prewarmAudio: failed to get mic");
493
+ }
494
+ }
495
+ emitStatus(t, e) {
496
+ if (this.statusCallback)
497
+ try {
498
+ this.statusCallback(t, e);
499
+ } catch {
500
+ this.error("VoiceProcessor: status callback error");
501
+ }
303
502
  }
304
503
  }
305
- class B {
504
+ class $ {
306
505
  constructor() {
307
506
  this.lastTap = 0;
308
507
  }
@@ -310,13 +509,16 @@ class B {
310
509
  * Sets up double-click and double-tap listeners
311
510
  * @param onDoubleClickOrTap Callback to execute when a double-click or double-tap is detected
312
511
  */
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
- });
512
+ setupDoubleTapListener(t) {
513
+ this.destroy(), this.dblClickListener = () => {
514
+ t();
515
+ }, document.addEventListener("dblclick", this.dblClickListener), this.touchEndListener = () => {
516
+ const e = (/* @__PURE__ */ new Date()).getTime(), i = e - this.lastTap;
517
+ i < 300 && i > 0 && t(), this.lastTap = e;
518
+ }, document.addEventListener("touchend", this.touchEndListener);
519
+ }
520
+ destroy() {
521
+ this.dblClickListener && document.removeEventListener("dblclick", this.dblClickListener), this.touchEndListener && document.removeEventListener("touchend", this.touchEndListener), this.dblClickListener = void 0, this.touchEndListener = void 0;
320
522
  }
321
523
  }
322
524
  function D() {
@@ -324,8 +526,8 @@ function D() {
324
526
  console.log("Styles already injected");
325
527
  return;
326
528
  }
327
- const e = document.createElement("style");
328
- e.id = "assistant-styles", e.innerHTML = `
529
+ const t = document.createElement("style");
530
+ t.id = "assistant-styles", t.innerHTML = `
329
531
  /* Rounded shape with gradient animation */
330
532
  .gradient-indicator {
331
533
  position: fixed;
@@ -358,727 +560,862 @@ function D() {
358
560
  border-radius: 50%;
359
561
  }
360
562
  }
361
- `, document.head.appendChild(e), console.log("Gradient styles injected");
563
+ `, document.head.appendChild(t), console.log("Gradient styles injected");
362
564
  }
363
- function R() {
565
+ function j() {
364
566
  if (document.querySelector("#gradient-indicator"))
365
567
  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");
568
+ const d = document.createElement("div");
569
+ d.id = "gradient-indicator", D(), d.classList.add("gradient-indicator"), document.body.appendChild(d), console.log("Gradient indicator added to the DOM");
368
570
  }
369
- function H() {
370
- const r = document.querySelector("#gradient-indicator");
371
- r && (r.remove(), console.log("Gradient indicator removed from the DOM"));
571
+ function U() {
572
+ const d = document.querySelector("#gradient-indicator");
573
+ d && (d.remove(), console.log("Gradient indicator removed from the DOM"));
372
574
  }
373
- class N {
575
+ class V {
374
576
  constructor() {
375
577
  this.state = "idle", this.subscribers = [];
376
578
  }
377
579
  getState() {
378
580
  return this.state;
379
581
  }
380
- setState(e) {
381
- this.state = e, this.notifySubscribers(), console.log("State updated:", e), e === "listening" ? R() : H();
582
+ setState(t) {
583
+ this.state = t, this.notifySubscribers(), console.log("State updated:", t), t === "listening" ? j() : U();
382
584
  }
383
585
  // eslint-disable-next-line no-unused-vars
384
- subscribe(e) {
385
- this.subscribers.push(e);
586
+ subscribe(t) {
587
+ this.subscribers.push(t);
386
588
  }
387
589
  notifySubscribers() {
388
- this.subscribers.forEach((e) => e(this.state));
590
+ this.subscribers.forEach((t) => t(this.state));
389
591
  }
390
592
  }
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
- );
593
+ class G {
594
+ constructor(t) {
595
+ this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1, this.loadingEl = null, this.config = t, this.init();
396
596
  }
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;
597
+ init() {
598
+ var e, i;
599
+ if (this.container) return;
600
+ this.injectOverlayStyles();
601
+ const t = document.getElementById("foisit-overlay-container");
602
+ if (t && t instanceof HTMLElement) {
603
+ this.container = t, this.chatWindow = t.querySelector(".foisit-chat"), this.messagesContainer = t.querySelector(".foisit-messages"), this.input = t.querySelector("input.foisit-input"), ((e = this.config.floatingButton) == null ? void 0 : e.visible) !== !1 && !t.querySelector(".foisit-floating-btn") && this.renderFloatingButton(), this.chatWindow || this.renderChatWindow();
604
+ return;
605
+ }
606
+ this.container = document.createElement("div"), this.container.id = "foisit-overlay-container", this.container.className = "foisit-overlay-container", document.body.appendChild(this.container), ((i = this.config.floatingButton) == null ? void 0 : i.visible) !== !1 && this.renderFloatingButton(), this.renderChatWindow();
407
607
  }
408
- /**
409
- * Register callbacks for the overlay (used by floating button)
410
- */
411
- registerCallbacks(e, t) {
412
- this.submitCallback = e, this.closeCallback = t || null;
608
+ renderFloatingButton() {
609
+ var s, n, a, r, c, f;
610
+ const t = document.createElement("button");
611
+ t.innerHTML = ((s = this.config.floatingButton) == null ? void 0 : s.customHtml) || "🎙️";
612
+ const e = ((a = (n = this.config.floatingButton) == null ? void 0 : n.position) == null ? void 0 : a.bottom) || "20px", i = ((c = (r = this.config.floatingButton) == null ? void 0 : r.position) == null ? void 0 : c.right) || "20px";
613
+ t.className = "foisit-floating-btn", t.style.bottom = e, t.style.right = i, t.onclick = () => this.toggle(), t.onmouseenter = () => t.style.transform = "scale(1.05)", t.onmouseleave = () => t.style.transform = "scale(1)", (f = this.container) == null || f.appendChild(t);
413
614
  }
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);
615
+ renderChatWindow() {
616
+ var n;
617
+ if (this.chatWindow) return;
618
+ this.chatWindow = document.createElement("div"), this.chatWindow.className = "foisit-chat";
619
+ const t = document.createElement("div");
620
+ t.className = "foisit-header";
621
+ const e = document.createElement("span");
622
+ e.className = "foisit-title", e.textContent = "Foisit";
623
+ const i = document.createElement("button");
624
+ i.type = "button", i.className = "foisit-close", i.setAttribute("aria-label", "Close"), i.innerHTML = "&times;", i.addEventListener("click", () => this.toggle()), t.appendChild(e), t.appendChild(i), this.messagesContainer = document.createElement("div"), this.messagesContainer.className = "foisit-messages";
625
+ const s = document.createElement("div");
626
+ s.className = "foisit-input-area", this.input = document.createElement("input"), this.input.placeholder = this.config.inputPlaceholder || "Type a command...", this.input.className = "foisit-input", this.input.addEventListener("keydown", (a) => {
627
+ var r;
628
+ if (a.key === "Enter" && ((r = this.input) != null && r.value.trim())) {
629
+ const c = this.input.value.trim();
630
+ this.input.value = "", this.onSubmit && this.onSubmit(c);
631
+ }
632
+ }), s.appendChild(this.input), this.chatWindow.appendChild(t), this.chatWindow.appendChild(this.messagesContainer), this.chatWindow.appendChild(s), (n = this.container) == null || n.appendChild(this.chatWindow);
426
633
  }
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());
634
+ registerCallbacks(t, e) {
635
+ this.onSubmit = t, this.onClose = e;
435
636
  }
436
- /**
437
- * Toggle the overlay
438
- */
439
- toggle(e, t) {
440
- this.isOpen ? this.hide() : this.show(e, t);
637
+ toggle(t, e) {
638
+ t && (this.onSubmit = t), e && (this.onClose = e), this.isOpen = !this.isOpen, this.chatWindow && (this.isOpen ? (this.chatWindow.style.display = "flex", requestAnimationFrame(() => {
639
+ this.chatWindow && (this.chatWindow.style.opacity = "1", this.chatWindow.style.transform = "translateY(0) scale(1)");
640
+ }), setTimeout(() => {
641
+ var i;
642
+ return (i = this.input) == null ? void 0 : i.focus();
643
+ }, 100)) : (this.chatWindow.style.opacity = "0", this.chatWindow.style.transform = "translateY(20px) scale(0.95)", setTimeout(() => {
644
+ this.chatWindow && !this.isOpen && (this.chatWindow.style.display = "none");
645
+ }, 200), this.onClose && this.onClose()));
441
646
  }
442
- /**
443
- * Add a message bubble to the chat
444
- */
445
- addMessage(e, t = "system") {
446
- if (!this.chatContainer) return;
647
+ addMessage(t, e) {
648
+ if (!this.messagesContainer) return;
447
649
  const i = document.createElement("div");
448
- i.className = `foisit-bubble ${t}`, i.textContent = e, this.chatContainer.appendChild(i), this.scrollToBottom();
650
+ i.textContent = t, i.className = e === "user" ? "foisit-bubble user" : "foisit-bubble system", this.messagesContainer.appendChild(i), this.scrollToBottom();
449
651
  }
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) => {
652
+ addOptions(t) {
653
+ if (!this.messagesContainer) return;
654
+ const e = document.createElement("div");
655
+ e.className = "foisit-options-container", t.forEach((i) => {
457
656
  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);
657
+ s.textContent = i.label, s.className = "foisit-option-chip", s.setAttribute("type", "button"), s.setAttribute("aria-label", i.label);
658
+ const n = () => {
659
+ if (i.commandId) {
660
+ this.onSubmit && this.onSubmit({ commandId: i.commandId });
661
+ return;
662
+ }
663
+ const a = i && typeof i.value == "string" && i.value.trim() ? i.value : i.label;
664
+ this.onSubmit && this.onSubmit(a);
665
+ };
666
+ s.onclick = n, s.onkeydown = (a) => {
667
+ (a.key === "Enter" || a.key === " ") && (a.preventDefault(), n());
668
+ }, e.appendChild(s);
669
+ }), this.messagesContainer.appendChild(e), this.scrollToBottom();
482
670
  }
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);
671
+ addForm(t, e, i) {
672
+ if (!this.messagesContainer) return;
673
+ this.addMessage(t, "system");
674
+ const s = document.createElement("form");
675
+ s.className = "foisit-form";
676
+ const n = [], a = (o, p) => {
677
+ const b = document.createElement("div");
678
+ return b.className = "foisit-form-label", b.innerHTML = o + (p ? ' <span class="foisit-req-star">*</span>' : ""), b;
679
+ }, r = () => {
680
+ const o = document.createElement("div");
681
+ return o.className = "foisit-form-error", o.style.display = "none", o;
682
+ };
683
+ (e ?? []).forEach((o) => {
684
+ const p = document.createElement("div");
685
+ p.className = "foisit-form-group";
686
+ const b = o.description || o.name;
687
+ p.appendChild(a(b, o.required));
688
+ let h;
689
+ if (o.type === "select") {
690
+ const l = document.createElement("select");
691
+ l.className = "foisit-form-input";
692
+ const y = document.createElement("option");
693
+ y.value = "", y.textContent = "Select...", l.appendChild(y);
694
+ const x = (m) => {
695
+ (m ?? []).forEach((w) => {
696
+ const g = document.createElement("option");
697
+ g.value = String(w.value ?? w.label ?? ""), g.textContent = String(w.label ?? w.value ?? ""), l.appendChild(g);
698
+ });
699
+ };
700
+ if (Array.isArray(o.options) && o.options.length)
701
+ x(o.options);
702
+ else if (typeof o.getOptions == "function") {
703
+ const m = o.getOptions, w = document.createElement("option");
704
+ w.value = "", w.textContent = "Loading...", l.appendChild(w), Promise.resolve().then(() => m()).then((g) => {
705
+ for (; l.options.length > 1; ) l.remove(1);
706
+ x(g);
707
+ }).catch(() => {
708
+ for (; l.options.length > 1; ) l.remove(1);
709
+ const g = document.createElement("option");
710
+ g.value = "", g.textContent = "Error loading options", l.appendChild(g);
711
+ });
712
+ }
713
+ o.defaultValue != null && (l.value = String(o.defaultValue)), h = l;
714
+ } else if (o.type === "file") {
715
+ const l = o, y = document.createElement("input");
716
+ y.className = "foisit-form-input", y.type = "file", l.accept && Array.isArray(l.accept) && (y.accept = l.accept.join(",")), l.multiple && (y.multiple = !0), l.capture && (l.capture === !0 ? y.setAttribute("capture", "") : y.setAttribute("capture", String(l.capture))), y.addEventListener("change", async () => {
717
+ const x = Array.from(y.files || []), m = C;
718
+ if (m.style.display = "none", m.textContent = "", x.length === 0) return;
719
+ const w = l.maxFiles ?? (l.multiple ? 10 : 1);
720
+ if (x.length > w) {
721
+ m.textContent = `Please select at most ${w} file(s).`, m.style.display = "block";
722
+ return;
723
+ }
724
+ const g = l.maxSizeBytes ?? 1 / 0, u = x.reduce((v, E) => v + E.size, 0);
725
+ if (x.some((v) => v.size > g)) {
726
+ m.textContent = `One or more files exceed the maximum size of ${Math.round(g / 1024)} KB.`, m.style.display = "block";
727
+ return;
728
+ }
729
+ const S = l.maxTotalBytes ?? 1 / 0;
730
+ if (u > S) {
731
+ m.textContent = `Total selected files exceed the maximum of ${Math.round(S / 1024)} KB.`, m.style.display = "block";
732
+ return;
733
+ }
734
+ if (l.accept && Array.isArray(l.accept)) {
735
+ const v = l.accept;
736
+ if (!x.every((A) => A.type ? v.some((L) => L.startsWith(".") ? A.name.toLowerCase().endsWith(L.toLowerCase()) : A.type === L || A.type.startsWith(L.split("/")[0] + "/")) : !0)) {
737
+ m.textContent = "One or more files have an unsupported type.", m.style.display = "block";
738
+ return;
739
+ }
740
+ }
741
+ }), h = y;
742
+ } else {
743
+ const l = document.createElement("input");
744
+ l.className = "foisit-form-input", o.type === "string" && (l.placeholder = o.placeholder || "Type here..."), o.type === "number" ? (l.type = "number", typeof o.min == "number" && (l.min = String(o.min)), typeof o.max == "number" && (l.max = String(o.max)), typeof o.step == "number" && (l.step = String(o.step)), o.defaultValue != null && (l.value = String(o.defaultValue))) : o.type === "date" ? (l.type = "date", typeof o.min == "string" && (l.min = o.min), typeof o.max == "string" && (l.max = o.max), o.defaultValue != null && (l.value = String(o.defaultValue))) : (l.type = "text", o.defaultValue != null && (l.value = String(o.defaultValue))), h = l;
745
+ }
746
+ const C = r();
747
+ p.appendChild(h), p.appendChild(C), n.push({
748
+ name: o.name,
749
+ type: o.type,
750
+ el: h,
751
+ required: o.required
752
+ }), s.appendChild(p);
510
753
  });
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();
754
+ const c = document.createElement("div");
755
+ c.className = "foisit-form-actions";
756
+ const f = document.createElement("button");
757
+ f.type = "submit", f.textContent = "Submit", f.className = "foisit-option-chip", f.style.fontWeight = "600", c.appendChild(f), s.appendChild(c), s.onsubmit = async (o) => {
758
+ o.preventDefault();
759
+ const p = {};
760
+ let b = !1;
761
+ s.querySelectorAll(".foisit-form-error").forEach((h) => {
762
+ h.style.display = "none", h.textContent = "";
763
+ }), s.querySelectorAll(".foisit-form-input").forEach((h) => {
764
+ h.classList.remove("foisit-error-border");
765
+ });
766
+ for (const h of n) {
767
+ if (h.type === "file") {
768
+ const x = h.el.parentElement, m = x == null ? void 0 : x.querySelector(".foisit-form-error"), w = h.el, g = Array.from(w.files || []);
769
+ if (h.required && g.length === 0) {
770
+ b = !0, w.classList.add("foisit-error-border"), m && (m.textContent = "This file is required", m.style.display = "block");
771
+ continue;
772
+ }
773
+ if (g.length === 0) continue;
774
+ const u = (e ?? []).find((v) => v.name === h.name), S = (u == null ? void 0 : u.delivery) ?? "file";
775
+ if (u != null && u.maxWidth || u != null && u.maxHeight)
776
+ try {
777
+ const v = await this.getImageDimensions(g[0]);
778
+ if (u.maxWidth && v.width > u.maxWidth) {
779
+ b = !0, m && (m.textContent = `Image width must be ≤ ${u.maxWidth}px`, m.style.display = "block");
780
+ continue;
781
+ }
782
+ if (u.maxHeight && v.height > u.maxHeight) {
783
+ b = !0, m && (m.textContent = `Image height must be ≤ ${u.maxHeight}px`, m.style.display = "block");
784
+ continue;
785
+ }
786
+ } catch {
787
+ }
788
+ if (u != null && u.maxDurationSec)
789
+ try {
790
+ const v = await this.getMediaDuration(g[0]);
791
+ if (v && v > u.maxDurationSec) {
792
+ b = !0, m && (m.textContent = `Media duration must be ≤ ${u.maxDurationSec}s`, m.style.display = "block");
793
+ continue;
794
+ }
795
+ } catch {
796
+ }
797
+ if (S === "file")
798
+ p[h.name] = u != null && u.multiple ? g : g[0];
799
+ else if (S === "base64")
800
+ try {
801
+ const v = await Promise.all(g.map((E) => this.readFileAsDataURL(E)));
802
+ p[h.name] = u != null && u.multiple ? v : v[0];
803
+ } catch {
804
+ b = !0, m && (m.textContent = "Failed to encode file(s) to base64.", m.style.display = "block");
805
+ continue;
806
+ }
807
+ continue;
808
+ }
809
+ const C = (h.el.value ?? "").toString().trim(), l = h.el.parentElement, y = l == null ? void 0 : l.querySelector(".foisit-form-error");
810
+ if (h.required && (C == null || C === "")) {
811
+ b = !0, h.el.classList.add("foisit-error-border"), y && (y.textContent = "This field is required", y.style.display = "block");
812
+ continue;
813
+ }
814
+ if (C !== "")
815
+ if (h.type === "number") {
816
+ const x = Number(C);
817
+ Number.isNaN(x) || (p[h.name] = x);
818
+ } else
819
+ p[h.name] = C;
820
+ }
821
+ if (b) {
822
+ s.classList.add("foisit-shake"), setTimeout(() => s.classList.remove("foisit-shake"), 400);
823
+ return;
824
+ }
825
+ f.disabled = !0, f.style.opacity = "0.6", n.forEach((h) => {
826
+ h.el.disabled = !0;
827
+ }), i(p);
828
+ }, this.messagesContainer.appendChild(s), this.scrollToBottom();
518
829
  }
519
- /**
520
- * Show loading indicator
521
- */
522
830
  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();
831
+ if (this.messagesContainer && !this.loadingEl) {
832
+ this.loadingEl = document.createElement("div"), this.loadingEl.className = "foisit-loading-dots foisit-bubble system";
833
+ for (let t = 0; t < 3; t++) {
834
+ const e = document.createElement("div");
835
+ e.className = "foisit-dot", e.style.animation = `foisitPulse 1.4s infinite ease-in-out ${t * 0.2}s`, this.loadingEl.appendChild(e);
836
+ }
837
+ this.messagesContainer.appendChild(this.loadingEl), this.scrollToBottom();
838
+ }
526
839
  }
527
- /**
528
- * Hide loading indicator
529
- */
530
840
  hideLoading() {
531
- const e = document.getElementById("foisit-loading-bubble");
532
- e && e.remove();
841
+ var t;
842
+ (t = this.loadingEl) == null || t.remove(), this.loadingEl = null;
533
843
  }
534
844
  scrollToBottom() {
535
- this.chatContainer && (this.chatContainer.scrollTop = this.chatContainer.scrollHeight);
845
+ this.messagesContainer && (this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight);
536
846
  }
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);
847
+ destroy() {
848
+ var t;
849
+ (t = this.container) == null || t.remove(), this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1;
850
+ }
851
+ readFileAsDataURL(t) {
852
+ return new Promise((e, i) => {
853
+ const s = new FileReader();
854
+ s.onerror = () => i(new Error("Failed to read file")), s.onload = () => e(String(s.result)), s.readAsDataURL(t);
855
+ });
856
+ }
857
+ getImageDimensions(t) {
858
+ return new Promise((e) => {
859
+ try {
860
+ const i = URL.createObjectURL(t), s = new Image();
861
+ s.onload = () => {
862
+ const n = { width: s.naturalWidth || s.width, height: s.naturalHeight || s.height };
863
+ URL.revokeObjectURL(i), e(n);
864
+ }, s.onerror = () => {
865
+ URL.revokeObjectURL(i), e({ width: 0, height: 0 });
866
+ }, s.src = i;
867
+ } catch {
868
+ e({ width: 0, height: 0 });
552
869
  }
870
+ });
871
+ }
872
+ getMediaDuration(t) {
873
+ return new Promise((e) => {
874
+ try {
875
+ const i = URL.createObjectURL(t), s = t.type.startsWith("audio") ? document.createElement("audio") : document.createElement("video");
876
+ let n = !1;
877
+ const a = setTimeout(() => {
878
+ n || (n = !0, URL.revokeObjectURL(i), e(0));
879
+ }, 5e3);
880
+ s.preload = "metadata", s.onloadedmetadata = () => {
881
+ if (n) return;
882
+ n = !0, clearTimeout(a);
883
+ const c = s.duration || 0;
884
+ URL.revokeObjectURL(i), e(c);
885
+ }, s.onerror = () => {
886
+ n || (n = !0, clearTimeout(a), URL.revokeObjectURL(i), e(0));
887
+ }, s.src = i;
888
+ } catch {
889
+ e(0);
890
+ }
891
+ });
892
+ }
893
+ injectOverlayStyles() {
894
+ if (document.getElementById("foisit-overlay-styles")) return;
895
+ const t = document.createElement("style");
896
+ t.id = "foisit-overlay-styles", t.textContent = `
897
+ :root {
898
+ /* LIGHT MODE (Default) - Smoother gradient */
899
+ /* Changed: Softer, right-focused radial highlight to avoid a heavy white bottom */
900
+ --foisit-bg: radial-gradient(ellipse at 75% 30%, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.03));
901
+ --foisit-border: 1px solid rgba(255, 255, 255, 0.25);
902
+ --foisit-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
903
+ --foisit-text: #333;
904
+
905
+ /* Input */
906
+ --foisit-input-color: #333;
907
+ --foisit-input-placeholder: rgba(60, 60, 67, 0.6);
908
+
909
+ /* Bubbles */
910
+ --foisit-bubble-user-bg: rgba(0, 0, 0, 0.04);
911
+ --foisit-bubble-user-text: #333;
912
+
913
+ --foisit-bubble-sys-bg: rgba(255, 255, 255, 0.45);
914
+ --foisit-bubble-sys-text: #333;
553
915
 
554
- #${l.OVERLAY_ID}.visible {
555
- opacity: 1;
556
- transform: translateY(0);
916
+ /* Form Colors */
917
+ --foisit-req-star: #ef4444; /* Red asterisk */
918
+ --foisit-error-text: #dc2626;
919
+ --foisit-error-border: #fca5a5;
557
920
  }
558
921
 
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;
922
+ @media (prefers-color-scheme: dark) {
923
+ :root {
924
+ /* DARK MODE */
925
+ --foisit-bg: linear-gradient(135deg, rgba(40, 40, 40, 0.65), rgba(40, 40, 40, 0.25));
926
+ --foisit-border: 1px solid rgba(255, 255, 255, 0.1);
927
+ --foisit-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
928
+ --foisit-text: #fff;
929
+
930
+ /* Input */
931
+ --foisit-input-color: white;
932
+ --foisit-input-placeholder: rgba(235, 235, 245, 0.5);
933
+
934
+ /* Bubbles */
935
+ --foisit-bubble-user-bg: rgba(255, 255, 255, 0.1);
936
+ --foisit-bubble-user-text: white;
937
+
938
+ --foisit-bubble-sys-bg: rgba(255, 255, 255, 0.05);
939
+ --foisit-bubble-sys-text: rgba(255, 255, 255, 0.9);
940
+
941
+ /* Form Colors */
942
+ --foisit-req-star: #f87171;
943
+ --foisit-error-text: #fca5a5;
944
+ --foisit-error-border: #f87171;
945
+ }
576
946
  }
577
947
 
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;
948
+ @keyframes foisitPulse {
949
+ 0%, 100% { transform: scale(0.8); opacity: 0.5; }
950
+ 50% { transform: scale(1.2); opacity: 1; }
592
951
  }
593
952
 
594
- #${l.INPUT_ID}::placeholder {
595
- color: rgba(60, 60, 67, 0.7);
596
- font-weight: 500;
953
+ @keyframes foisitShake {
954
+ 0%, 100% { transform: translateX(0); }
955
+ 25% { transform: translateX(-4px); }
956
+ 75% { transform: translateX(4px); }
597
957
  }
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
- }
958
+ .foisit-shake { animation: foisitShake 0.4s ease-in-out; }
959
+
960
+ /* Container */
961
+ .foisit-overlay-container {
962
+ position: fixed;
963
+ inset: 0;
964
+ z-index: 2147483647;
965
+ pointer-events: none;
966
+ display: flex;
967
+ flex-direction: column;
968
+ justify-content: flex-end;
969
+ align-items: flex-end;
970
+ padding: 20px;
971
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
617
972
  }
618
973
 
619
- .foisit-watermark {
620
- align-self: flex-end;
621
- margin: 0 12px 10px auto;
622
- padding: 4px 8px;
623
- border-radius: 8px;
974
+ .foisit-overlay-container * {
975
+ box-sizing: border-box;
976
+ }
624
977
 
625
- font-size: 9px;
626
- font-weight: 600;
627
- letter-spacing: 0.8px;
628
- text-transform: capitalize;
978
+ /* Chat Window - Dynamic Height */
979
+ .foisit-chat {
980
+ position: absolute;
981
+ top: 20px;
982
+ right: 20px;
983
+ width: min(420px, 92vw);
629
984
 
630
- background: rgba(0, 0, 0, 0.35);
631
- backdrop-filter: blur(6px);
632
- -webkit-backdrop-filter: blur(6px);
985
+ /* FIX: Auto height to prevent empty space */
986
+ height: auto;
987
+ min-height: 120px;
988
+ max-height: 80vh;
633
989
 
634
- color: rgba(255, 255, 255, 0.85);
635
- pointer-events: none;
636
- }
990
+ background: var(--foisit-bg);
991
+ border: var(--foisit-border);
992
+ box-shadow: var(--foisit-shadow);
637
993
 
994
+ backdrop-filter: blur(20px);
995
+ -webkit-backdrop-filter: blur(20px);
638
996
 
639
- /* Chat UI Styles */
640
- #foisit-chat-history {
997
+ border-radius: 18px;
998
+ display: none;
999
+ flex-direction: column;
1000
+ overflow: hidden;
1001
+ pointer-events: auto;
1002
+ transform-origin: top right;
1003
+ transition: opacity 0.2s, transform 0.2s cubic-bezier(0.2, 0.9, 0.2, 1);
1004
+ }
1005
+
1006
+ .foisit-header {
1007
+ display: flex;
1008
+ align-items: center;
1009
+ justify-content: space-between;
1010
+ padding: 12px 16px;
1011
+ font-weight: 600;
1012
+ font-size: 14px;
1013
+ color: var(--foisit-text);
1014
+ border-bottom: 1px solid rgba(127,127,127,0.08); /* Subtle separator */
1015
+ }
1016
+
1017
+ .foisit-close {
1018
+ background: transparent;
1019
+ border: none;
1020
+ color: var(--foisit-text);
1021
+ opacity: 0.5;
1022
+ font-size: 24px;
1023
+ line-height: 1;
1024
+ cursor: pointer;
1025
+ padding: 0;
1026
+ width: 28px;
1027
+ height: 28px;
1028
+ display: flex;
1029
+ align-items: center;
1030
+ justify-content: center;
1031
+ transition: opacity 0.2s;
1032
+ }
1033
+ .foisit-close:hover { opacity: 1; }
1034
+
1035
+ /* Message Area */
1036
+ .foisit-messages {
641
1037
  flex: 1;
642
1038
  overflow-y: auto;
643
1039
  padding: 16px;
644
1040
  display: flex;
645
1041
  flex-direction: column;
646
- gap: 12px;
647
- max-height: 400px;
1042
+ gap: 10px;
1043
+ /* Ensure it doesn't get too tall initially */
1044
+ min-height: 60px;
648
1045
  }
649
1046
 
1047
+ /* Make sure empty state isn't huge */
1048
+ .foisit-messages:empty {
1049
+ display: none;
1050
+ }
1051
+
1052
+ /* Only show messages container if it has children */
1053
+ .foisit-messages:not(:empty) {
1054
+ display: flex;
1055
+ }
1056
+
1057
+ /* Bubbles */
650
1058
  .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;
1059
+ max-width: 90%;
1060
+ padding: 8px 14px;
1061
+ border-radius: 14px;
655
1062
  font-size: 14px;
656
1063
  line-height: 1.4;
1064
+ word-wrap: break-word;
657
1065
  }
658
1066
 
659
1067
  .foisit-bubble.user {
660
1068
  align-self: flex-end;
661
- background: rgba(0, 0, 0, 0.05); /* Subtle dark for user */
662
- color: #333;
1069
+ background: var(--foisit-bubble-user-bg);
1070
+ color: var(--foisit-bubble-user-text);
663
1071
  border-bottom-right-radius: 4px;
664
1072
  }
665
1073
 
666
1074
  .foisit-bubble.system {
667
1075
  align-self: flex-start;
668
- background: rgba(255, 255, 255, 0.4); /* Glassy white */
669
- color: #333;
1076
+ background: var(--foisit-bubble-sys-bg);
1077
+ color: var(--foisit-bubble-sys-text);
670
1078
  border-bottom-left-radius: 4px;
1079
+ border: 1px solid rgba(255,255,255,0.1);
671
1080
  }
672
1081
 
1082
+ /* Input Area */
1083
+ .foisit-input-area {
1084
+ padding: 0;
1085
+ width: 100%;
1086
+ border-top: 1px solid rgba(127,127,127,0.08);
1087
+ }
1088
+
1089
+ .foisit-input {
1090
+ width: 100%;
1091
+ background: transparent;
1092
+ border: none;
1093
+ font-size: 16px;
1094
+ color: var(--foisit-input-color);
1095
+ padding: 16px 20px;
1096
+ outline: none;
1097
+ text-align: left;
1098
+ }
1099
+
1100
+ .foisit-input::placeholder {
1101
+ color: var(--foisit-input-placeholder);
1102
+ font-weight: 400;
1103
+ }
1104
+
1105
+ /* Options & Buttons */
673
1106
  .foisit-options-container {
674
1107
  display: flex;
675
1108
  flex-wrap: wrap;
676
1109
  gap: 8px;
677
- margin-left: 4px;
1110
+ margin-left: 2px;
1111
+ margin-top: 4px;
678
1112
  }
679
1113
 
680
1114
  .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);
1115
+ padding: 6px 14px;
1116
+ background: var(--foisit-bubble-sys-bg);
1117
+ border: 1px solid rgba(127,127,127,0.1);
684
1118
  border-radius: 20px;
685
1119
  font-size: 13px;
686
- color: #333;
1120
+ color: var(--foisit-text);
687
1121
  cursor: pointer;
688
1122
  transition: all 0.2s;
1123
+ font-weight: 500;
689
1124
  }
690
-
691
1125
  .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;
1126
+ background: rgba(127,127,127,0.15);
764
1127
  }
765
1128
 
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);
1129
+ /* Form Styling */
1130
+ .foisit-form {
1131
+ background: var(--foisit-bubble-sys-bg);
823
1132
  padding: 16px;
824
- border-radius: 12px;
825
- width: 100%;
826
- box-sizing: border-box;
827
- border: 1px solid rgba(255, 255, 255, 0.2);
1133
+ border-radius: 14px;
828
1134
  display: flex;
829
1135
  flex-direction: column;
830
1136
  gap: 12px;
1137
+ width: 100%;
1138
+ border: 1px solid rgba(127,127,127,0.1);
831
1139
  }
832
1140
 
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;
1141
+ .foisit-form-label {
1142
+ font-size: 12px;
1143
+ font-weight: 600;
1144
+ color: var(--foisit-text);
1145
+ opacity: 0.9;
1146
+ margin-bottom: 2px;
845
1147
  }
846
1148
 
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);
1149
+ .foisit-req-star {
1150
+ color: var(--foisit-req-star);
1151
+ font-weight: bold;
852
1152
  }
853
1153
 
854
- .foisit-field-input {
855
- background: rgba(255, 255, 255, 0.6);
856
- border: 1px solid rgba(0, 0, 0, 0.1);
1154
+ .foisit-form-input {
1155
+ width: 100%;
1156
+ padding: 10px;
857
1157
  border-radius: 8px;
858
- padding: 8px 12px;
1158
+ border: 1px solid rgba(127,127,127,0.2);
1159
+ background: rgba(255,255,255,0.05); /* Very subtle fill */
1160
+ color: var(--foisit-text);
859
1161
  font-size: 14px;
860
- color: #333;
861
1162
  outline: none;
1163
+ transition: border 0.2s;
1164
+ }
1165
+ .foisit-form-input:focus {
1166
+ border-color: var(--foisit-text);
1167
+ background: rgba(255,255,255,0.1);
862
1168
  }
863
1169
 
864
- .foisit-field-input:focus {
865
- border-color: rgba(0, 0, 0, 0.3);
1170
+ .foisit-error-border {
1171
+ border-color: var(--foisit-error-border) !important;
866
1172
  }
867
1173
 
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;
1174
+ .foisit-form-error {
1175
+ font-size: 11px;
1176
+ color: var(--foisit-error-text);
878
1177
  margin-top: 4px;
879
1178
  }
880
1179
 
881
- .foisit-form-submit:hover {
882
- opacity: 0.8;
1180
+ /* Loading */
1181
+ .foisit-loading-dots {
1182
+ display: inline-flex;
1183
+ gap: 4px;
1184
+ padding: 10px 14px;
1185
+ align-self: flex-start;
883
1186
  }
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
- }
1187
+ .foisit-dot {
1188
+ width: 6px;
1189
+ height: 6px;
1190
+ border-radius: 50%;
1191
+ background: var(--foisit-text);
1192
+ opacity: 0.4;
905
1193
  }
906
1194
 
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");
1195
+ /* Floating Button */
1196
+ .foisit-floating-btn {
1197
+ position: absolute;
1198
+ width: 56px;
1199
+ height: 56px;
1200
+ border-radius: 50%;
1201
+ border: 1px solid rgba(255,255,255,0.2);
1202
+ background: var(--foisit-bg);
1203
+ color: var(--foisit-text);
1204
+ backdrop-filter: blur(10px);
1205
+ -webkit-backdrop-filter: blur(10px);
1206
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
1207
+ cursor: pointer;
1208
+ pointer-events: auto;
1209
+ display: flex;
1210
+ align-items: center;
1211
+ justify-content: center;
1212
+ font-size: 24px;
1213
+ z-index: 100000;
1214
+ transition: transform 0.2s;
933
1215
  }
934
- i.key === "Escape" && this.hide();
935
- }));
1216
+ .foisit-floating-btn:hover { transform: scale(1.05); }
1217
+ `, document.head.appendChild(t);
936
1218
  }
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({
1219
+ }
1220
+ class Y {
1221
+ constructor(t) {
1222
+ this.config = t, this.isActivated = !1, this.lastProcessedInput = "", this.processingLock = !1, this.defaultIntroMessage = "How can I help you?", this.commandHandler = new B({
1223
+ enableSmartIntent: this.config.enableSmartIntent !== !1,
1224
+ intentEndpoint: this.config.intentEndpoint
1225
+ }), this.fallbackHandler = new O(), this.voiceProcessor = new z(), this.textToSpeech = new H(), this.stateManager = new V(), this.gestureHandler = new $(), this.overlayManager = new G({
945
1226
  floatingButton: this.config.floatingButton,
946
1227
  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);
1228
+ }), this.config.commands.forEach((e) => this.commandHandler.addCommand(e)), this.config.fallbackResponse && this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse), this.gestureHandler.setupDoubleTapListener(() => this.toggle()), this.overlayManager.registerCallbacks(
1229
+ async (e) => {
1230
+ if (typeof e == "string") {
1231
+ this.overlayManager.addMessage(e, "user"), await this.handleCommand(e);
1232
+ return;
1233
+ }
1234
+ if (e && typeof e == "object") {
1235
+ const i = e, s = i.label ?? i.commandId ?? "Selection";
1236
+ this.overlayManager.addMessage(String(s), "user"), this.overlayManager.showLoading();
1237
+ const n = await this.commandHandler.executeCommand(i);
1238
+ this.overlayManager.hideLoading(), this.processResponse(n);
1239
+ }
950
1240
  },
951
1241
  () => console.log("AssistantService: Overlay closed.")
952
1242
  );
953
1243
  }
954
1244
  /** Start listening for activation and commands */
955
1245
  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
- });
1246
+ console.log("AssistantService: Voice is disabled; startListening() is a no-op.");
970
1247
  }
971
1248
  /** Stop listening */
972
1249
  stopListening() {
973
- console.log("AssistantService: Stopping listening..."), this.voiceProcessor.stopListening(), this.isActivated = !1;
1250
+ console.log("AssistantService: Voice is disabled; stopListening() is a no-op."), this.isActivated = !1;
1251
+ }
1252
+ /**
1253
+ * Reset activation state so the next activation flow can occur.
1254
+ * This is mainly used by the wrapper UI (e.g. AssistantActivator).
1255
+ */
1256
+ reactivate() {
1257
+ console.log("AssistantService: Reactivating assistant..."), this.isActivated = !1;
1258
+ try {
1259
+ this.startListening();
1260
+ } catch {
1261
+ }
974
1262
  }
975
1263
  /** Process activation command */
976
- async processActivation(e) {
1264
+ async processActivation(t) {
977
1265
  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(
1266
+ const e = (i = this.config.activationCommand) == null ? void 0 : i.toLowerCase();
1267
+ e && (t === e ? (console.log("AssistantService: Activation matched."), this.isActivated = !0, this.textToSpeech.speak(
980
1268
  this.config.introMessage || this.defaultIntroMessage
981
1269
  )) : console.log("AssistantService: Activation command not recognized."));
982
1270
  }
983
1271
  /** Handle recognized commands */
984
- async handleCommand(e) {
1272
+ async handleCommand(t) {
985
1273
  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);
1274
+ let e;
1275
+ try {
1276
+ e = await this.commandHandler.executeCommand(t);
1277
+ } finally {
1278
+ this.overlayManager.hideLoading();
1279
+ }
1280
+ if (e.type === "form" && e.fields) {
1281
+ this.overlayManager.addForm(
1282
+ e.message,
1283
+ e.fields,
1284
+ async (i) => {
1285
+ this.overlayManager.showLoading();
1286
+ let s;
1287
+ try {
1288
+ s = await this.commandHandler.executeCommand(i);
1289
+ } finally {
1290
+ this.overlayManager.hideLoading();
1291
+ }
1292
+ this.processResponse(s);
1293
+ }
1294
+ );
1295
+ return;
1296
+ }
1297
+ if (e.type === "error") {
1298
+ this.fallbackHandler.handleFallback(t), this.overlayManager.addMessage(this.fallbackHandler.getFallbackMessage(), "system");
1299
+ return;
1300
+ }
1301
+ e.message ? this.overlayManager.addMessage(e.message, "system") : (e.type === "ambiguous" || e.type === "confirm") && e.options && this.overlayManager.addOptions(e.options);
996
1302
  }
997
1303
  /**
998
1304
  * Cleanup resources
999
1305
  */
1000
1306
  destroy() {
1001
- this.voiceProcessor.stopListening(), this.overlayManager.destroy();
1307
+ this.voiceProcessor.stopListening(), this.gestureHandler.destroy(), this.overlayManager.destroy();
1002
1308
  }
1003
1309
  /** 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);
1310
+ processResponse(t) {
1311
+ if (t) {
1312
+ if (t.type === "form" && t.fields) {
1313
+ this.overlayManager.addForm(
1314
+ t.message,
1315
+ t.fields,
1316
+ async (e) => {
1317
+ this.overlayManager.showLoading();
1318
+ let i;
1319
+ try {
1320
+ i = await this.commandHandler.executeCommand(e);
1321
+ } finally {
1322
+ this.overlayManager.hideLoading();
1323
+ }
1324
+ this.processResponse(i);
1325
+ }
1326
+ );
1327
+ return;
1012
1328
  }
1013
- ) : e.type === "ambiguous" && e.options && this.overlayManager.addOptions(e.options);
1329
+ if ((t.type === "ambiguous" || t.type === "confirm") && t.options) {
1330
+ t.message && this.overlayManager.addMessage(t.message, "system"), this.overlayManager.addOptions(t.options);
1331
+ return;
1332
+ }
1333
+ t.message && this.overlayManager.addMessage(t.message, "system");
1334
+ }
1014
1335
  }
1015
1336
  /** 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);
1337
+ addCommand(t, e) {
1338
+ console.log(typeof t == "string" ? `AssistantService: Adding command "${t}".` : `AssistantService: Adding rich command "${t.command}".`), this.commandHandler.addCommand(t, e);
1018
1339
  }
1019
1340
  /** Remove a command dynamically */
1020
- removeCommand(e) {
1021
- console.log(`AssistantService: Removing command "${e}".`), this.commandHandler.removeCommand(e);
1341
+ removeCommand(t) {
1342
+ console.log(`AssistantService: Removing command "${t}".`), this.commandHandler.removeCommand(t);
1022
1343
  }
1023
1344
  /** Get all registered commands */
1024
1345
  getCommands() {
1025
1346
  return this.commandHandler.getCommands();
1026
1347
  }
1027
1348
  /** Toggle the assistant overlay */
1028
- toggle(e, t) {
1349
+ toggle(t, e) {
1029
1350
  console.log("AssistantService: Toggling overlay..."), this.overlayManager.toggle(
1030
1351
  async (i) => {
1031
- this.overlayManager.addMessage(i, "user"), e && e(i), await this.handleCommand(i);
1352
+ if (typeof i == "string") {
1353
+ this.overlayManager.addMessage(i, "user"), t && t(i), await this.handleCommand(i);
1354
+ return;
1355
+ }
1356
+ if (i && typeof i == "object") {
1357
+ const s = i, n = s.label ?? s.commandId ?? "Selection";
1358
+ this.overlayManager.addMessage(String(n), "user"), this.overlayManager.showLoading();
1359
+ let a;
1360
+ try {
1361
+ a = await this.commandHandler.executeCommand(s);
1362
+ } finally {
1363
+ this.overlayManager.hideLoading();
1364
+ }
1365
+ this.processResponse(a);
1366
+ }
1032
1367
  },
1033
1368
  () => {
1034
- console.log("AssistantService: Overlay closed."), t && t();
1369
+ console.log("AssistantService: Overlay closed."), e && e();
1035
1370
  }
1036
1371
  );
1037
1372
  }
1038
1373
  }
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;
1374
+ const q = F(null);
1375
+ let I = null;
1376
+ const Z = ({ config: d, children: t }) => {
1377
+ const [e, i] = R(null), [s, n] = R(!1);
1378
+ return P(() => {
1379
+ I ? console.warn(
1380
+ "Multiple AssistantProvider instances detected. Reusing global AssistantService."
1381
+ ) : (console.log("Initializing global AssistantService..."), I = new Y(d));
1382
+ const a = I;
1383
+ return i(a), n(!0), () => {
1384
+ var r;
1385
+ console.log("Cleaning up AssistantService..."), (r = a.destroy) == null || r.call(a), I = null;
1049
1386
  };
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)
1387
+ }, [d]), !s || !e ? /* @__PURE__ */ k("div", { children: "Loading Assistant..." }) : /* @__PURE__ */ k(q.Provider, { value: e, children: t });
1388
+ }, K = () => {
1389
+ const d = N(q);
1390
+ if (console.log("assistant", d), !d)
1054
1391
  throw new Error("useAssistant must be used within an AssistantProvider");
1055
- return r;
1056
- }, U = ({
1057
- label: r = "Activate Assistant",
1058
- onActivate: e
1392
+ return d;
1393
+ }, Q = ({
1394
+ label: d = "Activate Assistant",
1395
+ onActivate: t
1059
1396
  }) => {
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(() => {
1397
+ const e = K();
1398
+ return /* @__PURE__ */ k("button", { onClick: () => {
1399
+ t && t(), e.reactivate();
1400
+ }, className: "assistant-activator", children: d });
1401
+ }, tt = (d) => {
1402
+ const [t, e] = R(d.getState());
1403
+ return P(() => {
1067
1404
  const i = (s) => {
1068
- t(s);
1405
+ e(s);
1069
1406
  };
1070
- return r.subscribe(i), () => {
1071
- r.subscribe(() => {
1407
+ return d.subscribe(i), () => {
1408
+ d.subscribe(() => {
1072
1409
  });
1073
1410
  };
1074
- }, [r]), e;
1411
+ }, [d]), t;
1075
1412
  };
1076
1413
  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
1414
+ Q as AssistantActivator,
1415
+ q as AssistantContext,
1416
+ Z as AssistantProvider,
1417
+ Y as AssistantService,
1418
+ J as ReactWrapper,
1419
+ K as useAssistant,
1420
+ tt as useAssistantState
1084
1421
  };