@foisit/react-wrapper 2.1.2 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("react/jsx-runtime"),u=require("react"),I={};function E(){return g.jsx("div",{className:I.container,children:g.jsx("h1",{children:"Welcome to ReactWrapper!"})})}class L{constructor(){this.endpoint="https://foisit-ninja.netlify.app/.netlify/functions/intent"}async determineIntent(e,t,s){try{const i=await fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userInput:e,context:s,commands:t.map(c=>({id:c.id,command:c.command,description:c.description,keywords:c.keywords,parameters:c.parameters}))})});if(!i.ok)throw new Error("Proxy API request failed");return await i.json()}catch(i){return console.error("Foisit AI Error:",i),{type:"unknown"}}}}class M{constructor(e=!0){this.commands=new Map,this.pendingConfirmation=null,this.conversationContext=null,this.enableSmartIntent=!0,this.enableSmartIntent=e,this.aiService=new L}addCommand(e,t){let s;if(typeof e=="string"){if(!t)throw new Error("Action is required when passing a command string.");s={command:e,action:t,id:`cmd_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}}else s=e,s.id||(s.id=`cmd_${Date.now()}_${Math.random().toString(36).substr(2,9)}`);const i=s.command.toLowerCase();this.commands.set(i,s)}removeCommand(e){const t=e.toLowerCase();this.commands.has(t)&&this.commands.delete(t)}async executeCommand(e){var c;if(typeof e=="object"&&this.conversationContext){const o=Array.from(this.commands.values()).find(a=>{var n;return a.id===((n=this.conversationContext)==null?void 0:n.commandId)});if(o){const a={...this.conversationContext.params,...e};return this.conversationContext=null,this.runAction(o,a)}}const t=(typeof e=="string"?e:"").toLowerCase().trim();if(this.pendingConfirmation)if(t==="yes"||t==="y"||t==="confirm"){const o=this.pendingConfirmation;return this.pendingConfirmation=null,this.runAction(o)}else return t==="no"||t==="n"||t==="cancel"?(this.pendingConfirmation=null,{type:"success",message:"Action cancelled."}):{type:"ambiguous",message:`Please confirm: Are you sure you want to ${this.pendingConfirmation.description||this.pendingConfirmation.command}?`,options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]};if(!this.conversationContext){const o=this.commands.get(t);if(o){if(!o.parameters||o.parameters.length===0)return o.critical?(this.pendingConfirmation=o,{type:"ambiguous",message:`Are you sure you want to ${o.description||o.command}?`,options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}):this.runAction(o);this.conversationContext={commandId:o.id||"",params:{}};const a=await Promise.all(o.parameters.map(async n=>{let h=n.options;if(n.getOptions)try{h=await n.getOptions()}catch(m){console.error(`Error fetching options for ${n.name}`,m)}return{name:n.name,label:n.name.charAt(0).toUpperCase()+n.name.slice(1),value:"",required:n.required,type:n.type||"string",options:h}}));return{type:"form",message:o.description||`Please fill in the details for ${o.command}:`,fields:a}}}const s=Array.from(this.commands.values());if(this.enableSmartIntent){const o=await this.aiService.determineIntent(t,s,this.conversationContext);if(o.type==="match"&&o.match){const a=s.find(n=>n.id===o.match);if(a){const n={...((c=this.conversationContext)==null?void 0:c.params)||{},...o.params||{}};if(o.incomplete){if(this.conversationContext={commandId:a.id,params:n},a.parameters&&a.parameters.length>0){const h=await Promise.all(a.parameters.map(async m=>{let d=m.options;if(m.getOptions)try{d=await m.getOptions()}catch(f){console.error(`Error fetching options for ${m.name}`,f)}return{name:m.name,label:m.name.charAt(0).toUpperCase()+m.name.slice(1),value:n[m.name]||"",required:m.required,type:m.type||"string",options:d}}));return{type:"form",message:o.message||`Please fill in the details for ${a.command}:`,fields:h}}return{type:"ambiguous",message:o.message||`Need more info for ${a.command}...`}}return this.conversationContext=null,a.critical?(this.pendingConfirmation={...a,action:()=>a.action(n)},{type:"ambiguous",message:`Are you sure you want to ${a.description||a.command}?`,options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}):this.runAction(a,n)}}else if(o.type==="ambiguous"&&o.options)return{type:"ambiguous",message:"Did you mean...",options:o.options.map(a=>({label:a.label,value:a.label}))}}return{type:"ambiguous",message:"I'm not sure what you mean. Here is what I can do:",options:s.map(o=>({label:o.command,value:o.command}))}}async runAction(e,t){try{const s=await e.action(t);return typeof s=="string"?{type:"success",message:s}:s&&s.type?s:{type:"success",message:`Executed: ${e.command}`}}catch(s){return{type:"error",message:s.message||"An error occurred during execution."}}}getCommands(){return Array.from(this.commands.keys())}}class k{constructor(){this.synth=window.speechSynthesis}speak(e,t){if(!this.synth){console.error("SpeechSynthesis API is not supported in this browser.");return}const s=new SpeechSynthesisUtterance(e);t&&(s.pitch=t.pitch||1,s.rate=t.rate||1,s.volume=t.volume||1),s.onend=()=>{console.log("Speech finished.")},s.onerror=i=>{console.error("Error during speech synthesis:",i.error)},this.synth.speak(s)}stopSpeaking(){this.synth&&this.synth.cancel()}}class P{constructor(){this.fallbackMessage="Sorry, I didn’t understand that."}setFallbackMessage(e){this.fallbackMessage=e}handleFallback(e){console.log(this.fallbackMessage),new k().speak(this.fallbackMessage)}}class T{constructor(e="en-US"){this.isListening=!1,this.isStoppedSpeechRecog=!1,this.restartAllowed=!0}startListening(e){console.warn("VoiceProcessor: Voice interaction is currently DISABLED.")}stopListening(){if(console.log("VoiceProcessor: Stopping listening..."),this.isStoppedSpeechRecog=!0,this.restartAllowed=!1,!this.isListening){console.warn("VoiceProcessor: Already stopped. Skipping stop...");return}try{this.recognition.stop(),this.isListening=!1,console.log("VoiceProcessor: Listening stopped.")}catch(e){console.error("VoiceProcessor: Failed to stop SpeechRecognition:",e)}}handleResult(e,t){}handleEnd(){console.log("VoiceProcessor: Session ended."),this.isListening=!1,this.restartAllowed&&!this.isStoppedSpeechRecog&&(console.log("VoiceProcessor: Restarting session due to unexpected stop..."),setTimeout(()=>this.startListening(()=>{}),560))}handleError(e){console.error("VoiceProcessor: Error occurred:",e.error),e.error==="no-speech"?console.log("VoiceProcessor: No speech detected."):e.error==="audio-capture"&&console.log("VoiceProcessor: Microphone not detected."),this.isListening=!1}}class B{constructor(){this.lastTap=0}setupDoubleTapListener(e){document.addEventListener("dblclick",()=>{e()}),document.addEventListener("touchend",t=>{const s=new Date().getTime(),i=s-this.lastTap;i<300&&i>0&&e(),this.lastTap=s})}}function D(){if(document.querySelector("#assistant-styles")){console.log("Styles already injected");return}const e=document.createElement("style");e.id="assistant-styles",e.innerHTML=`
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
2
  /* Rounded shape with gradient animation */
3
3
  .gradient-indicator {
4
4
  position: fixed;
@@ -31,382 +31,325 @@
31
31
  border-radius: 50%;
32
32
  }
33
33
  }
34
- `,document.head.appendChild(e),console.log("Gradient styles injected")}function R(){if(document.querySelector("#gradient-indicator"))return;const r=document.createElement("div");r.id="gradient-indicator",D(),r.classList.add("gradient-indicator"),document.body.appendChild(r),console.log("Gradient indicator added to the DOM")}function H(){const r=document.querySelector("#gradient-indicator");r&&(r.remove(),console.log("Gradient indicator removed from the DOM"))}class N{constructor(){this.state="idle",this.subscribers=[]}getState(){return this.state}setState(e){this.state=e,this.notifySubscribers(),console.log("State updated:",e),e==="listening"?R():H()}subscribe(e){this.subscribers.push(e)}notifySubscribers(){this.subscribers.forEach(e=>e(this.state))}}const l=class l{constructor(e){this.isOpen=!1,this.submitCallback=null,this.closeCallback=null,this.chatContainer=null,this.config={},e&&(this.config=e),this.injectStyles(),this.injectOverlay(),this.injectFloatingButton(),this.setupEventListeners(),this.chatContainer=document.getElementById("foisit-chat-history")}destroy(){const e=document.getElementById(l.OVERLAY_ID);e&&e.remove();const t=document.getElementById(l.STYLES_ID);t&&t.remove();const s=document.getElementById("foisit-floating-btn");s&&s.remove(),this.isOpen=!1,this.chatContainer=null,this.submitCallback=null,this.closeCallback=null}registerCallbacks(e,t){this.submitCallback=e,this.closeCallback=t||null}show(e,t){const s=document.getElementById(l.OVERLAY_ID),i=document.getElementById(l.INPUT_ID);this.chatContainer=document.getElementById("foisit-chat-history"),s&&i&&(this.submitCallback=e,this.closeCallback=t||null,s.style.display="flex",setTimeout(()=>{s.classList.add("visible"),i.focus(),i.focus(),i.value="",this.chatContainer&&(this.chatContainer.innerHTML="")},10),this.isOpen=!0)}hide(){const e=document.getElementById(l.OVERLAY_ID);e&&(e.classList.remove("visible"),setTimeout(()=>{e.style.display="none"},300),this.isOpen=!1,this.closeCallback&&this.closeCallback())}toggle(e,t){this.isOpen?this.hide():this.show(e,t)}addMessage(e,t="system"){if(!this.chatContainer)return;const s=document.createElement("div");s.className=`foisit-bubble ${t}`,s.textContent=e,this.chatContainer.appendChild(s),this.scrollToBottom()}addOptions(e){if(!this.chatContainer)return;const t=document.createElement("div");t.className="foisit-options-container",e.forEach(s=>{const i=document.createElement("button");i.className="foisit-option-chip",i.textContent=s.label,i.onclick=()=>{this.addMessage(s.label,"user"),this.submitCallback&&this.submitCallback(s.value)},t.appendChild(i)}),this.chatContainer.appendChild(t),this.scrollToBottom()}injectFloatingButton(){var i,c,o,a;if(((i=this.config.floatingButton)==null?void 0:i.visible)===!1)return;const e=document.getElementById("foisit-floating-btn");e&&e.remove();const t=document.createElement("div");t.id="foisit-floating-btn",t.className="foisit-floating-btn",t.title=((c=this.config.floatingButton)==null?void 0:c.tooltip)||"Open Foisit Assistant";const s=(o=this.config.floatingButton)==null?void 0:o.position;s&&(t.style.bottom=s.bottom,t.style.right=s.right),(a=this.config.floatingButton)!=null&&a.customHtml?t.innerHTML=this.config.floatingButton.customHtml:t.innerHTML=`
35
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
36
- <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 4C16.42 4 20 7.58 20 12C20 16.42 16.42 20 12 20C7.58 20 4 16.42 4 12C4 7.58 7.58 4 12 4Z" fill="white" fill-opacity="0.8"/>
37
- <path d="M12 6C8.69 6 6 8.69 6 12C6 15.31 8.69 18 12 18C15.31 18 18 15.31 18 12C18 8.69 15.31 6 12 6ZM12 16C9.79 16 8 14.21 8 12C8 9.79 9.79 8 12 8C14.21 8 16 9.79 16 12C16 14.21 14.21 16 12 16Z" fill="white"/>
38
- </svg>
39
- `,t.onclick=()=>{this.submitCallback&&this.toggle(this.submitCallback,this.closeCallback||void 0)},document.body.appendChild(t)}addForm(e,t,s){if(!this.chatContainer)return;const i=document.createElement("div");i.className="foisit-form-card";const c=document.createElement("div");c.className="foisit-form-message",c.textContent=e,i.appendChild(c);const o={};t.forEach(n=>{var f,w;const h=document.createElement("div");h.className="foisit-field-group";const m=document.createElement("label");m.textContent=n.label,h.appendChild(m);let d;if((n.type==="select"||n.options)&&((f=n.options)!=null&&f.length)&&n.options.length>0){d=document.createElement("select"),d.className="foisit-field-input";const p=document.createElement("option");p.value="",p.textContent=`Select ${n.label}`,p.disabled=!0,p.selected=!n.value,d.appendChild(p),(w=n.options)==null||w.forEach(x=>{const b=document.createElement("option");b.value=x.value,b.textContent=x.label,n.value===x.value&&(b.selected=!0),d.appendChild(b)})}else d=document.createElement("input"),d.className="foisit-field-input",d.placeholder=n.label,d.value=n.value||"",n.type==="date"?d.type="date":n.type==="number"?d.type="number":d.type="text";o[n.name]=d,h.appendChild(d),i.appendChild(h)});const a=document.createElement("button");a.className="foisit-form-submit",a.textContent="Submit",a.onclick=()=>{const n={};Object.keys(o).forEach(h=>{n[h]=o[h].value}),a.disabled=!0,a.textContent="Submitted",i.style.opacity="0.7",i.style.pointerEvents="none",s(n)},i.appendChild(a),this.chatContainer.appendChild(i),this.scrollToBottom()}showLoading(){if(!this.chatContainer||document.getElementById("foisit-loading-bubble"))return;const e=document.createElement("div");e.id="foisit-loading-bubble",e.className="foisit-bubble system loading",e.innerHTML="<span>.</span><span>.</span><span>.</span>",this.chatContainer.appendChild(e),this.scrollToBottom()}hideLoading(){const e=document.getElementById("foisit-loading-bubble");e&&e.remove()}scrollToBottom(){this.chatContainer&&(this.chatContainer.scrollTop=this.chatContainer.scrollHeight)}injectStyles(){if(document.getElementById(l.STYLES_ID))return;const e=document.createElement("style");e.id=l.STYLES_ID,e.innerHTML=`
40
- #${l.OVERLAY_ID} {
41
- position: fixed;
42
- top: 24px;
43
- right: 24px;
44
- width: 320px;
45
- z-index: 99999;
46
- display: none;
47
- flex-direction: column;
48
- opacity: 0;
49
- transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
50
- transform: translateY(-10px);
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="&times;",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;
51
58
  }
52
59
 
53
- #${l.OVERLAY_ID}.visible {
54
- opacity: 1;
55
- transform: translateY(0);
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
+ }
56
84
  }
