@foisit/react-wrapper 2.4.4 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -6
- package/index.d.ts +1 -0
- package/index.js +158 -44
- package/index.mjs +590 -265
- package/lib/services/AssistantService.d.ts +10 -0
- package/package.json +9 -2
package/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as k } from "react/jsx-runtime";
|
|
2
|
-
import { createContext as F, useState as
|
|
3
|
-
const
|
|
4
|
-
function
|
|
5
|
-
return /* @__PURE__ */ k("div", { className:
|
|
2
|
+
import { createContext as F, useState as I, useEffect as H, useContext as B } from "react";
|
|
3
|
+
const O = {};
|
|
4
|
+
function Q() {
|
|
5
|
+
return /* @__PURE__ */ k("div", { className: O.container, children: /* @__PURE__ */ k("h1", { children: "Welcome to ReactWrapper!" }) });
|
|
6
6
|
}
|
|
7
|
-
class
|
|
7
|
+
class T {
|
|
8
8
|
constructor(t) {
|
|
9
9
|
this.endpoint = t || "https://foisit-ninja.netlify.app/.netlify/functions/intent";
|
|
10
10
|
}
|
|
@@ -12,11 +12,11 @@ class M {
|
|
|
12
12
|
try {
|
|
13
13
|
const s = {
|
|
14
14
|
userInput: t,
|
|
15
|
-
commands: e.map((
|
|
16
|
-
id:
|
|
17
|
-
command:
|
|
18
|
-
description:
|
|
19
|
-
parameters:
|
|
15
|
+
commands: e.map((o) => ({
|
|
16
|
+
id: o.id,
|
|
17
|
+
command: o.command,
|
|
18
|
+
description: o.description,
|
|
19
|
+
parameters: o.parameters
|
|
20
20
|
// Send param schemas to AI
|
|
21
21
|
})),
|
|
22
22
|
context: i
|
|
@@ -35,13 +35,13 @@ class M {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
class
|
|
38
|
+
class N {
|
|
39
39
|
constructor(t = !0) {
|
|
40
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
|
|
41
|
+
this.enableSmartIntent = t, this.enableSmartIntent && (this.openAIService = new T());
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
this.enableSmartIntent = t.enableSmartIntent ?? !0, this.enableSmartIntent && (this.openAIService = new
|
|
44
|
+
this.enableSmartIntent = t.enableSmartIntent ?? !0, this.enableSmartIntent && (this.openAIService = new T(t.intentEndpoint));
|
|
45
45
|
}
|
|
46
46
|
/** Add a new command (string or object) */
|
|
47
47
|
addCommand(t, e) {
|
|
@@ -66,14 +66,14 @@ class B {
|
|
|
66
66
|
async executeCommand(t) {
|
|
67
67
|
if (typeof t == "object" && t !== null) {
|
|
68
68
|
if (this.isStructured(t)) {
|
|
69
|
-
const c = String(t.commandId),
|
|
70
|
-
if (!
|
|
71
|
-
const p = this.sanitizeParamsForCommand(
|
|
72
|
-
return m.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(
|
|
73
|
-
message: `Please provide the required details for "${
|
|
69
|
+
const c = String(t.commandId), u = t.params ?? {}, r = this.getCommandById(c);
|
|
70
|
+
if (!r) return { message: "That command is not available.", type: "error" };
|
|
71
|
+
const p = this.sanitizeParamsForCommand(r, u), m = (r.parameters ?? []).filter((C) => C.required).filter((C) => p[C.name] == null || p[C.name] === "");
|
|
72
|
+
return m.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(r), params: p }, {
|
|
73
|
+
message: `Please provide the required details for "${r.command}".`,
|
|
74
74
|
type: "form",
|
|
75
75
|
fields: m
|
|
76
|
-
}) :
|
|
76
|
+
}) : r.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(r), params: p }, this.buildConfirmResponse(r)) : this.safeRunAction(r, p);
|
|
77
77
|
}
|
|
78
78
|
if (!this.context)
|
|
79
79
|
return { message: "Session expired or invalid context.", type: "error" };
|
|
@@ -82,26 +82,26 @@ class B {
|
|
|
82
82
|
return this.context = null, { message: "Session expired or invalid context.", type: "error" };
|
|
83
83
|
if (Array.isArray(t))
|
|
84
84
|
return { message: "Invalid form payload.", type: "error" };
|
|
85
|
-
const
|
|
85
|
+
const a = {
|
|
86
86
|
...this.context.params,
|
|
87
87
|
...t
|
|
88
88
|
};
|
|
89
89
|
if (n.critical)
|
|
90
90
|
return this.context = null, this.pendingConfirmation = {
|
|
91
91
|
commandId: this.getCommandIdentifier(n),
|
|
92
|
-
params:
|
|
92
|
+
params: a
|
|
93
93
|
}, this.buildConfirmResponse(n);
|
|
94
|
-
const
|
|
95
|
-
return this.context = null, this.normalizeResponse(
|
|
94
|
+
const o = await this.safeRunAction(n, a);
|
|
95
|
+
return this.context = null, this.normalizeResponse(o);
|
|
96
96
|
}
|
|
97
97
|
const e = t.trim().toLowerCase();
|
|
98
98
|
if (this.pendingConfirmation) {
|
|
99
99
|
const n = e;
|
|
100
100
|
if (["yes", "y", "confirm", "ok", "okay"].includes(n)) {
|
|
101
|
-
const { commandId:
|
|
101
|
+
const { commandId: a, params: o } = this.pendingConfirmation;
|
|
102
102
|
this.pendingConfirmation = null;
|
|
103
|
-
const c = this.getCommandById(
|
|
104
|
-
return c ? this.safeRunAction(c,
|
|
103
|
+
const c = this.getCommandById(a);
|
|
104
|
+
return c ? this.safeRunAction(c, o) : { message: "That action is no longer available.", type: "error" };
|
|
105
105
|
}
|
|
106
106
|
return ["no", "n", "cancel", "stop"].includes(n) ? (this.pendingConfirmation = null, { message: "Cancelled.", type: "success" }) : {
|
|
107
107
|
message: "Please confirm: Yes or No.",
|
|
@@ -114,22 +114,25 @@ class B {
|
|
|
114
114
|
}
|
|
115
115
|
const i = this.commands.get(e);
|
|
116
116
|
if (i) {
|
|
117
|
-
const n = i
|
|
118
|
-
|
|
117
|
+
const n = i;
|
|
118
|
+
if (n.macro)
|
|
119
|
+
return this.safeRunAction(n, {});
|
|
120
|
+
const a = (n.parameters ?? []).filter((o) => o.required);
|
|
121
|
+
return a.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
|
|
119
122
|
message: `Please provide the required details for "${n.command}".`,
|
|
120
123
|
type: "form",
|
|
121
|
-
fields:
|
|
124
|
+
fields: a
|
|
122
125
|
}) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
|
|
123
126
|
}
|
|
124
127
|
const s = await this.tryDeterministicMatch(e);
|
|
125
128
|
if (s) return s;
|
|
126
129
|
if (this.enableSmartIntent && this.openAIService) {
|
|
127
|
-
const n = await this.getCommandsForAI(),
|
|
130
|
+
const n = await this.getCommandsForAI(), a = await this.openAIService.determineIntent(
|
|
128
131
|
e,
|
|
129
132
|
n,
|
|
130
133
|
this.context
|
|
131
134
|
);
|
|
132
|
-
return this.handleAIResult(
|
|
135
|
+
return this.handleAIResult(a);
|
|
133
136
|
}
|
|
134
137
|
return this.enableSmartIntent ? this.listAllCommands() : { message: "I'm not sure what you mean.", type: "error" };
|
|
135
138
|
}
|
|
@@ -138,10 +141,12 @@ class B {
|
|
|
138
141
|
const e = this.getCommandById(t.match);
|
|
139
142
|
if (!e)
|
|
140
143
|
return { message: "I'm not sure what you mean.", type: "error" };
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
if (e.macro)
|
|
145
|
+
return this.safeRunAction(e, {});
|
|
146
|
+
const i = t.params ?? {}, s = this.sanitizeParamsForCommand(e, i), n = e.allowAiParamExtraction === !1 ? {} : s, o = (e.parameters ?? []).filter((u) => u.required).filter((u) => n[u.name] == null || n[u.name] === "");
|
|
147
|
+
if (t.incomplete || o.length > 0) {
|
|
148
|
+
if (this.context = { commandId: this.getCommandIdentifier(e), params: n }, !(e.collectRequiredViaForm !== !1) && this.shouldAskSingleQuestion(o)) {
|
|
149
|
+
const p = o.map((g) => g.name).join(" and ");
|
|
145
150
|
return {
|
|
146
151
|
message: t.message || `Please provide ${p}.`,
|
|
147
152
|
type: "question"
|
|
@@ -150,7 +155,7 @@ class B {
|
|
|
150
155
|
return {
|
|
151
156
|
message: t.message || `Please fill in the missing details for "${e.command}".`,
|
|
152
157
|
type: "form",
|
|
153
|
-
fields:
|
|
158
|
+
fields: o
|
|
154
159
|
};
|
|
155
160
|
}
|
|
156
161
|
if (e.critical)
|
|
@@ -180,52 +185,52 @@ class B {
|
|
|
180
185
|
delete i[s.name];
|
|
181
186
|
continue;
|
|
182
187
|
}
|
|
183
|
-
const
|
|
184
|
-
if (!
|
|
188
|
+
const a = n.trim();
|
|
189
|
+
if (!a) {
|
|
185
190
|
delete i[s.name];
|
|
186
191
|
continue;
|
|
187
192
|
}
|
|
188
|
-
i[s.name] =
|
|
193
|
+
i[s.name] = a;
|
|
189
194
|
}
|
|
190
195
|
if (s.type === "number") {
|
|
191
|
-
const
|
|
192
|
-
if (Number.isNaN(
|
|
196
|
+
const a = typeof n == "number" ? n : Number(n == null ? void 0 : n.toString().trim());
|
|
197
|
+
if (Number.isNaN(a)) {
|
|
193
198
|
delete i[s.name];
|
|
194
199
|
continue;
|
|
195
200
|
}
|
|
196
|
-
if (typeof s.min == "number" &&
|
|
201
|
+
if (typeof s.min == "number" && a < s.min) {
|
|
197
202
|
delete i[s.name];
|
|
198
203
|
continue;
|
|
199
204
|
}
|
|
200
|
-
if (typeof s.max == "number" &&
|
|
205
|
+
if (typeof s.max == "number" && a > s.max) {
|
|
201
206
|
delete i[s.name];
|
|
202
207
|
continue;
|
|
203
208
|
}
|
|
204
|
-
i[s.name] =
|
|
209
|
+
i[s.name] = a;
|
|
205
210
|
}
|
|
206
211
|
if (s.type === "date") {
|
|
207
|
-
const
|
|
208
|
-
if (typeof
|
|
209
|
-
const
|
|
210
|
-
this.isIsoDateString(
|
|
212
|
+
const a = i[s.name];
|
|
213
|
+
if (typeof a == "string") {
|
|
214
|
+
const o = a.trim();
|
|
215
|
+
this.isIsoDateString(o) ? i[s.name] = o : delete i[s.name];
|
|
211
216
|
} else
|
|
212
217
|
delete i[s.name];
|
|
213
218
|
}
|
|
214
219
|
if (s.type === "select") {
|
|
215
|
-
const
|
|
216
|
-
if (!
|
|
220
|
+
const a = typeof n == "string" ? n : n == null ? void 0 : n.toString();
|
|
221
|
+
if (!a) {
|
|
217
222
|
delete i[s.name];
|
|
218
223
|
continue;
|
|
219
224
|
}
|
|
220
|
-
if (Array.isArray(s.options) && s.options.length > 0 && !s.options.some((c) => String(c.value) === String(
|
|
225
|
+
if (Array.isArray(s.options) && s.options.length > 0 && !s.options.some((c) => String(c.value) === String(a))) {
|
|
221
226
|
delete i[s.name];
|
|
222
227
|
continue;
|
|
223
228
|
}
|
|
224
|
-
i[s.name] =
|
|
229
|
+
i[s.name] = a;
|
|
225
230
|
}
|
|
226
231
|
if (s.type === "file") {
|
|
227
|
-
const
|
|
228
|
-
(s.delivery ?? "file") === "base64" ? !c && !
|
|
232
|
+
const a = i[s.name], o = a && typeof a == "object" && typeof a.name == "string" && typeof a.size == "number", c = typeof a == "string" && /^data:[^;]+;base64,/.test(a);
|
|
233
|
+
(s.delivery ?? "file") === "base64" ? !c && !o && delete i[s.name] : o || delete i[s.name];
|
|
229
234
|
}
|
|
230
235
|
}
|
|
231
236
|
return i;
|
|
@@ -252,35 +257,35 @@ class B {
|
|
|
252
257
|
}
|
|
253
258
|
async tryDeterministicMatch(t) {
|
|
254
259
|
const e = [];
|
|
255
|
-
for (const
|
|
260
|
+
for (const o of this.commands.values()) {
|
|
256
261
|
let c = 0;
|
|
257
|
-
const
|
|
258
|
-
t.includes(
|
|
259
|
-
const
|
|
260
|
-
for (const p of
|
|
262
|
+
const u = o.command.toLowerCase();
|
|
263
|
+
t.includes(u) && (c += 5);
|
|
264
|
+
const r = o.keywords ?? [];
|
|
265
|
+
for (const p of r) {
|
|
261
266
|
const g = p.toLowerCase().trim();
|
|
262
267
|
g && (t === g ? c += 4 : t.includes(g) && (c += 3));
|
|
263
268
|
}
|
|
264
|
-
c > 0 && e.push({ cmd:
|
|
269
|
+
c > 0 && e.push({ cmd: o, score: c });
|
|
265
270
|
}
|
|
266
271
|
if (e.length === 0) return null;
|
|
267
|
-
e.sort((
|
|
268
|
-
const i = e[0].score, s = e.filter((
|
|
272
|
+
e.sort((o, c) => c.score - o.score);
|
|
273
|
+
const i = e[0].score, s = e.filter((o) => o.score === i).slice(0, 3);
|
|
269
274
|
if (s.length > 1)
|
|
270
275
|
return {
|
|
271
276
|
message: "I think you mean one of these. Which one should I run?",
|
|
272
277
|
type: "ambiguous",
|
|
273
|
-
options: s.map((
|
|
274
|
-
label:
|
|
275
|
-
value:
|
|
276
|
-
commandId:
|
|
278
|
+
options: s.map((o) => ({
|
|
279
|
+
label: o.cmd.command,
|
|
280
|
+
value: o.cmd.command,
|
|
281
|
+
commandId: o.cmd.id
|
|
277
282
|
}))
|
|
278
283
|
};
|
|
279
|
-
const n = s[0].cmd,
|
|
280
|
-
return
|
|
284
|
+
const n = s[0].cmd, a = (n.parameters ?? []).filter((o) => o.required);
|
|
285
|
+
return a.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
|
|
281
286
|
message: `Please provide the required details for "${n.command}".`,
|
|
282
287
|
type: "form",
|
|
283
|
-
fields:
|
|
288
|
+
fields: a
|
|
284
289
|
}) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
|
|
285
290
|
}
|
|
286
291
|
async safeRunAction(t, e) {
|
|
@@ -301,14 +306,14 @@ class B {
|
|
|
301
306
|
e.parameters && await Promise.all(
|
|
302
307
|
e.parameters.map(async (i) => {
|
|
303
308
|
if (i.type !== "select" || !i.getOptions || i.options && i.options.length) return;
|
|
304
|
-
const s = `${e.id ?? e.command}:${i.name}`, n = this.selectOptionsCache.get(s),
|
|
305
|
-
if (n &&
|
|
309
|
+
const s = `${e.id ?? e.command}:${i.name}`, n = this.selectOptionsCache.get(s), a = Date.now();
|
|
310
|
+
if (n && a - n.ts < 6e4) {
|
|
306
311
|
i.options = n.options;
|
|
307
312
|
return;
|
|
308
313
|
}
|
|
309
314
|
try {
|
|
310
|
-
const
|
|
311
|
-
this.selectOptionsCache.set(s, { options:
|
|
315
|
+
const o = await i.getOptions();
|
|
316
|
+
this.selectOptionsCache.set(s, { options: o, ts: a }), i.options = o;
|
|
312
317
|
} catch {
|
|
313
318
|
}
|
|
314
319
|
})
|
|
@@ -345,7 +350,7 @@ class B {
|
|
|
345
350
|
return Array.from(this.commands.keys());
|
|
346
351
|
}
|
|
347
352
|
}
|
|
348
|
-
class
|
|
353
|
+
class P {
|
|
349
354
|
constructor() {
|
|
350
355
|
this.synth = typeof window < "u" ? window.speechSynthesis : null;
|
|
351
356
|
}
|
|
@@ -375,18 +380,18 @@ class z {
|
|
|
375
380
|
this.fallbackMessage = t;
|
|
376
381
|
}
|
|
377
382
|
handleFallback(t) {
|
|
378
|
-
t && console.log(`Fallback triggered for: "${t}"`), console.log(this.fallbackMessage), new
|
|
383
|
+
t && console.log(`Fallback triggered for: "${t}"`), console.log(this.fallbackMessage), new P().speak(this.fallbackMessage);
|
|
379
384
|
}
|
|
380
385
|
getFallbackMessage() {
|
|
381
386
|
return this.fallbackMessage;
|
|
382
387
|
}
|
|
383
388
|
}
|
|
384
|
-
const
|
|
389
|
+
const $ = () => {
|
|
385
390
|
if (typeof window > "u") return null;
|
|
386
391
|
const d = window;
|
|
387
392
|
return d.SpeechRecognition ?? d.webkitSpeechRecognition ?? null;
|
|
388
393
|
};
|
|
389
|
-
class
|
|
394
|
+
class W {
|
|
390
395
|
constructor(t = "en-US", e = {}) {
|
|
391
396
|
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 = () => {
|
|
392
397
|
var s;
|
|
@@ -399,7 +404,7 @@ class O {
|
|
|
399
404
|
}, this.onTTSEnd = () => {
|
|
400
405
|
this.ttsSpeaking = !1, this.isListening && this.restartAllowed ? this.safeRestart() : this.emitStatus(this.isListening ? "listening" : "idle");
|
|
401
406
|
};
|
|
402
|
-
const i =
|
|
407
|
+
const i = $();
|
|
403
408
|
if (i) {
|
|
404
409
|
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 = () => {
|
|
405
410
|
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");
|
|
@@ -431,7 +436,7 @@ class O {
|
|
|
431
436
|
}
|
|
432
437
|
/** Check if SpeechRecognition is available */
|
|
433
438
|
isSupported() {
|
|
434
|
-
return
|
|
439
|
+
return $() !== null;
|
|
435
440
|
}
|
|
436
441
|
/** Allow consumers (wrappers) to observe status changes */
|
|
437
442
|
onStatusChange(t) {
|
|
@@ -469,11 +474,11 @@ class O {
|
|
|
469
474
|
var s, n;
|
|
470
475
|
if (!this.resultCallback) return;
|
|
471
476
|
const i = e.confidenceThreshold ?? 0.6;
|
|
472
|
-
for (let
|
|
473
|
-
const
|
|
474
|
-
if (
|
|
477
|
+
for (let a = t.resultIndex; a < t.results.length; a++) {
|
|
478
|
+
const o = t.results[a], c = o && o[0], u = ((n = (s = c == null ? void 0 : c.transcript) == null ? void 0 : s.trim) == null ? void 0 : n.call(s)) || "", r = (c == null ? void 0 : c.confidence) ?? 0;
|
|
479
|
+
if (u && !(!o.isFinal && e.interimResults === !1) && !(o.isFinal && r < i))
|
|
475
480
|
try {
|
|
476
|
-
this.hadResultThisSession = !0, this.resultCallback(
|
|
481
|
+
this.hadResultThisSession = !0, this.resultCallback(u, !!o.isFinal);
|
|
477
482
|
} catch {
|
|
478
483
|
this.error("VoiceProcessor: result callback error");
|
|
479
484
|
}
|
|
@@ -552,27 +557,29 @@ class O {
|
|
|
552
557
|
}
|
|
553
558
|
}
|
|
554
559
|
}
|
|
555
|
-
class
|
|
560
|
+
class R {
|
|
556
561
|
constructor() {
|
|
557
|
-
this.lastTap = 0;
|
|
562
|
+
this.lastTap = 0, this.tapCount = 0;
|
|
558
563
|
}
|
|
559
564
|
/**
|
|
560
|
-
* Sets up
|
|
561
|
-
* @param
|
|
565
|
+
* Sets up triple-click and triple-tap listeners
|
|
566
|
+
* @param onTripleClickOrTap Callback to execute when a triple-click or triple-tap is detected
|
|
562
567
|
*/
|
|
563
|
-
|
|
564
|
-
this.destroy(), this.
|
|
565
|
-
|
|
566
|
-
|
|
568
|
+
setupTripleTapListener(t) {
|
|
569
|
+
this.destroy(), this.clickListener = () => {
|
|
570
|
+
this.tapCount++, this.tapCount === 1 ? this.tapTimeout = window.setTimeout(() => {
|
|
571
|
+
this.tapCount = 0;
|
|
572
|
+
}, 500) : this.tapCount === 3 && (clearTimeout(this.tapTimeout), this.tapCount = 0, t());
|
|
573
|
+
}, document.addEventListener("click", this.clickListener), this.touchEndListener = () => {
|
|
567
574
|
const e = (/* @__PURE__ */ new Date()).getTime(), i = e - this.lastTap;
|
|
568
|
-
i <
|
|
575
|
+
i < 500 && i > 0 ? (this.tapCount++, this.tapCount === 3 && (this.tapCount = 0, t())) : this.tapCount = 1, this.lastTap = e;
|
|
569
576
|
}, document.addEventListener("touchend", this.touchEndListener);
|
|
570
577
|
}
|
|
571
578
|
destroy() {
|
|
572
|
-
this.dblClickListener && document.removeEventListener("dblclick", this.dblClickListener), this.touchEndListener && document.removeEventListener("touchend", this.touchEndListener), this.dblClickListener = void 0, this.touchEndListener = void 0;
|
|
579
|
+
this.dblClickListener && document.removeEventListener("dblclick", this.dblClickListener), this.touchEndListener && document.removeEventListener("touchend", this.touchEndListener), this.clickListener && document.removeEventListener("click", this.clickListener), this.tapTimeout && clearTimeout(this.tapTimeout), this.dblClickListener = void 0, this.touchEndListener = void 0, this.clickListener = void 0, this.tapTimeout = void 0, this.tapCount = 0;
|
|
573
580
|
}
|
|
574
581
|
}
|
|
575
|
-
function
|
|
582
|
+
function j() {
|
|
576
583
|
if (document.querySelector("#assistant-styles")) {
|
|
577
584
|
console.log("Styles already injected");
|
|
578
585
|
return;
|
|
@@ -613,20 +620,20 @@ function D() {
|
|
|
613
620
|
}
|
|
614
621
|
`, document.head.appendChild(t), console.log("Gradient styles injected");
|
|
615
622
|
}
|
|
616
|
-
function
|
|
623
|
+
function U() {
|
|
617
624
|
if (document.querySelector("#gradient-indicator"))
|
|
618
625
|
return;
|
|
619
626
|
const d = document.createElement("div");
|
|
620
|
-
d.id = "gradient-indicator",
|
|
627
|
+
d.id = "gradient-indicator", j(), d.classList.add("gradient-indicator"), document.body.appendChild(d), console.log("Gradient indicator added to the DOM");
|
|
621
628
|
}
|
|
622
|
-
function
|
|
629
|
+
function D() {
|
|
623
630
|
const d = document.querySelector("#gradient-indicator");
|
|
624
631
|
d && (d.remove(), console.log("Gradient indicator removed from the DOM"));
|
|
625
632
|
}
|
|
626
633
|
function V() {
|
|
627
634
|
return typeof window < "u" && typeof document < "u";
|
|
628
635
|
}
|
|
629
|
-
class
|
|
636
|
+
class _ {
|
|
630
637
|
constructor() {
|
|
631
638
|
this.state = "idle", this.subscribers = [];
|
|
632
639
|
}
|
|
@@ -634,7 +641,7 @@ class G {
|
|
|
634
641
|
return this.state;
|
|
635
642
|
}
|
|
636
643
|
setState(t) {
|
|
637
|
-
this.state = t, this.notifySubscribers(), console.log("State updated:", t), t === "listening" ?
|
|
644
|
+
this.state = t, this.notifySubscribers(), console.log("State updated:", t), t === "listening" ? U() : D();
|
|
638
645
|
}
|
|
639
646
|
// eslint-disable-next-line no-unused-vars
|
|
640
647
|
subscribe(t) {
|
|
@@ -644,9 +651,81 @@ class G {
|
|
|
644
651
|
this.subscribers.forEach((t) => t(this.state));
|
|
645
652
|
}
|
|
646
653
|
}
|
|
647
|
-
class
|
|
654
|
+
class G {
|
|
648
655
|
constructor(t) {
|
|
649
|
-
this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1, this.loadingEl = null, this.
|
|
656
|
+
this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1, this.loadingEl = null, this.commandHandlers = /* @__PURE__ */ new Map(), this.active = V(), this.handleClickOutside = (e) => {
|
|
657
|
+
const i = e.target;
|
|
658
|
+
this.chatWindow && this.chatWindow.contains(i) || i.closest(".foisit-floating-btn") || this.toggle();
|
|
659
|
+
}, this.config = t, this.active && this.init();
|
|
660
|
+
}
|
|
661
|
+
/** Register a command handler that can be invoked programmatically via `runCommand` */
|
|
662
|
+
registerCommandHandler(t, e) {
|
|
663
|
+
!t || typeof e != "function" || this.commandHandlers.set(t, e);
|
|
664
|
+
}
|
|
665
|
+
/** Check whether a programmatic handler is registered locally */
|
|
666
|
+
hasCommandHandler(t) {
|
|
667
|
+
return this.commandHandlers.has(t);
|
|
668
|
+
}
|
|
669
|
+
/** Set an external executor (used to run commands registered via CommandHandler) */
|
|
670
|
+
setExternalCommandExecutor(t) {
|
|
671
|
+
this.externalCommandExecutor = t;
|
|
672
|
+
}
|
|
673
|
+
/** Unregister a previously registered command handler */
|
|
674
|
+
unregisterCommandHandler(t) {
|
|
675
|
+
t && this.commandHandlers.delete(t);
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Run a registered command by id. Options:
|
|
679
|
+
* - `params`: passed to the handler
|
|
680
|
+
* - `openOverlay`: if true, open the overlay before running
|
|
681
|
+
* - `showInvocation`: if true, show the invocation as a user message
|
|
682
|
+
*/
|
|
683
|
+
async runCommand(t) {
|
|
684
|
+
if (!t || !t.commandId)
|
|
685
|
+
throw new Error("runCommand requires a commandId");
|
|
686
|
+
const {
|
|
687
|
+
commandId: e,
|
|
688
|
+
params: i,
|
|
689
|
+
openOverlay: s = !0,
|
|
690
|
+
showInvocation: n = !0
|
|
691
|
+
} = t;
|
|
692
|
+
s && !this.isOpen && this.toggle();
|
|
693
|
+
const a = this.commandHandlers.get(e);
|
|
694
|
+
if (a && n && this.messagesContainer && this.addMessage(`Command: ${e}`, "user"), a)
|
|
695
|
+
try {
|
|
696
|
+
this.showLoading();
|
|
697
|
+
const o = await a(i);
|
|
698
|
+
if (this.hideLoading(), typeof o == "string")
|
|
699
|
+
this.addMessage(o, "system");
|
|
700
|
+
else if (o && typeof o == "object")
|
|
701
|
+
try {
|
|
702
|
+
this.addMessage(JSON.stringify(o, null, 2), "system");
|
|
703
|
+
} catch {
|
|
704
|
+
this.addMessage(String(o), "system");
|
|
705
|
+
}
|
|
706
|
+
else o == null || this.addMessage(String(o), "system");
|
|
707
|
+
return o;
|
|
708
|
+
} catch (o) {
|
|
709
|
+
throw this.hideLoading(), this.addMessage(
|
|
710
|
+
`Command "${e}" failed: ${String(o)}`,
|
|
711
|
+
"system"
|
|
712
|
+
), o;
|
|
713
|
+
}
|
|
714
|
+
if (this.externalCommandExecutor)
|
|
715
|
+
try {
|
|
716
|
+
this.showLoading();
|
|
717
|
+
const o = await this.externalCommandExecutor({ commandId: e, params: i });
|
|
718
|
+
return this.hideLoading(), o;
|
|
719
|
+
} catch (o) {
|
|
720
|
+
throw this.hideLoading(), this.addMessage(
|
|
721
|
+
`Command "${e}" failed: ${String(o)}`,
|
|
722
|
+
"system"
|
|
723
|
+
), o;
|
|
724
|
+
}
|
|
725
|
+
this.addMessage(
|
|
726
|
+
`No handler registered for command "${e}".`,
|
|
727
|
+
"system"
|
|
728
|
+
);
|
|
650
729
|
}
|
|
651
730
|
init() {
|
|
652
731
|
var e, i;
|
|
@@ -654,17 +733,23 @@ class Y {
|
|
|
654
733
|
this.injectOverlayStyles();
|
|
655
734
|
const t = document.getElementById("foisit-overlay-container");
|
|
656
735
|
if (t && t instanceof HTMLElement) {
|
|
657
|
-
this.container = t, this.chatWindow = t.querySelector(
|
|
736
|
+
this.container = t, this.chatWindow = t.querySelector(
|
|
737
|
+
".foisit-chat"
|
|
738
|
+
), this.messagesContainer = t.querySelector(
|
|
739
|
+
".foisit-messages"
|
|
740
|
+
), this.input = t.querySelector(
|
|
741
|
+
"input.foisit-input"
|
|
742
|
+
), ((e = this.config.floatingButton) == null ? void 0 : e.visible) !== !1 && !t.querySelector(".foisit-floating-btn") && this.renderFloatingButton(), this.chatWindow || this.renderChatWindow(), this.config.enableGestureActivation && (this.gestureHandler = new R(), this.gestureHandler.setupTripleTapListener(() => this.toggle()));
|
|
658
743
|
return;
|
|
659
744
|
}
|
|
660
|
-
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();
|
|
745
|
+
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(), this.config.enableGestureActivation && (this.gestureHandler = new R(), this.gestureHandler.setupTripleTapListener(() => this.toggle()));
|
|
661
746
|
}
|
|
662
747
|
renderFloatingButton() {
|
|
663
|
-
var s, n,
|
|
748
|
+
var s, n, a, o, c, u;
|
|
664
749
|
const t = document.createElement("button");
|
|
665
750
|
t.innerHTML = ((s = this.config.floatingButton) == null ? void 0 : s.customHtml) || "🎙️";
|
|
666
|
-
const e = ((
|
|
667
|
-
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)", (
|
|
751
|
+
const e = ((a = (n = this.config.floatingButton) == null ? void 0 : n.position) == null ? void 0 : a.bottom) || "20px", i = ((c = (o = this.config.floatingButton) == null ? void 0 : o.position) == null ? void 0 : c.right) || "20px";
|
|
752
|
+
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)", (u = this.container) == null || u.appendChild(t);
|
|
668
753
|
}
|
|
669
754
|
renderChatWindow() {
|
|
670
755
|
var n;
|
|
@@ -677,9 +762,9 @@ class Y {
|
|
|
677
762
|
const i = document.createElement("button");
|
|
678
763
|
i.type = "button", i.className = "foisit-close", i.setAttribute("aria-label", "Close"), i.innerHTML = "×", i.addEventListener("click", () => this.toggle()), t.appendChild(e), t.appendChild(i), this.messagesContainer = document.createElement("div"), this.messagesContainer.className = "foisit-messages";
|
|
679
764
|
const s = document.createElement("div");
|
|
680
|
-
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", (
|
|
681
|
-
var
|
|
682
|
-
if (
|
|
765
|
+
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) => {
|
|
766
|
+
var o;
|
|
767
|
+
if (a.key === "Enter" && ((o = this.input) != null && o.value.trim())) {
|
|
683
768
|
const c = this.input.value.trim();
|
|
684
769
|
this.input.value = "", this.onSubmit && this.onSubmit(c);
|
|
685
770
|
}
|
|
@@ -689,19 +774,27 @@ class Y {
|
|
|
689
774
|
this.active && (this.onSubmit = t, this.onClose = e);
|
|
690
775
|
}
|
|
691
776
|
toggle(t, e) {
|
|
692
|
-
this.active && (t && (this.onSubmit = t), e && (this.onClose = e), this.isOpen = !this.isOpen, this.chatWindow && (this.isOpen ? (this.chatWindow.style.display = "flex", requestAnimationFrame(() => {
|
|
777
|
+
this.active && (t && (this.onSubmit = t), e && (this.onClose = e), this.isOpen = !this.isOpen, this.chatWindow && (this.isOpen ? (this.container && (this.container.style.pointerEvents = "auto"), this.chatWindow.style.display = "flex", requestAnimationFrame(() => {
|
|
693
778
|
this.chatWindow && (this.chatWindow.style.opacity = "1", this.chatWindow.style.transform = "translateY(0) scale(1)");
|
|
694
779
|
}), setTimeout(() => {
|
|
695
780
|
var i;
|
|
696
781
|
return (i = this.input) == null ? void 0 : i.focus();
|
|
697
|
-
}, 100)) : (this.chatWindow.style.opacity = "0", this.chatWindow.style.transform = "translateY(20px) scale(0.95)", setTimeout(() => {
|
|
782
|
+
}, 100), this.addClickOutsideListener()) : (this.chatWindow.style.opacity = "0", this.chatWindow.style.transform = "translateY(20px) scale(0.95)", setTimeout(() => {
|
|
698
783
|
this.chatWindow && !this.isOpen && (this.chatWindow.style.display = "none");
|
|
699
|
-
}, 200), this.onClose && this.onClose())));
|
|
784
|
+
}, 200), this.onClose && this.onClose(), this.removeClickOutsideListener(), this.container && (this.container.style.pointerEvents = "none"))));
|
|
785
|
+
}
|
|
786
|
+
addClickOutsideListener() {
|
|
787
|
+
this.container && (this.removeClickOutsideListener(), this.container.addEventListener("click", this.handleClickOutside));
|
|
788
|
+
}
|
|
789
|
+
removeClickOutsideListener() {
|
|
790
|
+
this.container && this.container.removeEventListener("click", this.handleClickOutside);
|
|
700
791
|
}
|
|
701
792
|
addMessage(t, e) {
|
|
702
793
|
if (!this.messagesContainer) return;
|
|
703
794
|
const i = document.createElement("div");
|
|
704
|
-
i.textContent = t, i.className = e === "user" ? "foisit-bubble user" : "foisit-bubble system"
|
|
795
|
+
e === "system" ? i.innerHTML = this.renderMarkdown(t) : i.textContent = t, i.className = e === "user" ? "foisit-bubble user" : "foisit-bubble system";
|
|
796
|
+
const s = (t || "").length || 0, n = Math.max(120, 700 - Math.min(600, Math.floor(s * 6)));
|
|
797
|
+
i.style.opacity = "0", i.style.transform = "translateY(8px)", i.style.transition = "none", this.messagesContainer.appendChild(i), this.animateMessageEntrance(i, n), this.scrollToBottom();
|
|
705
798
|
}
|
|
706
799
|
addOptions(t) {
|
|
707
800
|
if (!this.messagesContainer) return;
|
|
@@ -714,11 +807,11 @@ class Y {
|
|
|
714
807
|
this.onSubmit && this.onSubmit({ commandId: i.commandId });
|
|
715
808
|
return;
|
|
716
809
|
}
|
|
717
|
-
const
|
|
718
|
-
this.onSubmit && this.onSubmit(
|
|
810
|
+
const a = i && typeof i.value == "string" && i.value.trim() ? i.value : i.label;
|
|
811
|
+
this.onSubmit && this.onSubmit(a);
|
|
719
812
|
};
|
|
720
|
-
s.onclick = n, s.onkeydown = (
|
|
721
|
-
(
|
|
813
|
+
s.onclick = n, s.onkeydown = (a) => {
|
|
814
|
+
(a.key === "Enter" || a.key === " ") && (a.preventDefault(), n());
|
|
722
815
|
}, e.appendChild(s);
|
|
723
816
|
}), this.messagesContainer.appendChild(e), this.scrollToBottom();
|
|
724
817
|
}
|
|
@@ -727,89 +820,95 @@ class Y {
|
|
|
727
820
|
this.addMessage(t, "system");
|
|
728
821
|
const s = document.createElement("form");
|
|
729
822
|
s.className = "foisit-form";
|
|
730
|
-
const n = [],
|
|
823
|
+
const n = [], a = (r, p) => {
|
|
731
824
|
const g = document.createElement("div");
|
|
732
|
-
return g.className = "foisit-form-label", g.innerHTML =
|
|
733
|
-
},
|
|
734
|
-
const
|
|
735
|
-
return
|
|
825
|
+
return g.className = "foisit-form-label", g.innerHTML = r + (p ? ' <span class="foisit-req-star">*</span>' : ""), g;
|
|
826
|
+
}, o = () => {
|
|
827
|
+
const r = document.createElement("div");
|
|
828
|
+
return r.className = "foisit-form-error", r.style.display = "none", r;
|
|
736
829
|
};
|
|
737
|
-
(e ?? []).forEach((
|
|
830
|
+
(e ?? []).forEach((r) => {
|
|
738
831
|
const p = document.createElement("div");
|
|
739
832
|
p.className = "foisit-form-group";
|
|
740
|
-
const g =
|
|
741
|
-
p.appendChild(
|
|
833
|
+
const g = r.description || r.name;
|
|
834
|
+
p.appendChild(a(g, r.required));
|
|
742
835
|
let m;
|
|
743
|
-
if (
|
|
836
|
+
if (r.type === "select") {
|
|
744
837
|
const l = document.createElement("select");
|
|
745
838
|
l.className = "foisit-form-input";
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
const
|
|
749
|
-
(h ?? []).forEach((
|
|
750
|
-
const
|
|
751
|
-
|
|
839
|
+
const y = document.createElement("option");
|
|
840
|
+
y.value = "", y.textContent = "Select...", l.appendChild(y);
|
|
841
|
+
const x = (h) => {
|
|
842
|
+
(h ?? []).forEach((w) => {
|
|
843
|
+
const b = document.createElement("option");
|
|
844
|
+
b.value = String(w.value ?? w.label ?? ""), b.textContent = String(w.label ?? w.value ?? ""), l.appendChild(b);
|
|
752
845
|
});
|
|
753
846
|
};
|
|
754
|
-
if (Array.isArray(
|
|
755
|
-
|
|
756
|
-
else if (typeof
|
|
757
|
-
const h =
|
|
758
|
-
|
|
847
|
+
if (Array.isArray(r.options) && r.options.length)
|
|
848
|
+
x(r.options);
|
|
849
|
+
else if (typeof r.getOptions == "function") {
|
|
850
|
+
const h = r.getOptions, w = document.createElement("option");
|
|
851
|
+
w.value = "", w.textContent = "Loading...", l.appendChild(w), Promise.resolve().then(() => h()).then((b) => {
|
|
759
852
|
for (; l.options.length > 1; ) l.remove(1);
|
|
760
|
-
|
|
853
|
+
x(b);
|
|
761
854
|
}).catch(() => {
|
|
762
855
|
for (; l.options.length > 1; ) l.remove(1);
|
|
763
|
-
const
|
|
764
|
-
|
|
856
|
+
const b = document.createElement("option");
|
|
857
|
+
b.value = "", b.textContent = "Error loading options", l.appendChild(b);
|
|
765
858
|
});
|
|
766
859
|
}
|
|
767
|
-
|
|
768
|
-
} else if (
|
|
769
|
-
const l =
|
|
770
|
-
|
|
771
|
-
const
|
|
772
|
-
if (h.style.display = "none", h.textContent = "",
|
|
773
|
-
const
|
|
774
|
-
if (
|
|
775
|
-
h.textContent = `Please select at most ${
|
|
860
|
+
r.defaultValue != null && (l.value = String(r.defaultValue)), m = l;
|
|
861
|
+
} else if (r.type === "file") {
|
|
862
|
+
const l = r, y = document.createElement("input");
|
|
863
|
+
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 () => {
|
|
864
|
+
const x = Array.from(y.files || []), h = C;
|
|
865
|
+
if (h.style.display = "none", h.textContent = "", x.length === 0) return;
|
|
866
|
+
const w = l.maxFiles ?? (l.multiple ? 10 : 1);
|
|
867
|
+
if (x.length > w) {
|
|
868
|
+
h.textContent = `Please select at most ${w} file(s).`, h.style.display = "block";
|
|
776
869
|
return;
|
|
777
870
|
}
|
|
778
|
-
const
|
|
779
|
-
if (
|
|
780
|
-
h.textContent = `One or more files exceed the maximum size of ${Math.round(
|
|
871
|
+
const b = l.maxSizeBytes ?? 1 / 0, f = x.reduce((v, E) => v + E.size, 0);
|
|
872
|
+
if (x.some((v) => v.size > b)) {
|
|
873
|
+
h.textContent = `One or more files exceed the maximum size of ${Math.round(
|
|
874
|
+
b / 1024
|
|
875
|
+
)} KB.`, h.style.display = "block";
|
|
781
876
|
return;
|
|
782
877
|
}
|
|
783
878
|
const S = l.maxTotalBytes ?? 1 / 0;
|
|
784
|
-
if (
|
|
785
|
-
h.textContent = `Total selected files exceed the maximum of ${Math.round(
|
|
879
|
+
if (f > S) {
|
|
880
|
+
h.textContent = `Total selected files exceed the maximum of ${Math.round(
|
|
881
|
+
S / 1024
|
|
882
|
+
)} KB.`, h.style.display = "block";
|
|
786
883
|
return;
|
|
787
884
|
}
|
|
788
885
|
if (l.accept && Array.isArray(l.accept)) {
|
|
789
886
|
const v = l.accept;
|
|
790
|
-
if (!
|
|
887
|
+
if (!x.every((L) => L.type ? v.some(
|
|
888
|
+
(A) => A.startsWith(".") ? L.name.toLowerCase().endsWith(A.toLowerCase()) : L.type === A || L.type.startsWith(A.split("/")[0] + "/")
|
|
889
|
+
) : !0)) {
|
|
791
890
|
h.textContent = "One or more files have an unsupported type.", h.style.display = "block";
|
|
792
891
|
return;
|
|
793
892
|
}
|
|
794
893
|
}
|
|
795
|
-
}), m =
|
|
894
|
+
}), m = y;
|
|
796
895
|
} else {
|
|
797
896
|
const l = document.createElement("input");
|
|
798
|
-
l.className = "foisit-form-input",
|
|
897
|
+
l.className = "foisit-form-input", r.type === "string" && (l.placeholder = r.placeholder || "Type here..."), r.type === "number" ? (l.type = "number", typeof r.min == "number" && (l.min = String(r.min)), typeof r.max == "number" && (l.max = String(r.max)), typeof r.step == "number" && (l.step = String(r.step)), r.defaultValue != null && (l.value = String(r.defaultValue))) : r.type === "date" ? (l.type = "date", typeof r.min == "string" && (l.min = r.min), typeof r.max == "string" && (l.max = r.max), r.defaultValue != null && (l.value = String(r.defaultValue))) : (l.type = "text", r.defaultValue != null && (l.value = String(r.defaultValue))), m = l;
|
|
799
898
|
}
|
|
800
|
-
const C =
|
|
899
|
+
const C = o();
|
|
801
900
|
p.appendChild(m), p.appendChild(C), n.push({
|
|
802
|
-
name:
|
|
803
|
-
type:
|
|
901
|
+
name: r.name,
|
|
902
|
+
type: r.type,
|
|
804
903
|
el: m,
|
|
805
|
-
required:
|
|
904
|
+
required: r.required
|
|
806
905
|
}), s.appendChild(p);
|
|
807
906
|
});
|
|
808
907
|
const c = document.createElement("div");
|
|
809
908
|
c.className = "foisit-form-actions";
|
|
810
|
-
const
|
|
811
|
-
|
|
812
|
-
|
|
909
|
+
const u = document.createElement("button");
|
|
910
|
+
u.type = "submit", u.textContent = "Submit", u.className = "foisit-option-chip", u.style.fontWeight = "600", c.appendChild(u), s.appendChild(c), s.onsubmit = async (r) => {
|
|
911
|
+
r.preventDefault();
|
|
813
912
|
const p = {};
|
|
814
913
|
let g = !1;
|
|
815
914
|
s.querySelectorAll(".foisit-form-error").forEach((m) => {
|
|
@@ -819,56 +918,62 @@ class Y {
|
|
|
819
918
|
});
|
|
820
919
|
for (const m of n) {
|
|
821
920
|
if (m.type === "file") {
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
|
|
921
|
+
const x = m.el.parentElement, h = x == null ? void 0 : x.querySelector(
|
|
922
|
+
".foisit-form-error"
|
|
923
|
+
), w = m.el, b = Array.from(w.files || []);
|
|
924
|
+
if (m.required && b.length === 0) {
|
|
925
|
+
g = !0, w.classList.add("foisit-error-border"), h && (h.textContent = "This file is required", h.style.display = "block");
|
|
825
926
|
continue;
|
|
826
927
|
}
|
|
827
|
-
if (
|
|
828
|
-
const
|
|
829
|
-
if (
|
|
928
|
+
if (b.length === 0) continue;
|
|
929
|
+
const f = (e ?? []).find((v) => v.name === m.name), S = (f == null ? void 0 : f.delivery) ?? "file";
|
|
930
|
+
if (f != null && f.maxWidth || f != null && f.maxHeight)
|
|
830
931
|
try {
|
|
831
|
-
const v = await this.getImageDimensions(
|
|
832
|
-
if (
|
|
833
|
-
g = !0, h && (h.textContent = `Image width must be ≤ ${
|
|
932
|
+
const v = await this.getImageDimensions(b[0]);
|
|
933
|
+
if (f.maxWidth && v.width > f.maxWidth) {
|
|
934
|
+
g = !0, h && (h.textContent = `Image width must be ≤ ${f.maxWidth}px`, h.style.display = "block");
|
|
834
935
|
continue;
|
|
835
936
|
}
|
|
836
|
-
if (
|
|
837
|
-
g = !0, h && (h.textContent = `Image height must be ≤ ${
|
|
937
|
+
if (f.maxHeight && v.height > f.maxHeight) {
|
|
938
|
+
g = !0, h && (h.textContent = `Image height must be ≤ ${f.maxHeight}px`, h.style.display = "block");
|
|
838
939
|
continue;
|
|
839
940
|
}
|
|
840
941
|
} catch {
|
|
841
942
|
}
|
|
842
|
-
if (
|
|
943
|
+
if (f != null && f.maxDurationSec)
|
|
843
944
|
try {
|
|
844
|
-
const v = await this.getMediaDuration(
|
|
845
|
-
if (v && v >
|
|
846
|
-
g = !0, h && (h.textContent = `Media duration must be ≤ ${
|
|
945
|
+
const v = await this.getMediaDuration(b[0]);
|
|
946
|
+
if (v && v > f.maxDurationSec) {
|
|
947
|
+
g = !0, h && (h.textContent = `Media duration must be ≤ ${f.maxDurationSec}s`, h.style.display = "block");
|
|
847
948
|
continue;
|
|
848
949
|
}
|
|
849
950
|
} catch {
|
|
850
951
|
}
|
|
851
952
|
if (S === "file")
|
|
852
|
-
p[m.name] =
|
|
953
|
+
p[m.name] = f != null && f.multiple ? b : b[0];
|
|
853
954
|
else if (S === "base64")
|
|
854
955
|
try {
|
|
855
|
-
const v = await Promise.all(
|
|
856
|
-
|
|
956
|
+
const v = await Promise.all(
|
|
957
|
+
b.map((E) => this.readFileAsDataURL(E))
|
|
958
|
+
);
|
|
959
|
+
p[m.name] = f != null && f.multiple ? v : v[0];
|
|
857
960
|
} catch {
|
|
858
961
|
g = !0, h && (h.textContent = "Failed to encode file(s) to base64.", h.style.display = "block");
|
|
859
962
|
continue;
|
|
860
963
|
}
|
|
861
964
|
continue;
|
|
862
965
|
}
|
|
863
|
-
const C = (m.el.value ?? "").toString().trim(), l = m.el.parentElement,
|
|
966
|
+
const C = (m.el.value ?? "").toString().trim(), l = m.el.parentElement, y = l == null ? void 0 : l.querySelector(
|
|
967
|
+
".foisit-form-error"
|
|
968
|
+
);
|
|
864
969
|
if (m.required && (C == null || C === "")) {
|
|
865
|
-
g = !0, m.el.classList.add("foisit-error-border"),
|
|
970
|
+
g = !0, m.el.classList.add("foisit-error-border"), y && (y.textContent = "This field is required", y.style.display = "block");
|
|
866
971
|
continue;
|
|
867
972
|
}
|
|
868
973
|
if (C !== "")
|
|
869
974
|
if (m.type === "number") {
|
|
870
|
-
const
|
|
871
|
-
Number.isNaN(
|
|
975
|
+
const x = Number(C);
|
|
976
|
+
Number.isNaN(x) || (p[m.name] = x);
|
|
872
977
|
} else
|
|
873
978
|
p[m.name] = C;
|
|
874
979
|
}
|
|
@@ -876,7 +981,7 @@ class Y {
|
|
|
876
981
|
s.classList.add("foisit-shake"), setTimeout(() => s.classList.remove("foisit-shake"), 400);
|
|
877
982
|
return;
|
|
878
983
|
}
|
|
879
|
-
|
|
984
|
+
u.disabled = !0, u.style.opacity = "0.6", n.forEach((m) => {
|
|
880
985
|
m.el.disabled = !0;
|
|
881
986
|
}), i(p);
|
|
882
987
|
}, this.messagesContainer.appendChild(s), this.scrollToBottom();
|
|
@@ -898,9 +1003,72 @@ class Y {
|
|
|
898
1003
|
scrollToBottom() {
|
|
899
1004
|
this.messagesContainer && (this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight);
|
|
900
1005
|
}
|
|
1006
|
+
/** Subtle entrance animation for new messages */
|
|
1007
|
+
animateMessageEntrance(t, e) {
|
|
1008
|
+
if (!t) return;
|
|
1009
|
+
t.style.transition = `opacity ${e}ms cubic-bezier(0.22, 0.9, 0.32, 1), transform ${Math.max(
|
|
1010
|
+
120,
|
|
1011
|
+
e
|
|
1012
|
+
)}ms cubic-bezier(0.22, 0.9, 0.32, 1)`, requestAnimationFrame(() => {
|
|
1013
|
+
t.style.opacity = "1", t.style.transform = "translateY(0)";
|
|
1014
|
+
});
|
|
1015
|
+
const i = () => {
|
|
1016
|
+
try {
|
|
1017
|
+
t.style.transition = "";
|
|
1018
|
+
} catch {
|
|
1019
|
+
}
|
|
1020
|
+
t.removeEventListener("transitionend", i);
|
|
1021
|
+
};
|
|
1022
|
+
t.addEventListener("transitionend", i);
|
|
1023
|
+
}
|
|
1024
|
+
/** Smoothly scroll messages container to bottom over duration (ms) */
|
|
1025
|
+
animateScrollToBottom(t) {
|
|
1026
|
+
if (!this.messagesContainer) return;
|
|
1027
|
+
const e = this.messagesContainer, i = e.scrollTop, s = e.scrollHeight - e.clientHeight;
|
|
1028
|
+
if (s <= i || t <= 0) {
|
|
1029
|
+
e.scrollTop = s;
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
const n = s - i, a = performance.now(), o = (c) => {
|
|
1033
|
+
const u = Math.min(1, (c - a) / t), r = 1 - Math.pow(1 - u, 3);
|
|
1034
|
+
e.scrollTop = Math.round(i + n * r), u < 1 && requestAnimationFrame(o);
|
|
1035
|
+
};
|
|
1036
|
+
requestAnimationFrame(o);
|
|
1037
|
+
}
|
|
901
1038
|
destroy() {
|
|
902
1039
|
var t;
|
|
903
|
-
(t = this.container) == null || t.remove(), this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1;
|
|
1040
|
+
this.removeClickOutsideListener(), (t = this.container) == null || t.remove(), this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1;
|
|
1041
|
+
}
|
|
1042
|
+
/** Escape HTML special characters to prevent XSS */
|
|
1043
|
+
escapeHtml(t) {
|
|
1044
|
+
const e = {
|
|
1045
|
+
"&": "&",
|
|
1046
|
+
"<": "<",
|
|
1047
|
+
">": ">",
|
|
1048
|
+
'"': """,
|
|
1049
|
+
"'": "'"
|
|
1050
|
+
};
|
|
1051
|
+
return t.replace(/[&<>"']/g, (i) => e[i]);
|
|
1052
|
+
}
|
|
1053
|
+
/** Simple markdown renderer for AI responses */
|
|
1054
|
+
renderMarkdown(t) {
|
|
1055
|
+
let e = this.escapeHtml(t);
|
|
1056
|
+
return e = e.replace(/```(\w*)\n([\s\S]*?)```/g, (i, s, n) => `<pre class="foisit-code-block"><code${s ? ` class="language-${s}"` : ""}>${n.trim()}</code></pre>`), e = e.replace(
|
|
1057
|
+
/`([^`]+)`/g,
|
|
1058
|
+
'<code class="foisit-inline-code">$1</code>'
|
|
1059
|
+
), e = e.replace(/^###### (.+)$/gm, '<h6 class="foisit-md-h6">$1</h6>'), e = e.replace(/^##### (.+)$/gm, '<h5 class="foisit-md-h5">$1</h5>'), e = e.replace(/^#### (.+)$/gm, '<h4 class="foisit-md-h4">$1</h4>'), e = e.replace(/^### (.+)$/gm, '<h3 class="foisit-md-h3">$1</h3>'), e = e.replace(/^## (.+)$/gm, '<h2 class="foisit-md-h2">$1</h2>'), e = e.replace(/^# (.+)$/gm, '<h1 class="foisit-md-h1">$1</h1>'), e = e.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>"), e = e.replace(/__([^_]+)__/g, "<strong>$1</strong>"), e = e.replace(/\*([^*]+)\*/g, "<em>$1</em>"), e = e.replace(new RegExp("(?<!_)_([^_]+)_(?!_)", "g"), "<em>$1</em>"), e = e.replace(/~~([^~]+)~~/g, "<del>$1</del>"), e = e.replace(
|
|
1060
|
+
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
1061
|
+
'<a href="$2" target="_blank" rel="noopener noreferrer" class="foisit-md-link">$1</a>'
|
|
1062
|
+
), e = e.replace(/^[\-\*] (.+)$/gm, '<li class="foisit-md-li">$1</li>'), e = e.replace(
|
|
1063
|
+
/(<li class="foisit-md-li">.*<\/li>\n?)+/g,
|
|
1064
|
+
(i) => `<ul class="foisit-md-ul">${i}</ul>`
|
|
1065
|
+
), e = e.replace(/^\d+\. (.+)$/gm, '<li class="foisit-md-li">$1</li>'), e = e.replace(
|
|
1066
|
+
new RegExp('(?<!<\\/ul>)(<li class="foisit-md-li">.*<\\/li>\\n?)+', "g"),
|
|
1067
|
+
(i) => i.includes("<ul") ? i : `<ol class="foisit-md-ol">${i}</ol>`
|
|
1068
|
+
), e = e.replace(
|
|
1069
|
+
/^> (.+)$/gm,
|
|
1070
|
+
'<blockquote class="foisit-md-blockquote">$1</blockquote>'
|
|
1071
|
+
), e = e.replace(/^(---|___|\*\*\*)$/gm, '<hr class="foisit-md-hr">'), e = e.replace(/\n\n+/g, '</p><p class="foisit-md-p">'), e = e.replace(/\n/g, "<br>"), e.match(/^<(h[1-6]|ul|ol|pre|blockquote|hr|p)/) || (e = `<p class="foisit-md-p">${e}</p>`), e;
|
|
904
1072
|
}
|
|
905
1073
|
readFileAsDataURL(t) {
|
|
906
1074
|
return new Promise((e, i) => {
|
|
@@ -913,7 +1081,10 @@ class Y {
|
|
|
913
1081
|
try {
|
|
914
1082
|
const i = URL.createObjectURL(t), s = new Image();
|
|
915
1083
|
s.onload = () => {
|
|
916
|
-
const n = {
|
|
1084
|
+
const n = {
|
|
1085
|
+
width: s.naturalWidth || s.width,
|
|
1086
|
+
height: s.naturalHeight || s.height
|
|
1087
|
+
};
|
|
917
1088
|
URL.revokeObjectURL(i), e(n);
|
|
918
1089
|
}, s.onerror = () => {
|
|
919
1090
|
URL.revokeObjectURL(i), e({ width: 0, height: 0 });
|
|
@@ -928,16 +1099,16 @@ class Y {
|
|
|
928
1099
|
try {
|
|
929
1100
|
const i = URL.createObjectURL(t), s = t.type.startsWith("audio") ? document.createElement("audio") : document.createElement("video");
|
|
930
1101
|
let n = !1;
|
|
931
|
-
const
|
|
1102
|
+
const a = setTimeout(() => {
|
|
932
1103
|
n || (n = !0, URL.revokeObjectURL(i), e(0));
|
|
933
1104
|
}, 5e3);
|
|
934
1105
|
s.preload = "metadata", s.onloadedmetadata = () => {
|
|
935
1106
|
if (n) return;
|
|
936
|
-
n = !0, clearTimeout(
|
|
1107
|
+
n = !0, clearTimeout(a);
|
|
937
1108
|
const c = s.duration || 0;
|
|
938
1109
|
URL.revokeObjectURL(i), e(c);
|
|
939
1110
|
}, s.onerror = () => {
|
|
940
|
-
n || (n = !0, clearTimeout(
|
|
1111
|
+
n || (n = !0, clearTimeout(a), URL.revokeObjectURL(i), e(0));
|
|
941
1112
|
}, s.src = i;
|
|
942
1113
|
} catch {
|
|
943
1114
|
e(0);
|
|
@@ -947,57 +1118,93 @@ class Y {
|
|
|
947
1118
|
injectOverlayStyles() {
|
|
948
1119
|
if (document.getElementById("foisit-overlay-styles")) return;
|
|
949
1120
|
const t = document.createElement("style");
|
|
950
|
-
t.id = "foisit-overlay-styles"
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1121
|
+
t.id = "foisit-overlay-styles";
|
|
1122
|
+
const e = this.config.theme || "glass", i = this.config.themeColors || {};
|
|
1123
|
+
if (e === "solid") {
|
|
1124
|
+
const s = i.background || "#1a1a2e", n = i.text || "#ffffff", a = i.accent || "linear-gradient(135deg, #667eea 0%, #764ba2 100%)", o = i.userBubbleBg || "rgba(102, 126, 234, 0.2)", c = i.systemBubbleBg || "rgba(255, 255, 255, 0.08)", u = i.border || "rgba(255, 255, 255, 0.1)";
|
|
1125
|
+
t.textContent = `
|
|
1126
|
+
:root {
|
|
1127
|
+
/* SOLID THEME - Custom Colors */
|
|
1128
|
+
--foisit-bg: ${s};
|
|
1129
|
+
--foisit-border: 1px solid ${u};
|
|
1130
|
+
--foisit-shadow: 0 16px 48px rgba(0, 0, 0, 0.4);
|
|
1131
|
+
--foisit-text: ${n};
|
|
1132
|
+
--foisit-accent: ${a};
|
|
1133
|
+
--foisit-backdrop: none;
|
|
962
1134
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1135
|
+
/* Input */
|
|
1136
|
+
--foisit-input-color: ${n};
|
|
1137
|
+
--foisit-input-placeholder: ${n}99;
|
|
966
1138
|
|
|
967
|
-
|
|
968
|
-
|
|
1139
|
+
/* Bubbles */
|
|
1140
|
+
--foisit-bubble-user-bg: ${o};
|
|
1141
|
+
--foisit-bubble-user-text: ${n};
|
|
969
1142
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
--foisit-error-text: #dc2626;
|
|
973
|
-
--foisit-error-border: #fca5a5;
|
|
974
|
-
}
|
|
1143
|
+
--foisit-bubble-sys-bg: ${c};
|
|
1144
|
+
--foisit-bubble-sys-text: ${n}ee;
|
|
975
1145
|
|
|
976
|
-
|
|
1146
|
+
/* Form Colors */
|
|
1147
|
+
--foisit-req-star: #f87171;
|
|
1148
|
+
--foisit-error-text: #fca5a5;
|
|
1149
|
+
--foisit-error-border: #f87171;
|
|
1150
|
+
}
|
|
1151
|
+
`;
|
|
1152
|
+
} else
|
|
1153
|
+
t.textContent = `
|
|
977
1154
|
:root {
|
|
978
|
-
/*
|
|
979
|
-
|
|
980
|
-
--foisit-
|
|
981
|
-
--foisit-
|
|
982
|
-
--foisit-
|
|
1155
|
+
/* LIGHT MODE (Default) - Smoother gradient */
|
|
1156
|
+
/* Changed: Softer, right-focused radial highlight to avoid a heavy white bottom */
|
|
1157
|
+
--foisit-bg: radial-gradient(ellipse at 75% 30%, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.03));
|
|
1158
|
+
--foisit-border: 1px solid rgba(255, 255, 255, 0.25);
|
|
1159
|
+
--foisit-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
|
|
1160
|
+
--foisit-text: #333;
|
|
1161
|
+
--foisit-backdrop: blur(20px);
|
|
983
1162
|
|
|
984
1163
|
/* Input */
|
|
985
|
-
--foisit-input-color:
|
|
986
|
-
--foisit-input-placeholder: rgba(
|
|
1164
|
+
--foisit-input-color: #333;
|
|
1165
|
+
--foisit-input-placeholder: rgba(60, 60, 67, 0.6);
|
|
987
1166
|
|
|
988
1167
|
/* Bubbles */
|
|
989
|
-
--foisit-bubble-user-bg: rgba(
|
|
990
|
-
--foisit-bubble-user-text:
|
|
1168
|
+
--foisit-bubble-user-bg: rgba(0, 0, 0, 0.04);
|
|
1169
|
+
--foisit-bubble-user-text: #333;
|
|
991
1170
|
|
|
992
|
-
--foisit-bubble-sys-bg: rgba(255, 255, 255, 0.
|
|
993
|
-
--foisit-bubble-sys-text:
|
|
1171
|
+
--foisit-bubble-sys-bg: rgba(255, 255, 255, 0.45);
|
|
1172
|
+
--foisit-bubble-sys-text: #333;
|
|
994
1173
|
|
|
995
1174
|
/* Form Colors */
|
|
996
|
-
--foisit-req-star: #
|
|
997
|
-
--foisit-error-text: #
|
|
998
|
-
--foisit-error-border: #
|
|
1175
|
+
--foisit-req-star: #ef4444; /* Red asterisk */
|
|
1176
|
+
--foisit-error-text: #dc2626;
|
|
1177
|
+
--foisit-error-border: #fca5a5;
|
|
999
1178
|
}
|
|
1000
|
-
|
|
1179
|
+
|
|
1180
|
+
@media (prefers-color-scheme: dark) {
|
|
1181
|
+
:root {
|
|
1182
|
+
/* DARK MODE */
|
|
1183
|
+
--foisit-bg: linear-gradient(135deg, rgba(40, 40, 40, 0.65), rgba(40, 40, 40, 0.25));
|
|
1184
|
+
--foisit-border: 1px solid rgba(255, 255, 255, 0.1);
|
|
1185
|
+
--foisit-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
|
|
1186
|
+
--foisit-text: #fff;
|
|
1187
|
+
--foisit-backdrop: blur(20px);
|
|
1188
|
+
|
|
1189
|
+
/* Input */
|
|
1190
|
+
--foisit-input-color: white;
|
|
1191
|
+
--foisit-input-placeholder: rgba(235, 235, 245, 0.5);
|
|
1192
|
+
|
|
1193
|
+
/* Bubbles */
|
|
1194
|
+
--foisit-bubble-user-bg: rgba(255, 255, 255, 0.1);
|
|
1195
|
+
--foisit-bubble-user-text: white;
|
|
1196
|
+
|
|
1197
|
+
--foisit-bubble-sys-bg: rgba(255, 255, 255, 0.05);
|
|
1198
|
+
--foisit-bubble-sys-text: rgba(255, 255, 255, 0.9);
|
|
1199
|
+
|
|
1200
|
+
/* Form Colors */
|
|
1201
|
+
--foisit-req-star: #f87171;
|
|
1202
|
+
--foisit-error-text: #fca5a5;
|
|
1203
|
+
--foisit-error-border: #f87171;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
`;
|
|
1207
|
+
t.textContent += `
|
|
1001
1208
|
|
|
1002
1209
|
@keyframes foisitPulse {
|
|
1003
1210
|
0%, 100% { transform: scale(0.8); opacity: 0.5; }
|
|
@@ -1045,8 +1252,8 @@ class Y {
|
|
|
1045
1252
|
border: var(--foisit-border);
|
|
1046
1253
|
box-shadow: var(--foisit-shadow);
|
|
1047
1254
|
|
|
1048
|
-
backdrop-filter:
|
|
1049
|
-
-webkit-backdrop-filter:
|
|
1255
|
+
backdrop-filter: var(--foisit-backdrop);
|
|
1256
|
+
-webkit-backdrop-filter: var(--foisit-backdrop);
|
|
1050
1257
|
|
|
1051
1258
|
border-radius: 18px;
|
|
1052
1259
|
display: none;
|
|
@@ -1255,8 +1462,8 @@ class Y {
|
|
|
1255
1462
|
border: 1px solid rgba(255,255,255,0.2);
|
|
1256
1463
|
background: var(--foisit-bg);
|
|
1257
1464
|
color: var(--foisit-text);
|
|
1258
|
-
backdrop-filter:
|
|
1259
|
-
-webkit-backdrop-filter:
|
|
1465
|
+
backdrop-filter: var(--foisit-backdrop);
|
|
1466
|
+
-webkit-backdrop-filter: var(--foisit-backdrop);
|
|
1260
1467
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
1261
1468
|
cursor: pointer;
|
|
1262
1469
|
pointer-events: auto;
|
|
@@ -1268,18 +1475,108 @@ class Y {
|
|
|
1268
1475
|
transition: transform 0.2s;
|
|
1269
1476
|
}
|
|
1270
1477
|
.foisit-floating-btn:hover { transform: scale(1.05); }
|
|
1478
|
+
|
|
1479
|
+
/* Markdown Styles */
|
|
1480
|
+
.foisit-bubble.system .foisit-md-p { margin: 0 0 0.5em 0; }
|
|
1481
|
+
.foisit-bubble.system .foisit-md-p:last-child { margin-bottom: 0; }
|
|
1482
|
+
|
|
1483
|
+
.foisit-bubble.system .foisit-md-h1,
|
|
1484
|
+
.foisit-bubble.system .foisit-md-h2,
|
|
1485
|
+
.foisit-bubble.system .foisit-md-h3,
|
|
1486
|
+
.foisit-bubble.system .foisit-md-h4,
|
|
1487
|
+
.foisit-bubble.system .foisit-md-h5,
|
|
1488
|
+
.foisit-bubble.system .foisit-md-h6 {
|
|
1489
|
+
margin: 0.8em 0 0.4em 0;
|
|
1490
|
+
font-weight: 600;
|
|
1491
|
+
line-height: 1.3;
|
|
1492
|
+
}
|
|
1493
|
+
.foisit-bubble.system .foisit-md-h1:first-child,
|
|
1494
|
+
.foisit-bubble.system .foisit-md-h2:first-child,
|
|
1495
|
+
.foisit-bubble.system .foisit-md-h3:first-child { margin-top: 0; }
|
|
1496
|
+
|
|
1497
|
+
.foisit-bubble.system .foisit-md-h1 { font-size: 1.4em; }
|
|
1498
|
+
.foisit-bubble.system .foisit-md-h2 { font-size: 1.25em; }
|
|
1499
|
+
.foisit-bubble.system .foisit-md-h3 { font-size: 1.1em; }
|
|
1500
|
+
.foisit-bubble.system .foisit-md-h4 { font-size: 1em; }
|
|
1501
|
+
.foisit-bubble.system .foisit-md-h5 { font-size: 0.95em; }
|
|
1502
|
+
.foisit-bubble.system .foisit-md-h6 { font-size: 0.9em; opacity: 0.85; }
|
|
1503
|
+
|
|
1504
|
+
.foisit-bubble.system .foisit-md-ul,
|
|
1505
|
+
.foisit-bubble.system .foisit-md-ol {
|
|
1506
|
+
margin: 0.5em 0;
|
|
1507
|
+
padding-left: 1.5em;
|
|
1508
|
+
}
|
|
1509
|
+
.foisit-bubble.system .foisit-md-li { margin: 0.25em 0; }
|
|
1510
|
+
|
|
1511
|
+
.foisit-bubble.system .foisit-code-block {
|
|
1512
|
+
background: rgba(0,0,0,0.15);
|
|
1513
|
+
border-radius: 6px;
|
|
1514
|
+
padding: 10px 12px;
|
|
1515
|
+
margin: 0.5em 0;
|
|
1516
|
+
overflow-x: auto;
|
|
1517
|
+
font-family: 'SF Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
1518
|
+
font-size: 0.85em;
|
|
1519
|
+
line-height: 1.4;
|
|
1520
|
+
}
|
|
1521
|
+
.foisit-bubble.system .foisit-code-block code {
|
|
1522
|
+
background: transparent;
|
|
1523
|
+
padding: 0;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
.foisit-bubble.system .foisit-inline-code {
|
|
1527
|
+
background: rgba(0,0,0,0.1);
|
|
1528
|
+
padding: 2px 6px;
|
|
1529
|
+
border-radius: 4px;
|
|
1530
|
+
font-family: 'SF Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
1531
|
+
font-size: 0.9em;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
.foisit-bubble.system .foisit-md-blockquote {
|
|
1535
|
+
border-left: 3px solid rgba(127,127,127,0.4);
|
|
1536
|
+
margin: 0.5em 0;
|
|
1537
|
+
padding-left: 12px;
|
|
1538
|
+
opacity: 0.9;
|
|
1539
|
+
font-style: italic;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
.foisit-bubble.system .foisit-md-link {
|
|
1543
|
+
color: inherit;
|
|
1544
|
+
text-decoration: underline;
|
|
1545
|
+
opacity: 0.9;
|
|
1546
|
+
}
|
|
1547
|
+
.foisit-bubble.system .foisit-md-link:hover { opacity: 1; }
|
|
1548
|
+
|
|
1549
|
+
.foisit-bubble.system .foisit-md-hr {
|
|
1550
|
+
border: none;
|
|
1551
|
+
border-top: 1px solid rgba(127,127,127,0.3);
|
|
1552
|
+
margin: 0.8em 0;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
.foisit-bubble.system strong { font-weight: 600; }
|
|
1556
|
+
.foisit-bubble.system em { font-style: italic; }
|
|
1557
|
+
.foisit-bubble.system del { text-decoration: line-through; opacity: 0.7; }
|
|
1558
|
+
|
|
1559
|
+
@media (prefers-color-scheme: dark) {
|
|
1560
|
+
.foisit-bubble.system .foisit-code-block { background: rgba(255,255,255,0.08); }
|
|
1561
|
+
.foisit-bubble.system .foisit-inline-code { background: rgba(255,255,255,0.1); }
|
|
1562
|
+
}
|
|
1271
1563
|
`, document.head.appendChild(t);
|
|
1272
1564
|
}
|
|
1273
1565
|
}
|
|
1274
|
-
class
|
|
1566
|
+
class Y {
|
|
1275
1567
|
constructor(t) {
|
|
1276
|
-
this.config = t, this.isActivated = !1, this.lastProcessedInput = "", this.processingLock = !1, this.defaultIntroMessage = "How can I help you?", this.commandHandler = new
|
|
1568
|
+
this.config = t, this.isActivated = !1, this.lastProcessedInput = "", this.processingLock = !1, this.defaultIntroMessage = "How can I help you?", this.commandHandler = new N({
|
|
1277
1569
|
enableSmartIntent: this.config.enableSmartIntent !== !1,
|
|
1278
1570
|
intentEndpoint: this.config.intentEndpoint
|
|
1279
|
-
}), this.fallbackHandler = new z(), typeof window < "u" && typeof document < "u" ? (this.voiceProcessor = new
|
|
1571
|
+
}), this.fallbackHandler = new z(), typeof window < "u" && typeof document < "u" ? (this.voiceProcessor = new W(), this.textToSpeech = new P(), this.stateManager = new _(), this.gestureHandler = new R(), this.overlayManager = new G({
|
|
1280
1572
|
floatingButton: this.config.floatingButton,
|
|
1281
|
-
inputPlaceholder: this.config.inputPlaceholder
|
|
1282
|
-
|
|
1573
|
+
inputPlaceholder: this.config.inputPlaceholder,
|
|
1574
|
+
enableGestureActivation: this.config.enableGestureActivation,
|
|
1575
|
+
theme: this.config.theme,
|
|
1576
|
+
themeColors: this.config.themeColors
|
|
1577
|
+
}), this.overlayManager.setExternalCommandExecutor(async (e) => this.commandHandler.executeCommand(e)), this.config.commands.forEach(
|
|
1578
|
+
(e) => this.commandHandler.addCommand(e)
|
|
1579
|
+
), this.config.fallbackResponse && this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse), this.overlayManager.registerCallbacks(
|
|
1283
1580
|
async (e) => {
|
|
1284
1581
|
if (typeof e == "string") {
|
|
1285
1582
|
this.overlayManager.addMessage(e, "user"), await this.handleCommand(e);
|
|
@@ -1288,24 +1585,32 @@ class K {
|
|
|
1288
1585
|
if (e && typeof e == "object") {
|
|
1289
1586
|
const i = e, s = i.label ?? i.commandId ?? "Selection";
|
|
1290
1587
|
this.overlayManager.addMessage(String(s), "user"), this.overlayManager.showLoading();
|
|
1291
|
-
const n = await this.commandHandler.executeCommand(
|
|
1588
|
+
const n = await this.commandHandler.executeCommand(
|
|
1589
|
+
i
|
|
1590
|
+
);
|
|
1292
1591
|
this.overlayManager.hideLoading(), this.processResponse(n);
|
|
1293
1592
|
}
|
|
1294
1593
|
},
|
|
1295
1594
|
() => console.log("AssistantService: Overlay closed.")
|
|
1296
|
-
)) : (this.voiceProcessor = void 0, this.textToSpeech = void 0, this.stateManager = void 0, this.gestureHandler = void 0, this.overlayManager = void 0, this.config.commands.forEach(
|
|
1595
|
+
)) : (this.voiceProcessor = void 0, this.textToSpeech = void 0, this.stateManager = void 0, this.gestureHandler = void 0, this.overlayManager = void 0, this.config.commands.forEach(
|
|
1596
|
+
(e) => this.commandHandler.addCommand(e)
|
|
1597
|
+
), this.config.fallbackResponse && this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse));
|
|
1297
1598
|
}
|
|
1298
1599
|
/** Start listening for activation and commands */
|
|
1299
1600
|
startListening() {
|
|
1300
1601
|
if (typeof window > "u" || !this.voiceProcessor) {
|
|
1301
|
-
console.log(
|
|
1602
|
+
console.log(
|
|
1603
|
+
"AssistantService: Voice is disabled or unavailable; startListening() is a no-op."
|
|
1604
|
+
);
|
|
1302
1605
|
return;
|
|
1303
1606
|
}
|
|
1304
1607
|
}
|
|
1305
1608
|
/** Stop listening */
|
|
1306
1609
|
stopListening() {
|
|
1307
1610
|
if (typeof window > "u" || !this.voiceProcessor) {
|
|
1308
|
-
console.log(
|
|
1611
|
+
console.log(
|
|
1612
|
+
"AssistantService: Voice unavailable; stopListening() is a no-op."
|
|
1613
|
+
), this.isActivated = !1;
|
|
1309
1614
|
return;
|
|
1310
1615
|
}
|
|
1311
1616
|
this.voiceProcessor.stopListening(), this.isActivated = !1;
|
|
@@ -1356,7 +1661,10 @@ class K {
|
|
|
1356
1661
|
return;
|
|
1357
1662
|
}
|
|
1358
1663
|
if (e.type === "error") {
|
|
1359
|
-
this.fallbackHandler.handleFallback(t), this.overlayManager.addMessage(
|
|
1664
|
+
this.fallbackHandler.handleFallback(t), this.overlayManager.addMessage(
|
|
1665
|
+
this.fallbackHandler.getFallbackMessage(),
|
|
1666
|
+
"system"
|
|
1667
|
+
);
|
|
1360
1668
|
return;
|
|
1361
1669
|
}
|
|
1362
1670
|
if ((e.type === "ambiguous" || e.type === "confirm") && e.options) {
|
|
@@ -1382,7 +1690,9 @@ class K {
|
|
|
1382
1690
|
this.overlayManager.showLoading();
|
|
1383
1691
|
let i;
|
|
1384
1692
|
try {
|
|
1385
|
-
i = await this.commandHandler.executeCommand(
|
|
1693
|
+
i = await this.commandHandler.executeCommand(
|
|
1694
|
+
e
|
|
1695
|
+
);
|
|
1386
1696
|
} finally {
|
|
1387
1697
|
this.overlayManager.hideLoading();
|
|
1388
1698
|
}
|
|
@@ -1406,6 +1716,19 @@ class K {
|
|
|
1406
1716
|
removeCommand(t) {
|
|
1407
1717
|
console.log(`AssistantService: Removing command "${t}".`), this.commandHandler.removeCommand(t);
|
|
1408
1718
|
}
|
|
1719
|
+
/** Expose programmatic command handler registration to host apps */
|
|
1720
|
+
registerCommandHandler(t, e) {
|
|
1721
|
+
this.overlayManager && this.overlayManager.registerCommandHandler(t, e);
|
|
1722
|
+
}
|
|
1723
|
+
unregisterCommandHandler(t) {
|
|
1724
|
+
this.overlayManager && this.overlayManager.unregisterCommandHandler(t);
|
|
1725
|
+
}
|
|
1726
|
+
/** Programmatically run a registered command (proxies to OverlayManager) */
|
|
1727
|
+
async runCommand(t) {
|
|
1728
|
+
if (!this.overlayManager) throw new Error("Overlay manager not available.");
|
|
1729
|
+
const e = await this.overlayManager.runCommand(t);
|
|
1730
|
+
return e && typeof e == "object" && "type" in e && this.processResponse(e), e;
|
|
1731
|
+
}
|
|
1409
1732
|
/** Get all registered commands */
|
|
1410
1733
|
getCommands() {
|
|
1411
1734
|
return this.commandHandler.getCommands();
|
|
@@ -1421,13 +1744,15 @@ class K {
|
|
|
1421
1744
|
if (i && typeof i == "object") {
|
|
1422
1745
|
const s = i, n = s.label ?? s.commandId ?? "Selection";
|
|
1423
1746
|
this.overlayManager.addMessage(String(n), "user"), this.overlayManager.showLoading();
|
|
1424
|
-
let
|
|
1747
|
+
let a;
|
|
1425
1748
|
try {
|
|
1426
|
-
|
|
1749
|
+
a = await this.commandHandler.executeCommand(
|
|
1750
|
+
s
|
|
1751
|
+
);
|
|
1427
1752
|
} finally {
|
|
1428
1753
|
this.overlayManager.hideLoading();
|
|
1429
1754
|
}
|
|
1430
|
-
this.processResponse(
|
|
1755
|
+
this.processResponse(a);
|
|
1431
1756
|
}
|
|
1432
1757
|
},
|
|
1433
1758
|
() => {
|
|
@@ -1437,21 +1762,21 @@ class K {
|
|
|
1437
1762
|
}
|
|
1438
1763
|
}
|
|
1439
1764
|
const q = F(null);
|
|
1440
|
-
let
|
|
1765
|
+
let M = null;
|
|
1441
1766
|
const Z = ({ config: d, children: t }) => {
|
|
1442
|
-
const [e, i] =
|
|
1443
|
-
return
|
|
1444
|
-
|
|
1767
|
+
const [e, i] = I(null), [s, n] = I(!1);
|
|
1768
|
+
return H(() => {
|
|
1769
|
+
M ? console.warn(
|
|
1445
1770
|
"Multiple AssistantProvider instances detected. Reusing global AssistantService."
|
|
1446
|
-
) : (console.log("Initializing global AssistantService..."),
|
|
1447
|
-
const
|
|
1448
|
-
return i(
|
|
1449
|
-
var
|
|
1450
|
-
console.log("Cleaning up AssistantService..."), (
|
|
1771
|
+
) : (console.log("Initializing global AssistantService..."), M = new Y(d));
|
|
1772
|
+
const a = M;
|
|
1773
|
+
return i(a), n(!0), () => {
|
|
1774
|
+
var o;
|
|
1775
|
+
console.log("Cleaning up AssistantService..."), (o = a.destroy) == null || o.call(a), M = null;
|
|
1451
1776
|
};
|
|
1452
1777
|
}, [d]), !s || !e ? /* @__PURE__ */ k("div", { children: "Loading Assistant..." }) : /* @__PURE__ */ k(q.Provider, { value: e, children: t });
|
|
1453
|
-
},
|
|
1454
|
-
const d =
|
|
1778
|
+
}, K = () => {
|
|
1779
|
+
const d = B(q);
|
|
1455
1780
|
if (console.log("assistant", d), !d)
|
|
1456
1781
|
throw new Error("useAssistant must be used within an AssistantProvider");
|
|
1457
1782
|
return d;
|
|
@@ -1459,13 +1784,13 @@ const Z = ({ config: d, children: t }) => {
|
|
|
1459
1784
|
label: d = "Activate Assistant",
|
|
1460
1785
|
onActivate: t
|
|
1461
1786
|
}) => {
|
|
1462
|
-
const e =
|
|
1787
|
+
const e = K();
|
|
1463
1788
|
return /* @__PURE__ */ k("button", { onClick: () => {
|
|
1464
1789
|
t && t(), e.reactivate();
|
|
1465
1790
|
}, className: "assistant-activator", children: d });
|
|
1466
1791
|
}, et = (d) => {
|
|
1467
|
-
const [t, e] =
|
|
1468
|
-
return
|
|
1792
|
+
const [t, e] = I(d.getState());
|
|
1793
|
+
return H(() => {
|
|
1469
1794
|
const i = (s) => {
|
|
1470
1795
|
e(s);
|
|
1471
1796
|
};
|
|
@@ -1479,8 +1804,8 @@ export {
|
|
|
1479
1804
|
tt as AssistantActivator,
|
|
1480
1805
|
q as AssistantContext,
|
|
1481
1806
|
Z as AssistantProvider,
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1807
|
+
Y as AssistantService,
|
|
1808
|
+
Q as ReactWrapper,
|
|
1809
|
+
K as useAssistant,
|
|
1485
1810
|
et as useAssistantState
|
|
1486
1811
|
};
|