@foisit/react-wrapper 2.1.1 → 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/README.md +96 -44
- package/index.d.ts +6 -0
- package/index.js +355 -0
- package/index.mjs +1421 -0
- package/lib/components/AssistantActivator.d.ts +8 -0
- package/lib/components/AssistantProvider.d.ts +9 -0
- package/lib/hooks/useAssistant.d.ts +3 -0
- package/lib/hooks/useAssistantState.d.ts +3 -0
- package/lib/react-wrapper.d.ts +2 -0
- package/lib/services/AssistantService.d.ts +44 -0
- package/lib/types/index.d.ts +0 -0
- package/lib/utils/index.d.ts +0 -0
- package/package.json +6 -2
- package/style.css +0 -0
package/index.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),S=require("react"),W={};function N(){return A.jsx("div",{className:W.container,children:A.jsx("h1",{children:"Welcome to ReactWrapper!"})})}class T{constructor(t){this.endpoint=t||"https://foisit-ninja.netlify.app/.netlify/functions/intent"}async determineIntent(t,e,i){try{const s={userInput:t,commands:e.map(r=>({id:r.id,command:r.command,description:r.description,parameters:r.parameters})),context:i},n=await fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!n.ok)throw new Error(`Proxy API Error: ${n.statusText}`);return await n.json()}catch(s){return console.error("OpenAIService Error:",s),{type:"unknown"}}}}class B{constructor(t=!0){if(this.commands=new Map,this.openAIService=null,this.context=null,this.pendingConfirmation=null,this.enableSmartIntent=!0,this.selectOptionsCache=new Map,typeof t=="boolean"){this.enableSmartIntent=t,this.enableSmartIntent&&(this.openAIService=new T);return}this.enableSmartIntent=t.enableSmartIntent??!0,this.enableSmartIntent&&(this.openAIService=new T(t.intentEndpoint))}addCommand(t,e){let i;if(typeof t=="string"){if(!e)throw new Error("Action required when adding command by string.");i={id:t.toLowerCase().replace(/\s+/g,"_"),command:t.toLowerCase(),action:e}}else i={...t},i.id||(i.id=i.command.toLowerCase().replace(/\s+/g,"_"));this.commands.set(i.command.toLowerCase(),i),i.id&&(i.id,i.command)}removeCommand(t){this.commands.delete(t.toLowerCase())}async executeCommand(t){if(typeof t=="object"&&t!==null){if(this.isStructured(t)){const c=String(t.commandId),f=t.params??{},o=this.getCommandById(c);if(!o)return{message:"That command is not available.",type:"error"};const p=this.sanitizeParamsForCommand(o,f),h=(o.parameters??[]).filter(C=>C.required).filter(C=>p[C.name]==null||p[C.name]==="");return h.length>0?(this.context={commandId:this.getCommandIdentifier(o),params:p},{message:`Please provide the required details for "${o.command}".`,type:"form",fields:h}):o.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(o),params:p},this.buildConfirmResponse(o)):this.safeRunAction(o,p)}if(!this.context)return{message:"Session expired or invalid context.",type:"error"};const n=this.getCommandById(this.context.commandId);if(!n)return this.context=null,{message:"Session expired or invalid context.",type:"error"};if(Array.isArray(t))return{message:"Invalid form payload.",type:"error"};const a={...this.context.params,...t};if(n.critical)return this.context=null,this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:a},this.buildConfirmResponse(n);const r=await this.safeRunAction(n,a);return this.context=null,this.normalizeResponse(r)}const e=t.trim().toLowerCase();if(this.pendingConfirmation){const n=e;if(["yes","y","confirm","ok","okay"].includes(n)){const{commandId:a,params:r}=this.pendingConfirmation;this.pendingConfirmation=null;const c=this.getCommandById(a);return c?this.safeRunAction(c,r):{message:"That action is no longer available.",type:"error"}}return["no","n","cancel","stop"].includes(n)?(this.pendingConfirmation=null,{message:"✅ Cancelled.",type:"success"}):{message:"Please confirm: Yes or No.",type:"confirm",options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}}const i=this.commands.get(e);if(i){const n=i,a=(n.parameters??[]).filter(r=>r.required);return a.length>0?(this.context={commandId:this.getCommandIdentifier(n),params:{}},{message:`Please provide the required details for "${n.command}".`,type:"form",fields:a}):n.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:{}},this.buildConfirmResponse(n)):this.safeRunAction(n,{})}const s=await this.tryDeterministicMatch(e);if(s)return s;if(this.enableSmartIntent&&this.openAIService){const n=await this.getCommandsForAI(),a=await this.openAIService.determineIntent(e,n,this.context);return this.handleAIResult(a)}return this.enableSmartIntent?this.listAllCommands():{message:"I'm not sure what you mean.",type:"error"}}async handleAIResult(t){if(t.type==="match"&&t.match){const e=this.getCommandById(t.match);if(!e)return{message:"I'm not sure what you mean.",type:"error"};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]==="");if(t.incomplete||a.length>0){this.context={commandId:this.getCommandIdentifier(e),params:s};const c=a.some(f=>f.type==="select");if(a.length<=2&&!c){const f=a.map(o=>o.name).join(" and ");return{message:t.message||`Please provide ${f}.`,type:"question"}}return{message:t.message||`Please fill in the missing details for "${e.command}".`,type:"form",fields:a}}if(e.critical)return this.pendingConfirmation={commandId:this.getCommandIdentifier(e),params:s},this.buildConfirmResponse(e);const r=await e.action(s);return this.normalizeResponse(r)}return t.type==="ambiguous"&&t.options&&t.options.length?{message:t.message||"Did you mean one of these?",type:"ambiguous",options:t.options.map(e=>({label:e.label,value:e.commandId??e.label,commandId:e.commandId}))}:this.listAllCommands()}sanitizeParamsForCommand(t,e){const i={...e??{}};for(const s of t.parameters??[])if(s.type==="date"){const n=i[s.name];if(typeof n=="string"){const a=n.trim();this.isIsoDateString(a)||delete i[s.name]}}return i}isIsoDateString(t){if(!/^\d{4}-\d{2}-\d{2}$/.test(t))return!1;const e=new Date(`${t}T00:00:00Z`);return!Number.isNaN(e.getTime())}buildConfirmResponse(t){return{message:`⚠️ Are you sure you want to run "${t.command}"?`,type:"confirm",options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}}async tryDeterministicMatch(t){const e=[];for(const r of this.commands.values()){let c=0;const f=r.command.toLowerCase();t.includes(f)&&(c+=5);const o=r.keywords??[];for(const p of o){const b=p.toLowerCase().trim();b&&(t===b?c+=4:t.includes(b)&&(c+=3))}c>0&&e.push({cmd:r,score:c})}if(e.length===0)return null;e.sort((r,c)=>c.score-r.score);const i=e[0].score,s=e.filter(r=>r.score===i).slice(0,3);if(s.length>1)return{message:"I think you mean one of these. Which one should I run?",type:"ambiguous",options:s.map(r=>({label:r.cmd.command,value:r.cmd.command,commandId:r.cmd.id}))};const n=s[0].cmd,a=(n.parameters??[]).filter(r=>r.required);return a.length>0?(this.context={commandId:this.getCommandIdentifier(n),params:{}},{message:`Please provide the required details for "${n.command}".`,type:"form",fields:a}):n.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:{}},this.buildConfirmResponse(n)):this.safeRunAction(n,{})}async safeRunAction(t,e){try{const i=await t.action(e??{});return this.normalizeResponse(i)}catch{return{message:"Something went wrong while running that command.",type:"error"}}}async getCommandsForAI(){const t=Array.from(this.commands.values()).map(e=>({...e,parameters:e.parameters?e.parameters.map(i=>({...i})):void 0}));return await Promise.all(t.map(async e=>{e.parameters&&await Promise.all(e.parameters.map(async i=>{if(i.type!=="select"||!i.getOptions||i.options&&i.options.length)return;const s=`${e.id??e.command}:${i.name}`,n=this.selectOptionsCache.get(s),a=Date.now();if(n&&a-n.ts<6e4){i.options=n.options;return}try{const r=await i.getOptions();this.selectOptionsCache.set(s,{options:r,ts:a}),i.options=r}catch{}}))})),t}getCommandById(t){for(const e of this.commands.values())if(e.id===t)return e}listAllCommands(){return{message:"Here are the available commands:",type:"ambiguous",options:Array.from(this.commands.values()).map(e=>({label:e.command,value:e.id??e.command,commandId:e.id??e.command}))}}normalizeResponse(t){return typeof t=="string"?{message:t,type:"success"}:t&&typeof t=="object"?t:{message:"Done",type:"success"}}isStructured(t){return typeof t.commandId=="string"}getCommandIdentifier(t){return t.id||(t.id=t.command.toLowerCase().replace(/\s+/g,"_")),t.id}getCommands(){return Array.from(this.commands.keys())}}class q{constructor(){this.synth=window.speechSynthesis}speak(t,e){if(!this.synth){console.error("SpeechSynthesis API is not supported in this browser.");return}const i=new SpeechSynthesisUtterance(t);e&&(i.pitch=e.pitch||1,i.rate=e.rate||1,i.volume=e.volume||1),i.onstart=()=>{window.dispatchEvent(new CustomEvent("foisit:tts-start"))},i.onend=()=>{console.log("Speech finished."),window.dispatchEvent(new CustomEvent("foisit:tts-end"))},i.onerror=s=>{console.error("Error during speech synthesis:",s.error)},this.synth.speak(i)}stopSpeaking(){this.synth&&this.synth.cancel()}}class O{constructor(){this.fallbackMessage="Sorry, I didn’t understand that."}setFallbackMessage(t){this.fallbackMessage=t}handleFallback(t){t&&console.log(`Fallback triggered for: "${t}"`),console.log(this.fallbackMessage),new q().speak(this.fallbackMessage)}getFallbackMessage(){return this.fallbackMessage}}const P=()=>{const d=window;return d.SpeechRecognition??d.webkitSpeechRecognition??null};class z{constructor(t="en-US",e={}){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=()=>{var s;this.ttsSpeaking=!0;try{(s=this.recognition)==null||s.stop()}catch{}this.isListening&&this.emitStatus("speaking")},this.onTTSEnd=()=>{this.ttsSpeaking=!1,this.isListening&&this.restartAllowed?this.safeRestart():this.emitStatus(this.isListening?"listening":"idle")};const i=P();if(i){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=()=>{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")};const s=this.recognition;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)}else this.recognition=null,this.emitStatus("unsupported");window.addEventListener("foisit:tts-start",this.onTTSStart),window.addEventListener("foisit:tts-end",this.onTTSEnd),this.visibilityHandler=()=>{var s;if(document.hidden){try{(s=this.recognition)==null||s.stop()}catch{}this.emitStatus(this.ttsSpeaking?"speaking":"idle")}else this.isListening&&!this.ttsSpeaking&&this.safeRestart()},document.addEventListener("visibilitychange",this.visibilityHandler)}log(t){this.debugEnabled&&t&&console.log("[VoiceProcessor]",t)}warn(t){this.debugEnabled&&t&&console.warn("[VoiceProcessor]",t)}error(t){this.debugEnabled&&t&&console.error("[VoiceProcessor]",t)}isSupported(){return P()!==null}onStatusChange(t){this.statusCallback=t}startListening(t){if(!this.isSupported()||!this.recognition){this.warn("VoiceProcessor: SpeechRecognition is not supported in this browser."),this.emitStatus("unsupported");return}if(this.isListening){this.warn("VoiceProcessor: Already listening."),this.resultCallback=t;return}this.resultCallback=t,this.intentionallyStopped=!1,this.restartAllowed=!0,this.isListening=!0,this.emitStatus("listening"),this.prewarmAudio().finally(()=>{this.safeRestart()})}stopListening(){var t;this.intentionallyStopped=!0,this.restartAllowed=!1,this.isListening=!1,this.emitStatus(this.ttsSpeaking?"speaking":"idle");try{(t=this.recognition)==null||t.stop()}catch{}}destroy(){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)}handleResult(t,e){var s,n;if(!this.resultCallback)return;const i=e.confidenceThreshold??.6;for(let a=t.resultIndex;a<t.results.length;a++){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;if(f&&!(!r.isFinal&&e.interimResults===!1)&&!(r.isFinal&&o<i))try{this.hadResultThisSession=!0,this.resultCallback(f,!!r.isFinal)}catch{this.error("VoiceProcessor: result callback error")}}}handleEnd(){if(this.log("recognition onend"),this.engineActive=!1,this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking){this.ttsSpeaking||(this.isListening=!1,this.emitStatus("idle"));return}this.isListening=!0,this.scheduleRestart()}handleError(t){const e=t==null?void 0:t.error;if(this.warn(`Error occurred: ${e??"unknown"}`),e&&["not-allowed","service-not-allowed","bad-grammar","language-not-supported"].includes(e)){this.intentionallyStopped=!0,this.restartAllowed=!1,this.isListening=!1,this.emitStatus("error",{error:e});return}this.scheduleRestart()}safeRestart(){if(!this.recognition)return;if(this.engineActive){this.log("safeRestart: engine already active, skipping start");return}const t=Date.now();if(t-this.lastStart<300){setTimeout(()=>this.safeRestart(),300);return}this.lastStart=t;try{this.log("calling recognition.start()"),this.recognition.start(),this.backoffMs=250,this.isListening&&!this.ttsSpeaking&&this.emitStatus("listening")}catch{this.error("recognition.start() threw; scheduling restart"),this.scheduleRestart()}}scheduleRestart(){if(this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking)return;if(this.engineActive){this.log("scheduleRestart: engine active, not scheduling");return}const t=Math.min(this.backoffMs,2e3);if(this.log(`scheduleRestart in ${t}ms`),this.restartTimer){this.log("scheduleRestart: restart already scheduled");return}this.restartTimer=setTimeout(()=>{this.restartTimer=null,!(this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking)&&this.safeRestart()},t),this.backoffMs=Math.min(this.backoffMs*2,2e3)}async prewarmAudio(){if(!this.prewarmed)try{if(typeof navigator>"u"||!("mediaDevices"in navigator))return;const t=navigator.mediaDevices;if(!(t!=null&&t.getUserMedia))return;this.log("prewarmAudio: requesting mic");const e=await t.getUserMedia({audio:!0});for(const i of e.getTracks())i.stop();this.prewarmed=!0,this.log("prewarmAudio: mic ready")}catch{this.warn("prewarmAudio: failed to get mic")}}emitStatus(t,e){if(this.statusCallback)try{this.statusCallback(t,e)}catch{this.error("VoiceProcessor: status callback error")}}}class j{constructor(){this.lastTap=0}setupDoubleTapListener(t){this.destroy(),this.dblClickListener=()=>{t()},document.addEventListener("dblclick",this.dblClickListener),this.touchEndListener=()=>{const e=new Date().getTime(),i=e-this.lastTap;i<300&&i>0&&t(),this.lastTap=e},document.addEventListener("touchend",this.touchEndListener)}destroy(){this.dblClickListener&&document.removeEventListener("dblclick",this.dblClickListener),this.touchEndListener&&document.removeEventListener("touchend",this.touchEndListener),this.dblClickListener=void 0,this.touchEndListener=void 0}}function $(){if(document.querySelector("#assistant-styles")){console.log("Styles already injected");return}const t=document.createElement("style");t.id="assistant-styles",t.innerHTML=`
|
|
2
|
+
/* Rounded shape with gradient animation */
|
|
3
|
+
.gradient-indicator {
|
|
4
|
+
position: fixed;
|
|
5
|
+
top: 20px;
|
|
6
|
+
right: 20px;
|
|
7
|
+
width: 60px;
|
|
8
|
+
height: 60px;
|
|
9
|
+
border-radius: 50%;
|
|
10
|
+
background: linear-gradient(135deg, #ff6ec4, #7873f5, #5e8cff, #6ed0f6);
|
|
11
|
+
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
|
|
12
|
+
animation: amoeba 5s infinite ease-in-out;
|
|
13
|
+
z-index: 9999; /* Ensure it's above all other elements */
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Amoeba effect for the borders */
|
|
17
|
+
@keyframes amoeba {
|
|
18
|
+
0% {
|
|
19
|
+
border-radius: 50%;
|
|
20
|
+
}
|
|
21
|
+
25% {
|
|
22
|
+
border-radius: 40% 60% 60% 40%;
|
|
23
|
+
}
|
|
24
|
+
50% {
|
|
25
|
+
border-radius: 60% 40% 40% 60%;
|
|
26
|
+
}
|
|
27
|
+
75% {
|
|
28
|
+
border-radius: 40% 60% 60% 40%;
|
|
29
|
+
}
|
|
30
|
+
100% {
|
|
31
|
+
border-radius: 50%;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`,document.head.appendChild(t),console.log("Gradient styles injected")}function D(){if(document.querySelector("#gradient-indicator"))return;const d=document.createElement("div");d.id="gradient-indicator",$(),d.classList.add("gradient-indicator"),document.body.appendChild(d),console.log("Gradient indicator added to the DOM")}function U(){const d=document.querySelector("#gradient-indicator");d&&(d.remove(),console.log("Gradient indicator removed from the DOM"))}class V{constructor(){this.state="idle",this.subscribers=[]}getState(){return this.state}setState(t){this.state=t,this.notifySubscribers(),console.log("State updated:",t),t==="listening"?D():U()}subscribe(t){this.subscribers.push(t)}notifySubscribers(){this.subscribers.forEach(t=>t(this.state))}}class G{constructor(t){this.container=null,this.chatWindow=null,this.messagesContainer=null,this.input=null,this.isOpen=!1,this.loadingEl=null,this.config=t,this.init()}init(){var e,i;if(this.container)return;this.injectOverlayStyles();const t=document.getElementById("foisit-overlay-container");if(t&&t instanceof HTMLElement){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();return}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()}renderFloatingButton(){var s,n,a,r,c,f;const t=document.createElement("button");t.innerHTML=((s=this.config.floatingButton)==null?void 0:s.customHtml)||"🎙️";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";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)}renderChatWindow(){var n;if(this.chatWindow)return;this.chatWindow=document.createElement("div"),this.chatWindow.className="foisit-chat";const t=document.createElement("div");t.className="foisit-header";const e=document.createElement("span");e.className="foisit-title",e.textContent="Foisit";const i=document.createElement("button");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";const s=document.createElement("div");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=>{var r;if(a.key==="Enter"&&((r=this.input)!=null&&r.value.trim())){const c=this.input.value.trim();this.input.value="",this.onSubmit&&this.onSubmit(c)}}),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)}registerCallbacks(t,e){this.onSubmit=t,this.onClose=e}toggle(t,e){t&&(this.onSubmit=t),e&&(this.onClose=e),this.isOpen=!this.isOpen,this.chatWindow&&(this.isOpen?(this.chatWindow.style.display="flex",requestAnimationFrame(()=>{this.chatWindow&&(this.chatWindow.style.opacity="1",this.chatWindow.style.transform="translateY(0) scale(1)")}),setTimeout(()=>{var i;return(i=this.input)==null?void 0:i.focus()},100)):(this.chatWindow.style.opacity="0",this.chatWindow.style.transform="translateY(20px) scale(0.95)",setTimeout(()=>{this.chatWindow&&!this.isOpen&&(this.chatWindow.style.display="none")},200),this.onClose&&this.onClose()))}addMessage(t,e){if(!this.messagesContainer)return;const i=document.createElement("div");i.textContent=t,i.className=e==="user"?"foisit-bubble user":"foisit-bubble system",this.messagesContainer.appendChild(i),this.scrollToBottom()}addOptions(t){if(!this.messagesContainer)return;const e=document.createElement("div");e.className="foisit-options-container",t.forEach(i=>{const s=document.createElement("button");s.textContent=i.label,s.className="foisit-option-chip",s.setAttribute("type","button"),s.setAttribute("aria-label",i.label);const n=()=>{if(i.commandId){this.onSubmit&&this.onSubmit({commandId:i.commandId});return}const a=i&&typeof i.value=="string"&&i.value.trim()?i.value:i.label;this.onSubmit&&this.onSubmit(a)};s.onclick=n,s.onkeydown=a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),n())},e.appendChild(s)}),this.messagesContainer.appendChild(e),this.scrollToBottom()}addForm(t,e,i){if(!this.messagesContainer)return;this.addMessage(t,"system");const s=document.createElement("form");s.className="foisit-form";const n=[],a=(o,p)=>{const b=document.createElement("div");return b.className="foisit-form-label",b.innerHTML=o+(p?' <span class="foisit-req-star">*</span>':""),b},r=()=>{const o=document.createElement("div");return o.className="foisit-form-error",o.style.display="none",o};(e??[]).forEach(o=>{const p=document.createElement("div");p.className="foisit-form-group";const b=o.description||o.name;p.appendChild(a(b,o.required));let h;if(o.type==="select"){const l=document.createElement("select");l.className="foisit-form-input";const y=document.createElement("option");y.value="",y.textContent="Select...",l.appendChild(y);const x=m=>{(m??[]).forEach(w=>{const g=document.createElement("option");g.value=String(w.value??w.label??""),g.textContent=String(w.label??w.value??""),l.appendChild(g)})};if(Array.isArray(o.options)&&o.options.length)x(o.options);else if(typeof o.getOptions=="function"){const m=o.getOptions,w=document.createElement("option");w.value="",w.textContent="Loading...",l.appendChild(w),Promise.resolve().then(()=>m()).then(g=>{for(;l.options.length>1;)l.remove(1);x(g)}).catch(()=>{for(;l.options.length>1;)l.remove(1);const g=document.createElement("option");g.value="",g.textContent="Error loading options",l.appendChild(g)})}o.defaultValue!=null&&(l.value=String(o.defaultValue)),h=l}else if(o.type==="file"){const l=o,y=document.createElement("input");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()=>{const x=Array.from(y.files||[]),m=C;if(m.style.display="none",m.textContent="",x.length===0)return;const w=l.maxFiles??(l.multiple?10:1);if(x.length>w){m.textContent=`Please select at most ${w} file(s).`,m.style.display="block";return}const g=l.maxSizeBytes??1/0,u=x.reduce((v,E)=>v+E.size,0);if(x.some(v=>v.size>g)){m.textContent=`One or more files exceed the maximum size of ${Math.round(g/1024)} KB.`,m.style.display="block";return}const k=l.maxTotalBytes??1/0;if(u>k){m.textContent=`Total selected files exceed the maximum of ${Math.round(k/1024)} KB.`,m.style.display="block";return}if(l.accept&&Array.isArray(l.accept)){const v=l.accept;if(!x.every(L=>L.type?v.some(I=>I.startsWith(".")?L.name.toLowerCase().endsWith(I.toLowerCase()):L.type===I||L.type.startsWith(I.split("/")[0]+"/")):!0)){m.textContent="One or more files have an unsupported type.",m.style.display="block";return}}}),h=y}else{const l=document.createElement("input");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}const C=r();p.appendChild(h),p.appendChild(C),n.push({name:o.name,type:o.type,el:h,required:o.required}),s.appendChild(p)});const c=document.createElement("div");c.className="foisit-form-actions";const f=document.createElement("button");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=>{o.preventDefault();const p={};let b=!1;s.querySelectorAll(".foisit-form-error").forEach(h=>{h.style.display="none",h.textContent=""}),s.querySelectorAll(".foisit-form-input").forEach(h=>{h.classList.remove("foisit-error-border")});for(const h of n){if(h.type==="file"){const x=h.el.parentElement,m=x==null?void 0:x.querySelector(".foisit-form-error"),w=h.el,g=Array.from(w.files||[]);if(h.required&&g.length===0){b=!0,w.classList.add("foisit-error-border"),m&&(m.textContent="This file is required",m.style.display="block");continue}if(g.length===0)continue;const u=(e??[]).find(v=>v.name===h.name),k=(u==null?void 0:u.delivery)??"file";if(u!=null&&u.maxWidth||u!=null&&u.maxHeight)try{const v=await this.getImageDimensions(g[0]);if(u.maxWidth&&v.width>u.maxWidth){b=!0,m&&(m.textContent=`Image width must be ≤ ${u.maxWidth}px`,m.style.display="block");continue}if(u.maxHeight&&v.height>u.maxHeight){b=!0,m&&(m.textContent=`Image height must be ≤ ${u.maxHeight}px`,m.style.display="block");continue}}catch{}if(u!=null&&u.maxDurationSec)try{const v=await this.getMediaDuration(g[0]);if(v&&v>u.maxDurationSec){b=!0,m&&(m.textContent=`Media duration must be ≤ ${u.maxDurationSec}s`,m.style.display="block");continue}}catch{}if(k==="file")p[h.name]=u!=null&&u.multiple?g:g[0];else if(k==="base64")try{const v=await Promise.all(g.map(E=>this.readFileAsDataURL(E)));p[h.name]=u!=null&&u.multiple?v:v[0]}catch{b=!0,m&&(m.textContent="Failed to encode file(s) to base64.",m.style.display="block");continue}continue}const C=(h.el.value??"").toString().trim(),l=h.el.parentElement,y=l==null?void 0:l.querySelector(".foisit-form-error");if(h.required&&(C==null||C==="")){b=!0,h.el.classList.add("foisit-error-border"),y&&(y.textContent="This field is required",y.style.display="block");continue}if(C!=="")if(h.type==="number"){const x=Number(C);Number.isNaN(x)||(p[h.name]=x)}else p[h.name]=C}if(b){s.classList.add("foisit-shake"),setTimeout(()=>s.classList.remove("foisit-shake"),400);return}f.disabled=!0,f.style.opacity="0.6",n.forEach(h=>{h.el.disabled=!0}),i(p)},this.messagesContainer.appendChild(s),this.scrollToBottom()}showLoading(){if(this.messagesContainer&&!this.loadingEl){this.loadingEl=document.createElement("div"),this.loadingEl.className="foisit-loading-dots foisit-bubble system";for(let t=0;t<3;t++){const e=document.createElement("div");e.className="foisit-dot",e.style.animation=`foisitPulse 1.4s infinite ease-in-out ${t*.2}s`,this.loadingEl.appendChild(e)}this.messagesContainer.appendChild(this.loadingEl),this.scrollToBottom()}}hideLoading(){var t;(t=this.loadingEl)==null||t.remove(),this.loadingEl=null}scrollToBottom(){this.messagesContainer&&(this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight)}destroy(){var t;(t=this.container)==null||t.remove(),this.container=null,this.chatWindow=null,this.messagesContainer=null,this.input=null,this.isOpen=!1}readFileAsDataURL(t){return new Promise((e,i)=>{const s=new FileReader;s.onerror=()=>i(new Error("Failed to read file")),s.onload=()=>e(String(s.result)),s.readAsDataURL(t)})}getImageDimensions(t){return new Promise(e=>{try{const i=URL.createObjectURL(t),s=new Image;s.onload=()=>{const n={width:s.naturalWidth||s.width,height:s.naturalHeight||s.height};URL.revokeObjectURL(i),e(n)},s.onerror=()=>{URL.revokeObjectURL(i),e({width:0,height:0})},s.src=i}catch{e({width:0,height:0})}})}getMediaDuration(t){return new Promise(e=>{try{const i=URL.createObjectURL(t),s=t.type.startsWith("audio")?document.createElement("audio"):document.createElement("video");let n=!1;const a=setTimeout(()=>{n||(n=!0,URL.revokeObjectURL(i),e(0))},5e3);s.preload="metadata",s.onloadedmetadata=()=>{if(n)return;n=!0,clearTimeout(a);const c=s.duration||0;URL.revokeObjectURL(i),e(c)},s.onerror=()=>{n||(n=!0,clearTimeout(a),URL.revokeObjectURL(i),e(0))},s.src=i}catch{e(0)}})}injectOverlayStyles(){if(document.getElementById("foisit-overlay-styles"))return;const t=document.createElement("style");t.id="foisit-overlay-styles",t.textContent=`
|
|
35
|
+
:root {
|
|
36
|
+
/* LIGHT MODE (Default) - Smoother gradient */
|
|
37
|
+
/* Changed: Softer, right-focused radial highlight to avoid a heavy white bottom */
|
|
38
|
+
--foisit-bg: radial-gradient(ellipse at 75% 30%, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.03));
|
|
39
|
+
--foisit-border: 1px solid rgba(255, 255, 255, 0.25);
|
|
40
|
+
--foisit-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
|
|
41
|
+
--foisit-text: #333;
|
|
42
|
+
|
|
43
|
+
/* Input */
|
|
44
|
+
--foisit-input-color: #333;
|
|
45
|
+
--foisit-input-placeholder: rgba(60, 60, 67, 0.6);
|
|
46
|
+
|
|
47
|
+
/* Bubbles */
|
|
48
|
+
--foisit-bubble-user-bg: rgba(0, 0, 0, 0.04);
|
|
49
|
+
--foisit-bubble-user-text: #333;
|
|
50
|
+
|
|
51
|
+
--foisit-bubble-sys-bg: rgba(255, 255, 255, 0.45);
|
|
52
|
+
--foisit-bubble-sys-text: #333;
|
|
53
|
+
|
|
54
|
+
/* Form Colors */
|
|
55
|
+
--foisit-req-star: #ef4444; /* Red asterisk */
|
|
56
|
+
--foisit-error-text: #dc2626;
|
|
57
|
+
--foisit-error-border: #fca5a5;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@media (prefers-color-scheme: dark) {
|
|
61
|
+
:root {
|
|
62
|
+
/* DARK MODE */
|
|
63
|
+
--foisit-bg: linear-gradient(135deg, rgba(40, 40, 40, 0.65), rgba(40, 40, 40, 0.25));
|
|
64
|
+
--foisit-border: 1px solid rgba(255, 255, 255, 0.1);
|
|
65
|
+
--foisit-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
|
|
66
|
+
--foisit-text: #fff;
|
|
67
|
+
|
|
68
|
+
/* Input */
|
|
69
|
+
--foisit-input-color: white;
|
|
70
|
+
--foisit-input-placeholder: rgba(235, 235, 245, 0.5);
|
|
71
|
+
|
|
72
|
+
/* Bubbles */
|
|
73
|
+
--foisit-bubble-user-bg: rgba(255, 255, 255, 0.1);
|
|
74
|
+
--foisit-bubble-user-text: white;
|
|
75
|
+
|
|
76
|
+
--foisit-bubble-sys-bg: rgba(255, 255, 255, 0.05);
|
|
77
|
+
--foisit-bubble-sys-text: rgba(255, 255, 255, 0.9);
|
|
78
|
+
|
|
79
|
+
/* Form Colors */
|
|
80
|
+
--foisit-req-star: #f87171;
|
|
81
|
+
--foisit-error-text: #fca5a5;
|
|
82
|
+
--foisit-error-border: #f87171;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@keyframes foisitPulse {
|
|
87
|
+
0%, 100% { transform: scale(0.8); opacity: 0.5; }
|
|
88
|
+
50% { transform: scale(1.2); opacity: 1; }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@keyframes foisitShake {
|
|
92
|
+
0%, 100% { transform: translateX(0); }
|
|
93
|
+
25% { transform: translateX(-4px); }
|
|
94
|
+
75% { transform: translateX(4px); }
|
|
95
|
+
}
|
|
96
|
+
.foisit-shake { animation: foisitShake 0.4s ease-in-out; }
|
|
97
|
+
|
|
98
|
+
/* Container */
|
|
99
|
+
.foisit-overlay-container {
|
|
100
|
+
position: fixed;
|
|
101
|
+
inset: 0;
|
|
102
|
+
z-index: 2147483647;
|
|
103
|
+
pointer-events: none;
|
|
104
|
+
display: flex;
|
|
105
|
+
flex-direction: column;
|
|
106
|
+
justify-content: flex-end;
|
|
107
|
+
align-items: flex-end;
|
|
108
|
+
padding: 20px;
|
|
109
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.foisit-overlay-container * {
|
|
113
|
+
box-sizing: border-box;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Chat Window - Dynamic Height */
|
|
117
|
+
.foisit-chat {
|
|
118
|
+
position: absolute;
|
|
119
|
+
top: 20px;
|
|
120
|
+
right: 20px;
|
|
121
|
+
width: min(420px, 92vw);
|
|
122
|
+
|
|
123
|
+
/* FIX: Auto height to prevent empty space */
|
|
124
|
+
height: auto;
|
|
125
|
+
min-height: 120px;
|
|
126
|
+
max-height: 80vh;
|
|
127
|
+
|
|
128
|
+
background: var(--foisit-bg);
|
|
129
|
+
border: var(--foisit-border);
|
|
130
|
+
box-shadow: var(--foisit-shadow);
|
|
131
|
+
|
|
132
|
+
backdrop-filter: blur(20px);
|
|
133
|
+
-webkit-backdrop-filter: blur(20px);
|
|
134
|
+
|
|
135
|
+
border-radius: 18px;
|
|
136
|
+
display: none;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
overflow: hidden;
|
|
139
|
+
pointer-events: auto;
|
|
140
|
+
transform-origin: top right;
|
|
141
|
+
transition: opacity 0.2s, transform 0.2s cubic-bezier(0.2, 0.9, 0.2, 1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.foisit-header {
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: space-between;
|
|
148
|
+
padding: 12px 16px;
|
|
149
|
+
font-weight: 600;
|
|
150
|
+
font-size: 14px;
|
|
151
|
+
color: var(--foisit-text);
|
|
152
|
+
border-bottom: 1px solid rgba(127,127,127,0.08); /* Subtle separator */
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.foisit-close {
|
|
156
|
+
background: transparent;
|
|
157
|
+
border: none;
|
|
158
|
+
color: var(--foisit-text);
|
|
159
|
+
opacity: 0.5;
|
|
160
|
+
font-size: 24px;
|
|
161
|
+
line-height: 1;
|
|
162
|
+
cursor: pointer;
|
|
163
|
+
padding: 0;
|
|
164
|
+
width: 28px;
|
|
165
|
+
height: 28px;
|
|
166
|
+
display: flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
justify-content: center;
|
|
169
|
+
transition: opacity 0.2s;
|
|
170
|
+
}
|
|
171
|
+
.foisit-close:hover { opacity: 1; }
|
|
172
|
+
|
|
173
|
+
/* Message Area */
|
|
174
|
+
.foisit-messages {
|
|
175
|
+
flex: 1;
|
|
176
|
+
overflow-y: auto;
|
|
177
|
+
padding: 16px;
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: 10px;
|
|
181
|
+
/* Ensure it doesn't get too tall initially */
|
|
182
|
+
min-height: 60px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Make sure empty state isn't huge */
|
|
186
|
+
.foisit-messages:empty {
|
|
187
|
+
display: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* Only show messages container if it has children */
|
|
191
|
+
.foisit-messages:not(:empty) {
|
|
192
|
+
display: flex;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* Bubbles */
|
|
196
|
+
.foisit-bubble {
|
|
197
|
+
max-width: 90%;
|
|
198
|
+
padding: 8px 14px;
|
|
199
|
+
border-radius: 14px;
|
|
200
|
+
font-size: 14px;
|
|
201
|
+
line-height: 1.4;
|
|
202
|
+
word-wrap: break-word;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.foisit-bubble.user {
|
|
206
|
+
align-self: flex-end;
|
|
207
|
+
background: var(--foisit-bubble-user-bg);
|
|
208
|
+
color: var(--foisit-bubble-user-text);
|
|
209
|
+
border-bottom-right-radius: 4px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.foisit-bubble.system {
|
|
213
|
+
align-self: flex-start;
|
|
214
|
+
background: var(--foisit-bubble-sys-bg);
|
|
215
|
+
color: var(--foisit-bubble-sys-text);
|
|
216
|
+
border-bottom-left-radius: 4px;
|
|
217
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Input Area */
|
|
221
|
+
.foisit-input-area {
|
|
222
|
+
padding: 0;
|
|
223
|
+
width: 100%;
|
|
224
|
+
border-top: 1px solid rgba(127,127,127,0.08);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.foisit-input {
|
|
228
|
+
width: 100%;
|
|
229
|
+
background: transparent;
|
|
230
|
+
border: none;
|
|
231
|
+
font-size: 16px;
|
|
232
|
+
color: var(--foisit-input-color);
|
|
233
|
+
padding: 16px 20px;
|
|
234
|
+
outline: none;
|
|
235
|
+
text-align: left;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.foisit-input::placeholder {
|
|
239
|
+
color: var(--foisit-input-placeholder);
|
|
240
|
+
font-weight: 400;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* Options & Buttons */
|
|
244
|
+
.foisit-options-container {
|
|
245
|
+
display: flex;
|
|
246
|
+
flex-wrap: wrap;
|
|
247
|
+
gap: 8px;
|
|
248
|
+
margin-left: 2px;
|
|
249
|
+
margin-top: 4px;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.foisit-option-chip {
|
|
253
|
+
padding: 6px 14px;
|
|
254
|
+
background: var(--foisit-bubble-sys-bg);
|
|
255
|
+
border: 1px solid rgba(127,127,127,0.1);
|
|
256
|
+
border-radius: 20px;
|
|
257
|
+
font-size: 13px;
|
|
258
|
+
color: var(--foisit-text);
|
|
259
|
+
cursor: pointer;
|
|
260
|
+
transition: all 0.2s;
|
|
261
|
+
font-weight: 500;
|
|
262
|
+
}
|
|
263
|
+
.foisit-option-chip:hover {
|
|
264
|
+
background: rgba(127,127,127,0.15);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* Form Styling */
|
|
268
|
+
.foisit-form {
|
|
269
|
+
background: var(--foisit-bubble-sys-bg);
|
|
270
|
+
padding: 16px;
|
|
271
|
+
border-radius: 14px;
|
|
272
|
+
display: flex;
|
|
273
|
+
flex-direction: column;
|
|
274
|
+
gap: 12px;
|
|
275
|
+
width: 100%;
|
|
276
|
+
border: 1px solid rgba(127,127,127,0.1);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.foisit-form-label {
|
|
280
|
+
font-size: 12px;
|
|
281
|
+
font-weight: 600;
|
|
282
|
+
color: var(--foisit-text);
|
|
283
|
+
opacity: 0.9;
|
|
284
|
+
margin-bottom: 2px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.foisit-req-star {
|
|
288
|
+
color: var(--foisit-req-star);
|
|
289
|
+
font-weight: bold;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.foisit-form-input {
|
|
293
|
+
width: 100%;
|
|
294
|
+
padding: 10px;
|
|
295
|
+
border-radius: 8px;
|
|
296
|
+
border: 1px solid rgba(127,127,127,0.2);
|
|
297
|
+
background: rgba(255,255,255,0.05); /* Very subtle fill */
|
|
298
|
+
color: var(--foisit-text);
|
|
299
|
+
font-size: 14px;
|
|
300
|
+
outline: none;
|
|
301
|
+
transition: border 0.2s;
|
|
302
|
+
}
|
|
303
|
+
.foisit-form-input:focus {
|
|
304
|
+
border-color: var(--foisit-text);
|
|
305
|
+
background: rgba(255,255,255,0.1);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.foisit-error-border {
|
|
309
|
+
border-color: var(--foisit-error-border) !important;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.foisit-form-error {
|
|
313
|
+
font-size: 11px;
|
|
314
|
+
color: var(--foisit-error-text);
|
|
315
|
+
margin-top: 4px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* Loading */
|
|
319
|
+
.foisit-loading-dots {
|
|
320
|
+
display: inline-flex;
|
|
321
|
+
gap: 4px;
|
|
322
|
+
padding: 10px 14px;
|
|
323
|
+
align-self: flex-start;
|
|
324
|
+
}
|
|
325
|
+
.foisit-dot {
|
|
326
|
+
width: 6px;
|
|
327
|
+
height: 6px;
|
|
328
|
+
border-radius: 50%;
|
|
329
|
+
background: var(--foisit-text);
|
|
330
|
+
opacity: 0.4;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* Floating Button */
|
|
334
|
+
.foisit-floating-btn {
|
|
335
|
+
position: absolute;
|
|
336
|
+
width: 56px;
|
|
337
|
+
height: 56px;
|
|
338
|
+
border-radius: 50%;
|
|
339
|
+
border: 1px solid rgba(255,255,255,0.2);
|
|
340
|
+
background: var(--foisit-bg);
|
|
341
|
+
color: var(--foisit-text);
|
|
342
|
+
backdrop-filter: blur(10px);
|
|
343
|
+
-webkit-backdrop-filter: blur(10px);
|
|
344
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
345
|
+
cursor: pointer;
|
|
346
|
+
pointer-events: auto;
|
|
347
|
+
display: flex;
|
|
348
|
+
align-items: center;
|
|
349
|
+
justify-content: center;
|
|
350
|
+
font-size: 24px;
|
|
351
|
+
z-index: 100000;
|
|
352
|
+
transition: transform 0.2s;
|
|
353
|
+
}
|
|
354
|
+
.foisit-floating-btn:hover { transform: scale(1.05); }
|
|
355
|
+
`,document.head.appendChild(t)}}class H{constructor(t){this.config=t,this.isActivated=!1,this.lastProcessedInput="",this.processingLock=!1,this.defaultIntroMessage="How can I help you?",this.commandHandler=new B({enableSmartIntent:this.config.enableSmartIntent!==!1,intentEndpoint:this.config.intentEndpoint}),this.fallbackHandler=new O,this.voiceProcessor=new z,this.textToSpeech=new q,this.stateManager=new V,this.gestureHandler=new j,this.overlayManager=new G({floatingButton:this.config.floatingButton,inputPlaceholder:this.config.inputPlaceholder}),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(async e=>{if(typeof e=="string"){this.overlayManager.addMessage(e,"user"),await this.handleCommand(e);return}if(e&&typeof e=="object"){const i=e,s=i.label??i.commandId??"Selection";this.overlayManager.addMessage(String(s),"user"),this.overlayManager.showLoading();const n=await this.commandHandler.executeCommand(i);this.overlayManager.hideLoading(),this.processResponse(n)}},()=>console.log("AssistantService: Overlay closed."))}startListening(){console.log("AssistantService: Voice is disabled; startListening() is a no-op.")}stopListening(){console.log("AssistantService: Voice is disabled; stopListening() is a no-op."),this.isActivated=!1}reactivate(){console.log("AssistantService: Reactivating assistant..."),this.isActivated=!1;try{this.startListening()}catch{}}async processActivation(t){var i;const e=(i=this.config.activationCommand)==null?void 0:i.toLowerCase();e&&(t===e?(console.log("AssistantService: Activation matched."),this.isActivated=!0,this.textToSpeech.speak(this.config.introMessage||this.defaultIntroMessage)):console.log("AssistantService: Activation command not recognized."))}async handleCommand(t){this.overlayManager.showLoading();let e;try{e=await this.commandHandler.executeCommand(t)}finally{this.overlayManager.hideLoading()}if(e.type==="form"&&e.fields){this.overlayManager.addForm(e.message,e.fields,async i=>{this.overlayManager.showLoading();let s;try{s=await this.commandHandler.executeCommand(i)}finally{this.overlayManager.hideLoading()}this.processResponse(s)});return}if(e.type==="error"){this.fallbackHandler.handleFallback(t),this.overlayManager.addMessage(this.fallbackHandler.getFallbackMessage(),"system");return}e.message?this.overlayManager.addMessage(e.message,"system"):(e.type==="ambiguous"||e.type==="confirm")&&e.options&&this.overlayManager.addOptions(e.options)}destroy(){this.voiceProcessor.stopListening(),this.gestureHandler.destroy(),this.overlayManager.destroy()}processResponse(t){if(t){if(t.type==="form"&&t.fields){this.overlayManager.addForm(t.message,t.fields,async e=>{this.overlayManager.showLoading();let i;try{i=await this.commandHandler.executeCommand(e)}finally{this.overlayManager.hideLoading()}this.processResponse(i)});return}if((t.type==="ambiguous"||t.type==="confirm")&&t.options){t.message&&this.overlayManager.addMessage(t.message,"system"),this.overlayManager.addOptions(t.options);return}t.message&&this.overlayManager.addMessage(t.message,"system")}}addCommand(t,e){console.log(typeof t=="string"?`AssistantService: Adding command "${t}".`:`AssistantService: Adding rich command "${t.command}".`),this.commandHandler.addCommand(t,e)}removeCommand(t){console.log(`AssistantService: Removing command "${t}".`),this.commandHandler.removeCommand(t)}getCommands(){return this.commandHandler.getCommands()}toggle(t,e){console.log("AssistantService: Toggling overlay..."),this.overlayManager.toggle(async i=>{if(typeof i=="string"){this.overlayManager.addMessage(i,"user"),t&&t(i),await this.handleCommand(i);return}if(i&&typeof i=="object"){const s=i,n=s.label??s.commandId??"Selection";this.overlayManager.addMessage(String(n),"user"),this.overlayManager.showLoading();let a;try{a=await this.commandHandler.executeCommand(s)}finally{this.overlayManager.hideLoading()}this.processResponse(a)}},()=>{console.log("AssistantService: Overlay closed."),e&&e()})}}const M=S.createContext(null);let R=null;const Y=({config:d,children:t})=>{const[e,i]=S.useState(null),[s,n]=S.useState(!1);return S.useEffect(()=>{R?console.warn("Multiple AssistantProvider instances detected. Reusing global AssistantService."):(console.log("Initializing global AssistantService..."),R=new H(d));const a=R;return i(a),n(!0),()=>{var r;console.log("Cleaning up AssistantService..."),(r=a.destroy)==null||r.call(a),R=null}},[d]),!s||!e?A.jsx("div",{children:"Loading Assistant..."}):A.jsx(M.Provider,{value:e,children:t})},F=()=>{const d=S.useContext(M);if(console.log("assistant",d),!d)throw new Error("useAssistant must be used within an AssistantProvider");return d},K=({label:d="Activate Assistant",onActivate:t})=>{const e=F(),i=()=>{t&&t(),e.reactivate()};return A.jsx("button",{onClick:i,className:"assistant-activator",children:d})},X=d=>{const[t,e]=S.useState(d.getState());return S.useEffect(()=>{const i=s=>{e(s)};return d.subscribe(i),()=>{d.subscribe(()=>{})}},[d]),t};exports.AssistantActivator=K;exports.AssistantContext=M;exports.AssistantProvider=Y;exports.AssistantService=H;exports.ReactWrapper=N;exports.useAssistant=F;exports.useAssistantState=X;
|