57
85
 
58
- .foisit-content {
59
- width: 100%;
60
- padding: 0;
61
- border-radius: 16px;
62
- overflow: hidden;
63
- /* Stronger Frosted Look (User Provided) */
64
- background: linear-gradient(
65
- 135deg,
66
- rgba(255, 255, 255, 0.25),
67
- rgba(255, 255, 255, 0.05)
68
- );
69
- backdrop-filter: blur(20px);
70
- -webkit-backdrop-filter: blur(20px);
71
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
72
- border: 1px solid rgba(255, 255, 255, 0.4);
73
- display: flex;
74
- flex-direction: column;
86
+ @keyframes foisitPulse {
87
+ 0%, 100% { transform: scale(0.8); opacity: 0.5; }
88
+ 50% { transform: scale(1.2); opacity: 1; }
75
89
  }
76
90
 
77
- #${l.INPUT_ID} {
78
- width: 100%;
79
- background: transparent;
80
- border: none;
81
- font-size: 16px;
82
- color: #333;
83
- padding: 18px 20px 12px 20px;
84
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
85
- outline: none;
86
- text-align: left;
87
- resize: none;
88
- min-height: 48px;
89
- max-height: 200px;
90
- overflow-y: auto;
91
+ @keyframes foisitShake {
92
+ 0%, 100% { transform: translateX(0); }
93
+ 25% { transform: translateX(-4px); }
94
+ 75% { transform: translateX(4px); }
91
95
  }
96
+ .foisit-shake { animation: foisitShake 0.4s ease-in-out; }
92
97
 
93
- #${l.INPUT_ID}::placeholder {
94
- color: rgba(60, 60, 67, 0.7);
95
- font-weight: 500;
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;
96
110
  }
97
-
98
- @media (prefers-color-scheme: dark) {
99
- .foisit-content {
100
- background: linear-gradient(
101
- 135deg,
102
- rgba(40, 40, 40, 0.65),
103
- rgba(40, 40, 40, 0.25)
104
- );
105
- border: 1px solid rgba(255, 255, 255, 0.1);
106
- }
107
- #${l.INPUT_ID} {
108
- color: white;
109
- }
110
- #${l.INPUT_ID}::placeholder {
111
- color: rgba(235, 235, 245, 0.6);
112
- }
113
- .foisit-watermark {
114
- color: rgba(255, 255, 255, 0.5);
115
- }
111
+
112
+ .foisit-overlay-container * {
113
+ box-sizing: border-box;
116
114
  }
117
115
 
118
- .foisit-watermark {
119
- align-self: flex-end;
120
- margin: 0 12px 10px auto;
121
- padding: 4px 8px;
122
- border-radius: 8px;
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;
123
127
 
124
- font-size: 9px;
125
- font-weight: 600;
126
- letter-spacing: 0.8px;
127
- text-transform: capitalize;
128
+ background: var(--foisit-bg);
129
+ border: var(--foisit-border);
130
+ box-shadow: var(--foisit-shadow);
128
131
 
129
- background: rgba(0, 0, 0, 0.35);
130
- backdrop-filter: blur(6px);
131
- -webkit-backdrop-filter: blur(6px);
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
+ }
132
143
 
133
- color: rgba(255, 255, 255, 0.85);
134
- pointer-events: none;
135
- }
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
+ }
136
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; }
137
172
 
138
- /* Chat UI Styles */
139
- #foisit-chat-history {
173
+ /* Message Area */
174
+ .foisit-messages {
140
175
  flex: 1;
141
176
  overflow-y: auto;
142
177
  padding: 16px;
143
178
  display: flex;
144
179
  flex-direction: column;
145
- gap: 12px;
146
- max-height: 400px;
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;
147
193
  }
148
194
 
195
+ /* Bubbles */
149
196
  .foisit-bubble {
150
- max-width: 85%;
151
- padding: 8px 12px;
152
- border-radius: 12px;
153
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
197
+ max-width: 90%;
198
+ padding: 8px 14px;
199
+ border-radius: 14px;
154
200
  font-size: 14px;
155
201
  line-height: 1.4;
202
+ word-wrap: break-word;
156
203
  }
157
204
 
158
205
  .foisit-bubble.user {
159
206
  align-self: flex-end;
160
- background: rgba(0, 0, 0, 0.05); /* Subtle dark for user */
161
- color: #333;
207
+ background: var(--foisit-bubble-user-bg);
208
+ color: var(--foisit-bubble-user-text);
162
209
  border-bottom-right-radius: 4px;
163
210
  }
164
211
 
165
212
  .foisit-bubble.system {
166
213
  align-self: flex-start;
167
- background: rgba(255, 255, 255, 0.4); /* Glassy white */
168
- color: #333;
214
+ background: var(--foisit-bubble-sys-bg);
215
+ color: var(--foisit-bubble-sys-text);
169
216
  border-bottom-left-radius: 4px;
217
+ border: 1px solid rgba(255,255,255,0.1);
170
218
  }
171
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 */
172
244
  .foisit-options-container {
173
245
  display: flex;
174
246
  flex-wrap: wrap;
175
247
  gap: 8px;
176
- margin-left: 4px;
248
+ margin-left: 2px;
249
+ margin-top: 4px;
177
250
  }
178
251
 
179
252
  .foisit-option-chip {
180
- padding: 6px 12px;
181
- background: rgba(255, 255, 255, 0.5);
182
- border: 1px solid rgba(0, 0, 0, 0.1);
253
+ padding: 6px 14px;
254
+ background: var(--foisit-bubble-sys-bg);
255
+ border: 1px solid rgba(127,127,127,0.1);
183
256
  border-radius: 20px;
184
257
  font-size: 13px;
185
- color: #333;
258
+ color: var(--foisit-text);
186
259
  cursor: pointer;
187
260
  transition: all 0.2s;
261
+ font-weight: 500;
188
262
  }
189
-
190
263
  .foisit-option-chip:hover {
191
- background: rgba(255, 255, 255, 0.8);
192
- transform: translateY(-1px);
193
- box-shadow: 0 2px 5px rgba(0,0,0,0.05);
264
+ background: rgba(127,127,127,0.15);
194
265
  }
195
266
 
196
- @media (prefers-color-scheme: dark) {
197
- .foisit-bubble.user {
198
- background: rgba(255, 255, 255, 0.1);
199
- color: white;
200
- }
201
- .foisit-bubble.system {
202
- background: rgba(255, 255, 255, 0.05);
203
- color: rgba(255, 255, 255, 0.9);
204
- }
205
- .foisit-option-chip {
206
- background: rgba(255, 255, 255, 0.1);
207
- border-color: rgba(255, 255, 255, 0.2);
208
- color: white;
209
- }
210
- .foisit-option-chip:hover {
211
- background: rgba(255, 255, 255, 0.2);
212
- }
213
- /* Loading State */
214
- .foisit-loading-dots {
215
- display: inline-flex;
216
- gap: 4px;
217
- align-items: center;
218
- padding: 4px 8px;
219
- background: rgba(255, 255, 255, 0.4);
220
- border-radius: 12px;
221
- margin-left: 12px;
222
- align-self: flex-start;
223
- }
224
- .foisit-dot {
225
- width: 6px;
226
- height: 6px;
227
- background: #666;
228
- border-radius: 50%;
229
- animation: foisit-bounce 1.4s infinite ease-in-out both;
230
- }
231
- .foisit-dot:nth-child(1) { animation-delay: -0.32s; }
232
- .foisit-dot:nth-child(2) { animation-delay: -0.16s; }
233
-
234
- @keyframes foisit-bounce {
235
- 0%, 80%, 100% { transform: scale(0); }
236
- 40% { transform: scale(1); }
237
- }
238
-
239
- /* Floating Trigger Button - Glassmorphism Style */
240
- .foisit-floating-btn {
241
- position: fixed;
242
- bottom: 20px;
243
- right: 20px;
244
- width: 52px;
245
- height: 52px;
246
- /* Frosted Glass Effect */
247
- background: linear-gradient(
248
- 135deg,
249
- rgba(255, 255, 255, 0.25),
250
- rgba(255, 255, 255, 0.08)
251
- );
252
- backdrop-filter: blur(16px);
253
- -webkit-backdrop-filter: blur(16px);
254
- border-radius: 50%;
255
- display: flex;
256
- align-items: center;
257
- justify-content: center;
258
- cursor: pointer;
259
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
260
- border: 1px solid rgba(255, 255, 255, 0.35);
261
- z-index: 9998;
262
- transition: transform 0.2s ease, box-shadow 0.2s ease;
263
- }
264
-
265
- .foisit-floating-btn:hover {
266
- transform: scale(1.08);
267
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
268
- }
269
-
270
- /* Dark mode for floating button */
271
- @media (prefers-color-scheme: dark) {
272
- .foisit-floating-btn {
273
- background: linear-gradient(
274
- 135deg,
275
- rgba(60, 60, 60, 0.6),
276
- rgba(40, 40, 40, 0.35)
277
- );
278
- border-color: rgba(255, 255, 255, 0.15);
279
- }
280
- }
281
-
282
- .foisit-floating-btn img {
283
- width: 100%;
284
- height: 100%;
285
- object-fit: cover;
286
- border-radius: 50%;
287
- }
288
-
289
- /* Dark mode support for inputs */
290
- @media (prefers-color-scheme: dark) {
291
- .foisit-field-input {
292
- background: rgba(40, 40, 40, 0.6);
293
- color: white;
294
- border-color: rgba(255, 255, 255, 0.1);
295
- }
296
- }
297
- .foisit-watermark {
298
- color: rgba(255, 255, 255, 0.3);
299
- }
300
- }
301
-
302
- /* Loading Animation */
303
- .foisit-bubble.loading span {
304
- animation: foisit-dots 1.4s infinite ease-in-out both;
305
- font-size: 20px;
306
- line-height: 10px;
307
- margin: 0 1px;
308
- }
309
-
310
- .foisit-bubble.loading span:nth-child(1) { animation-delay: -0.32s; }
311
- .foisit-bubble.loading span:nth-child(2) { animation-delay: -0.16s; }
312
-
313
- @keyframes foisit-dots {
314
- 0%, 80%, 100% { transform: scale(0); opacity: 0.5; }
315
- 40% { transform: scale(1); opacity: 1; }
316
- }
317
-
318
- /* Form Styles */
319
- .foisit-form-card {
320
- align-self: flex-start;
321
- background: rgba(255, 255, 255, 0.4);
267
+ /* Form Styling */
268
+ .foisit-form {
269
+ background: var(--foisit-bubble-sys-bg);
322
270
  padding: 16px;
323
- border-radius: 12px;
324
- width: 100%;
325
- box-sizing: border-box;
326
- border: 1px solid rgba(255, 255, 255, 0.2);
271
+ border-radius: 14px;
327
272
  display: flex;
328
273
  flex-direction: column;
329
274
  gap: 12px;
275
+ width: 100%;
276
+ border: 1px solid rgba(127,127,127,0.1);
330
277
  }
331
278
 
332
- .foisit-form-message {
333
- font-family: -apple-system, sans-serif;
334
- font-size: 14px;
335
- color: #333;
336
- margin-bottom: 4px;
337
- font-weight: 500;
338
- }
339
-
340
- .foisit-field-group {
341
- display: flex;
342
- flex-direction: column;
343
- gap: 4px;
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;
344
285
  }
345
286
 
346
- .foisit-field-group label {
347
- font-size: 11px;
348
- font-weight: 600;
349
- text-transform: uppercase;
350
- color: rgba(0, 0, 0, 0.5);
287
+ .foisit-req-star {
288
+ color: var(--foisit-req-star);
289
+ font-weight: bold;
351
290
  }
352
291
 
353
- .foisit-field-input {
354
- background: rgba(255, 255, 255, 0.6);
355
- border: 1px solid rgba(0, 0, 0, 0.1);
292
+ .foisit-form-input {
293
+ width: 100%;
294
+ padding: 10px;
356
295
  border-radius: 8px;
357
- padding: 8px 12px;
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);
358
299
  font-size: 14px;
359
- color: #333;
360
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);
361
306
  }
362
307
 
363
- .foisit-field-input:focus {
364
- border-color: rgba(0, 0, 0, 0.3);
308
+ .foisit-error-border {
309
+ border-color: var(--foisit-error-border) !important;
365
310
  }
366
311
 
367
- .foisit-form-submit {
368
- background: #000;
369
- color: #fff;
370
- border: none;
371
- border-radius: 8px;
372
- padding: 10px;
373
- font-size: 14px;
374
- font-weight: 500;
375
- cursor: pointer;
376
- transition: opacity 0.2s;
312
+ .foisit-form-error {
313
+ font-size: 11px;
314
+ color: var(--foisit-error-text);
377
315
  margin-top: 4px;
378
316
  }
379
317
 
380
- .foisit-form-submit:hover {
381
- opacity: 0.8;
318
+ /* Loading */
319
+ .foisit-loading-dots {
320
+ display: inline-flex;
321
+ gap: 4px;
322
+ padding: 10px 14px;
323
+ align-self: flex-start;
382
324
  }
383
-
384
- @media (prefers-color-scheme: dark) {
385
- .foisit-form-card {
386
- background: rgba(255, 255, 255, 0.05);
387
- color: white;
388
- }
389
- .foisit-form-message {
390
- color: white;
391
- }
392
- .foisit-field-group label {
393
- color: rgba(255, 255, 255, 0.5);
394
- }
395
- .foisit-field-input {
396
- background: rgba(0, 0, 0, 0.2);
397
- border-color: rgba(255, 255, 255, 0.1);
398
- color: white;
399
- }
400
- .foisit-form-submit {
401
- background: #fff;
402
- color: #000;
403
- }
325
+ .foisit-dot {
326
+ width: 6px;
327
+ height: 6px;
328
+ border-radius: 50%;
329
+ background: var(--foisit-text);
330
+ opacity: 0.4;
404
331
  }
405
332
 
406
- `,document.head.appendChild(e)}injectOverlay(){if(document.getElementById(l.OVERLAY_ID))return;const e=this.config.inputPlaceholder||"How can I help you?",t=document.createElement("div");t.id=l.OVERLAY_ID,t.innerHTML=`
407
- <div class="foisit-content">
408
- <div id="foisit-chat-history"></div>
409
- <textarea id="${l.INPUT_ID}" placeholder="${e}" autocomplete="off" rows="1"></textarea>
410
- <div class="foisit-watermark">Foisit</div>
411
- </div>
412
- `,document.body.appendChild(t)}setupEventListeners(){const e=document.getElementById(l.OVERLAY_ID),t=document.getElementById(l.INPUT_ID);!e||!t||(t.addEventListener("input",()=>{t.style.height="auto",t.style.height=Math.min(t.scrollHeight,200)+"px"}),e.addEventListener("click",s=>{s.target===e&&this.hide()}),t.addEventListener("keydown",s=>{if(s.key==="Enter"&&!s.shiftKey){s.preventDefault();const i=t.value.trim();i&&this.submitCallback&&(this.submitCallback(i),t.value="",t.style.height="auto")}s.key==="Escape"&&this.hide()}))}};l.OVERLAY_ID="foisit-assistant-overlay",l.INPUT_ID="foisit-assistant-input",l.STYLES_ID="foisit-assistant-styles";let v=l;class S{constructor(e){this.config=e,this.isActivated=!1,this.lastProcessedInput="",this.processingLock=!1,this.defaultIntroMessage="How can I help you?",this.commandHandler=new M(this.config.enableSmartIntent!==!1),this.fallbackHandler=new P,this.voiceProcessor=new T,this.textToSpeech=new k,this.stateManager=new N,this.gestureHandler=new B,this.overlayManager=new v({floatingButton:this.config.floatingButton,inputPlaceholder:this.config.inputPlaceholder}),this.config.commands.forEach(t=>this.commandHandler.addCommand(t)),this.config.fallbackResponse&&this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse),this.gestureHandler.setupDoubleTapListener(()=>this.toggle()),this.overlayManager.registerCallbacks(async t=>{this.overlayManager.addMessage(t,"user"),await this.handleCommand(t)},()=>console.log("AssistantService: Overlay closed."))}startListening(){console.log("AssistantService: Starting listening..."),this.voiceProcessor.startListening(async e=>{var i,c;if(this.processingLock)return;const t=e.toLowerCase().trim();if(!t||t.length<3||t===this.lastProcessedInput){console.log("AssistantService: Ignoring irrelevant input.");return}if(this.lastProcessedInput=t,!this.isActivated){await this.processActivation(t);return}t===((i=this.config.fallbackResponse)==null?void 0:i.toLowerCase())||t===((c=this.config.introMessage)==null?void 0:c.toLowerCase())||t===this.defaultIntroMessage.toLowerCase()?console.log("AssistantService: Ignoring fallback or intro message."):await this.handleCommand(t),this.processingLock=!0,setTimeout(()=>this.processingLock=!1,1e3)})}stopListening(){console.log("AssistantService: Stopping listening..."),this.voiceProcessor.stopListening(),this.isActivated=!1}async processActivation(e){var s;const t=(s=this.config.activationCommand)==null?void 0:s.toLowerCase();t&&(e===t?(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(e){this.overlayManager.showLoading();const t=await this.commandHandler.executeCommand(e);this.overlayManager.hideLoading(),t.message&&this.overlayManager.addMessage(t.message,"system"),t.type==="form"&&t.fields?this.overlayManager.addForm(t.message,t.fields,async s=>{this.overlayManager.showLoading();const i=await this.commandHandler.executeCommand(s);this.overlayManager.hideLoading(),this.processResponse(i)}):t.type==="ambiguous"&&t.options?this.overlayManager.addOptions(t.options):t.type==="error"&&this.fallbackHandler.handleFallback(e)}destroy(){this.voiceProcessor.stopListening(),this.overlayManager.destroy()}processResponse(e){e.message&&this.overlayManager.addMessage(e.message,"system"),e.type==="form"&&e.fields?this.overlayManager.addForm(e.message,e.fields,async t=>{this.overlayManager.showLoading();const s=await this.commandHandler.executeCommand(t);this.overlayManager.hideLoading(),this.processResponse(s)}):e.type==="ambiguous"&&e.options&&this.overlayManager.addOptions(e.options)}addCommand(e,t){console.log(typeof e=="string"?`AssistantService: Adding command "${e}".`:`AssistantService: Adding rich command "${e.command}".`),this.commandHandler.addCommand(e,t)}removeCommand(e){console.log(`AssistantService: Removing command "${e}".`),this.commandHandler.removeCommand(e)}getCommands(){return this.commandHandler.getCommands()}toggle(e,t){console.log("AssistantService: Toggling overlay..."),this.overlayManager.toggle(async s=>{this.overlayManager.addMessage(s,"user"),e&&e(s),await this.handleCommand(s)},()=>{console.log("AssistantService: Overlay closed."),t&&t()})}}const C=u.createContext(null);let y=null;const $=({config:r,children:e})=>{const[t,s]=u.useState(null),[i,c]=u.useState(!1);return u.useEffect(()=>{y?console.warn("Multiple AssistantProvider instances detected. Reusing global AssistantService."):(console.log("Initializing global AssistantService..."),y=new S(r));const o=y;return s(o),o.startListening(),c(!0),()=>{var a;console.log("Cleaning up AssistantService..."),(a=o.destroy)==null||a.call(o),y=null}},[r]),!i||!t?g.jsx("div",{children:"Loading Assistant..."}):g.jsx(C.Provider,{value:t,children:e})},A=()=>{const r=u.useContext(C);if(console.log("assistant",r),!r)throw new Error("useAssistant must be used within an AssistantProvider");return r},O=({label:r="Activate Assistant",onActivate:e})=>{const t=A(),s=()=>{e&&e(),t.reactivate()};return g.jsx("button",{onClick:s,className:"assistant-activator",children:r})},F=r=>{const[e,t]=u.useState(r.getState());return u.useEffect(()=>{const s=i=>{t(i)};return r.subscribe(s),()=>{r.subscribe(()=>{})}},[r]),e};exports.AssistantActivator=O;exports.AssistantContext=C;exports.AssistantProvider=$;exports.AssistantService=S;exports.ReactWrapper=E;exports.useAssistant=A;exports.useAssistantState=F;
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;