dunefox-chatbot 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Official SDK for embedding the [Dunefox](https://dunefox.io) AI chatbot widget on any website.
4
4
 
5
- Get your **Tenant ID** from **Console → Install Widget**.
5
+ Get your **Tenant ID** from **Console → Integrations**.
6
6
 
7
7
  ---
8
8
 
@@ -1,4 +1,4 @@
1
- "use strict";var DunefoxChat=(()=>{var f=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var L=(e,t)=>{for(var n in t)f(e,n,{get:t[n],enumerable:!0})},O=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of S(t))!D.call(e,a)&&a!==n&&f(e,a,{get:()=>t[a],enumerable:!(i=I(t,a))||i.enumerable});return e};var C=e=>O(f({},"__esModule",{value:!0}),e);var T={};L(T,{close:()=>v,destroy:()=>E,init:()=>b,open:()=>y});var B="https://app.dunefox.io",U="https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png",g="dunefox_chat_uuid";function $(){var e,t;try{let n=localStorage.getItem(g);return n||(n=(t=(e=crypto==null?void 0:crypto.randomUUID)==null?void 0:e.call(crypto))!=null?t:Math.random().toString(36).slice(2)+Date.now().toString(36),localStorage.setItem(g,n)),n}catch(n){return Math.random().toString(36).slice(2)+Date.now().toString(36)}}function k(e){if(document.getElementById("dunefox-styles"))return;let t=e.startsWith("top"),i=e.endsWith("left")?"left:16px":"right:16px",u=`
1
+ "use strict";var DunefoxChat=(()=>{var m=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var L=(e,t)=>{for(var n in t)m(e,n,{get:t[n],enumerable:!0})},O=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of S(t))!D.call(e,a)&&a!==n&&m(e,a,{get:()=>t[a],enumerable:!(i=I(t,a))||i.enumerable});return e};var C=e=>O(m({},"__esModule",{value:!0}),e);var T={};L(T,{close:()=>v,destroy:()=>E,init:()=>b,open:()=>y});var B="https://app.dunefox.io",U="https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png",g="dunefox_chat_uuid";function $(){var e,t;try{let n=localStorage.getItem(g);return n||(n=(t=(e=crypto==null?void 0:crypto.randomUUID)==null?void 0:e.call(crypto))!=null?t:Math.random().toString(36).slice(2)+Date.now().toString(36),localStorage.setItem(g,n)),n}catch(n){return Math.random().toString(36).slice(2)+Date.now().toString(36)}}function k(e){if(document.getElementById("dunefox-styles"))return;let t=e.startsWith("top"),i=e.endsWith("left")?"left:16px":"right:16px",p=`
2
2
  #dunefox-btn {
3
3
  position: fixed; ${t?"top:16px":"bottom:16px"}; ${i};
4
4
  width: 60px; height: 60px; border-radius: 50%;
@@ -22,11 +22,16 @@
22
22
  opacity: 1; visibility: visible; transform: translateY(0) scale(1);
23
23
  }
24
24
  @media (max-width: 768px) {
25
+ #dunefox-btn {
26
+ bottom: unset !important; top: 16px !important;
27
+ right: 16px !important; left: unset !important;
28
+ }
25
29
  #dunefox-frame {
26
- width: 100vw; height: 100vh; max-height: none;
27
- inset: 0; border-radius: 0; transform: ${t?"translateY(-100%)":"translateY(100%)"};
28
- bottom: unset; right: unset; left: unset; top: unset;
30
+ width: 100% !important; height: 100% !important; max-height: none !important;
31
+ position: fixed !important; inset: 0 !important;
32
+ border-radius: 0 !important;
33
+ transform: ${t?"translateY(-100%)":"translateY(100%)"} !important;
29
34
  }
30
- #dunefox-frame.df-open { transform: translateY(0); }
35
+ #dunefox-frame.df-open { transform: translateY(0) !important; }
31
36
  }
32
- `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=u,document.head.appendChild(o)}var A='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',p=!1;function b(e){let t=typeof e=="string"?{tenantId:e}:e;if(p){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:i="bottom-right",defaultOpen:a=!1,baseUrl:m=B,iconUrl:x=U}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(l=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",l,{once:!0}):l())(()=>{k(i);let l=$(),u=`${m}/api/${n}?uuid=${l}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=u;let r=document.createElement("button");r.id="dunefox-btn",r.setAttribute("aria-label","Open chat"),r.setAttribute("aria-expanded","false");let s=document.createElement("img");s.src=x,s.alt="",s.width=60,s.height=60,s.style.cssText="display:block;border-radius:50%;object-fit:cover;";let c=document.createElement("span");c.innerHTML=A,c.style.display="none",r.append(s,c);let d=a,h=()=>{o.classList.toggle("df-open",d),s.style.display=d?"none":"block",c.style.display=d?"block":"none",r.setAttribute("aria-expanded",String(d))};r.addEventListener("click",()=>{d=!d,h()}),document.body.append(o,r),h(),p=!0})}function y(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.add("df-open"),t.setAttribute("aria-expanded","true"))}function v(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.remove("df-open"),t.setAttribute("aria-expanded","false"))}function E(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),p=!1}return C(T);})();
37
+ `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=p,document.head.appendChild(o)}var A='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',u=!1;function b(e){let t=typeof e=="string"?{tenantId:e}:e;if(u){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:i="bottom-right",defaultOpen:a=!1,baseUrl:f=B,iconUrl:x=U}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(l=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",l,{once:!0}):l())(()=>{k(i);let l=$(),p=`${f}/api/${n}?uuid=${l}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=p;let r=document.createElement("button");r.id="dunefox-btn",r.setAttribute("aria-label","Open chat"),r.setAttribute("aria-expanded","false");let s=document.createElement("img");s.src=x,s.alt="",s.width=60,s.height=60,s.style.cssText="display:block;border-radius:50%;object-fit:cover;";let c=document.createElement("span");c.innerHTML=A,c.style.display="none",r.append(s,c);let d=a,h=()=>{o.classList.toggle("df-open",d),s.style.display=d?"none":"block",c.style.display=d?"block":"none",r.setAttribute("aria-expanded",String(d))};r.addEventListener("click",()=>{d=!d,h()}),document.body.append(o,r),h(),u=!0})}function y(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.add("df-open"),t.setAttribute("aria-expanded","true"))}function v(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.remove("df-open"),t.setAttribute("aria-expanded","false"))}function E(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),u=!1}return C(T);})();
package/dist/index.js CHANGED
@@ -22,13 +22,18 @@
22
22
  opacity: 1; visibility: visible; transform: translateY(0) scale(1);
23
23
  }
24
24
  @media (max-width: 768px) {
25
+ #dunefox-btn {
26
+ bottom: unset !important; top: 16px !important;
27
+ right: 16px !important; left: unset !important;
28
+ }
25
29
  #dunefox-frame {
26
- width: 100vw; height: 100vh; max-height: none;
27
- inset: 0; border-radius: 0; transform: ${t?"translateY(-100%)":"translateY(100%)"};
28
- bottom: unset; right: unset; left: unset; top: unset;
30
+ width: 100% !important; height: 100% !important; max-height: none !important;
31
+ position: fixed !important; inset: 0 !important;
32
+ border-radius: 0 !important;
33
+ transform: ${t?"translateY(-100%)":"translateY(100%)"} !important;
29
34
  }
30
- #dunefox-frame.df-open { transform: translateY(0); }
35
+ #dunefox-frame.df-open { transform: translateY(0) !important; }
31
36
  }
32
- `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var w='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',u=false;function I(e){let t=typeof e=="string"?{tenantId:e}:e;if(u){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:p=false,baseUrl:f=b,iconUrl:m=y}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{E(d);let s=v(),c=`${f}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let a=document.createElement("button");a.id="dunefox-btn",a.setAttribute("aria-label","Open chat"),a.setAttribute("aria-expanded","false");let r=document.createElement("img");r.src=m,r.alt="",r.width=60,r.height=60,r.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=w,l.style.display="none",a.append(r,l);let i=p,x=()=>{o.classList.toggle("df-open",i),r.style.display=i?"none":"block",l.style.display=i?"block":"none",a.setAttribute("aria-expanded",String(i));};a.addEventListener("click",()=>{i=!i,x();}),document.body.append(o,a),x(),u=true;});}function S(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.add("df-open"),t.setAttribute("aria-expanded","true"));}function D(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.remove("df-open"),t.setAttribute("aria-expanded","false"));}function O(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),u=false;}
37
+ `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var w='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',p=false;function I(e){let t=typeof e=="string"?{tenantId:e}:e;if(p){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:m=false,baseUrl:u=b,iconUrl:f=y}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{E(d);let s=v(),c=`${u}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let a=document.createElement("button");a.id="dunefox-btn",a.setAttribute("aria-label","Open chat"),a.setAttribute("aria-expanded","false");let i=document.createElement("img");i.src=f,i.alt="",i.width=60,i.height=60,i.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=w,l.style.display="none",a.append(i,l);let r=m,x=()=>{o.classList.toggle("df-open",r),i.style.display=r?"none":"block",l.style.display=r?"block":"none",a.setAttribute("aria-expanded",String(r));};a.addEventListener("click",()=>{r=!r,x();}),document.body.append(o,a),x(),p=true;});}function S(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.add("df-open"),t.setAttribute("aria-expanded","true"));}function D(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.remove("df-open"),t.setAttribute("aria-expanded","false"));}function O(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),p=false;}
33
38
  exports.close=D;exports.destroy=O;exports.init=I;exports.open=S;//# sourceMappingURL=index.js.map
34
39
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","close","destroy","_c"],"mappings":"aAiBA,IAAMA,CAAAA,CAAe,yBACfC,CAAAA,CAAe,0DAAA,CACfC,EAAW,mBAAA,CAGjB,SAASC,GAA0B,CAtBnC,IAAAC,EAAAC,CAAAA,CAuBE,GAAI,CACF,IAAIC,CAAAA,CAAK,aAAa,OAAA,CAAQJ,CAAQ,CAAA,CACtC,OAAKI,CAAAA,GACHA,CAAAA,CAAAA,CAAKD,GAAAD,CAAAA,CAAA,MAAA,EAAA,IAAA,CAAA,KAAA,CAAA,CAAA,MAAA,CAAQ,aAAR,IAAA,CAAA,KAAA,CAAA,CAAAA,CAAAA,CAAA,oBAAAC,CAAAA,CACA,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAI,IAAA,CAAK,KAAI,CAAE,QAAA,CAAS,EAAE,CAAA,CACjE,YAAA,CAAa,OAAA,CAAQH,EAAUI,CAAE,CAAA,CAAA,CAE5BA,CACT,CAAA,MAAQC,CAAAA,CAAA,CAEN,OAAO,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAI,IAAA,CAAK,KAAI,CAAE,QAAA,CAAS,EAAE,CACrE,CACF,CAGA,SAASC,CAAAA,CAAaC,CAAAA,CAA2E,CAC/F,GAAI,QAAA,CAAS,eAAe,gBAAgB,CAAA,CAAG,OAE/C,IAAMC,CAAAA,CAAUD,EAAS,UAAA,CAAW,KAAK,EAEnCE,CAAAA,CADUF,CAAAA,CAAS,SAAS,MAAM,CAAA,CACd,WAAA,CAAgB,YAAA,CAWpCG,CAAAA,CAAM;AAAA;AAAA,uBAAA,EAVIF,CAAAA,CAAU,UAAA,CAAgB,aAYf,CAAA,EAAA,EAAKC,CAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAAA,EANdD,CAAAA,CAAQ,8BAAgC,8BAcb,CAAA;AAAA;AAAA,uBAAA,EAlBlCA,CAAAA,CAAU,UAAA,CAAgB,aAoBb,CAAA,EAAA,EAAKC,CAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAA,EAlBtBD,CAAAA,CAAS,+BAAiC,6BAuBlC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+CAAA,EAnBDA,CAAAA,CAAQ,oBAAsB,kBA4BO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA,CAMvDG,EAAM,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA,CAC1CA,EAAI,EAAA,CAAK,gBAAA,CACTA,CAAAA,CAAI,WAAA,CAAcD,EAClB,QAAA,CAAS,IAAA,CAAK,WAAA,CAAYC,CAAG,EAC/B,CAGA,IAAMC,CAAAA,CAAY,kOAAA,CAGdC,EAAe,KAAA,CAUZ,SAASC,CAAAA,CAAKC,CAAAA,CAA4C,CAE/D,IAAMC,CAAAA,CACJ,OAAOD,CAAAA,EAAY,SAAW,CAAE,QAAA,CAAUA,CAAQ,CAAA,CAAIA,CAAAA,CAExD,GAAIF,CAAAA,CAAc,CAChB,OAAA,CAAQ,IAAA,CAAK,0DAA0D,CAAA,CACvE,MACF,CAEA,GAAM,CACJ,QAAA,CAAAI,CAAAA,CACA,QAAA,CAAAV,CAAAA,CAAW,eACX,WAAA,CAAAW,CAAAA,CAAc,KAAA,CACd,OAAA,CAAAC,EAAUrB,CAAAA,CACV,OAAA,CAAAsB,CAAAA,CAAUrB,CACZ,EAAIiB,CAAAA,CAEJ,GAAI,CAACC,CAAAA,CAAU,MAAM,IAAI,KAAA,CAAM,qCAAqC,CAAA,CAAA,CAGrDI,GACb,QAAA,CAAS,UAAA,GAAe,UACpB,QAAA,CAAS,gBAAA,CAAiB,mBAAoBA,CAAAA,CAAI,CAAE,IAAA,CAAM,IAAK,CAAC,CAAA,CAChEA,CAAAA,EAAG,EAEH,IAAM,CACVf,CAAAA,CAAaC,CAAQ,CAAA,CAErB,IAAMe,EAAOrB,CAAAA,EAAgB,CACvBsB,CAAAA,CAAM,CAAA,EAAGJ,CAAO,CAAA,KAAA,EAAQF,CAAQ,CAAA,MAAA,EAASK,CAAI,GAG7CE,CAAAA,CAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,EAC9CA,CAAAA,CAAO,EAAA,CAAK,eAAA,CACZA,CAAAA,CAAO,MAAQ,cAAA,CACfA,CAAAA,CAAO,QAAU,MAAA,CACjBA,CAAAA,CAAO,IAAMD,CAAAA,CAGb,IAAME,CAAAA,CAAM,QAAA,CAAS,cAAc,QAAQ,CAAA,CAC3CA,CAAAA,CAAI,EAAA,CAAK,cACTA,CAAAA,CAAI,YAAA,CAAa,YAAA,CAAc,WAAW,EAC1CA,CAAAA,CAAI,YAAA,CAAa,gBAAiB,OAAO,CAAA,CAEzC,IAAMC,CAAAA,CAAM,QAAA,CAAS,aAAA,CAAc,KAAK,EACxCA,CAAAA,CAAI,GAAA,CAAMN,CAAAA,CACVM,CAAAA,CAAI,IAAM,EAAA,CACVA,CAAAA,CAAI,KAAA,CAAQ,EAAA,CACZA,EAAI,MAAA,CAAS,EAAA,CACbA,EAAI,KAAA,CAAM,OAAA,CAAU,oDAEpB,IAAMC,CAAAA,CAAY,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA,CAC/CA,CAAAA,CAAU,SAAA,CAAYf,CAAAA,CACtBe,EAAU,KAAA,CAAM,OAAA,CAAU,MAAA,CAE1BF,CAAAA,CAAI,OAAOC,CAAAA,CAAKC,CAAS,CAAA,CAGzB,IAAIC,EAAOV,CAAAA,CACLW,CAAAA,CAAa,IAAM,CACvBL,EAAO,SAAA,CAAU,MAAA,CAAO,SAAA,CAAWI,CAAI,EACvCF,CAAAA,CAAI,KAAA,CAAM,OAAA,CAAUE,CAAAA,CAAO,OAAS,OAAA,CACpCD,CAAAA,CAAU,MAAM,OAAA,CAAUC,CAAAA,CAAO,QAAU,MAAA,CAC3CH,CAAAA,CAAI,YAAA,CAAa,eAAA,CAAiB,OAAOG,CAAI,CAAC,EAChD,CAAA,CAEAH,EAAI,gBAAA,CAAiB,OAAA,CAAS,IAAM,CAClCG,EAAO,CAACA,CAAAA,CACRC,CAAAA,GACF,CAAC,CAAA,CAED,QAAA,CAAS,IAAA,CAAK,MAAA,CAAOL,EAAQC,CAAG,CAAA,CAChCI,CAAAA,EAAW,CACXhB,EAAe,KACjB,CAAC,EACH,CAKO,SAASe,CAAAA,EAAa,CAC3B,IAAMJ,CAAAA,CAAS,QAAA,CAAS,eAAe,eAAe,CAAA,CAChDC,CAAAA,CAAM,QAAA,CAAS,eAAe,aAAa,CAAA,CAC7C,CAACD,CAAAA,EAAU,CAACC,CAAAA,GAChBD,CAAAA,CAAO,SAAA,CAAU,GAAA,CAAI,SAAS,CAAA,CAC9BC,CAAAA,CAAI,YAAA,CAAa,eAAA,CAAiB,MAAM,CAAA,EAC1C,CAKO,SAASK,CAAAA,EAAc,CAC5B,IAAMN,CAAAA,CAAS,QAAA,CAAS,cAAA,CAAe,eAAe,CAAA,CAChDC,CAAAA,CAAM,QAAA,CAAS,cAAA,CAAe,aAAa,CAAA,CAC7C,CAACD,GAAU,CAACC,CAAAA,GAChBD,EAAO,SAAA,CAAU,MAAA,CAAO,SAAS,CAAA,CACjCC,EAAI,YAAA,CAAa,eAAA,CAAiB,OAAO,CAAA,EAC3C,CAKO,SAASM,CAAAA,EAAgB,CAjNhC,IAAA7B,EAAAC,CAAAA,CAAA6B,CAAAA,CAAAA,CAkNE9B,EAAA,QAAA,CAAS,cAAA,CAAe,eAAe,CAAA,GAAvC,IAAA,EAAAA,CAAAA,CAA0C,MAAA,EAAA,CAAA,CAC1CC,EAAA,QAAA,CAAS,cAAA,CAAe,aAAa,CAAA,GAArC,MAAAA,CAAAA,CAAwC,MAAA,EAAA,CAAA,CACxC6B,CAAAA,CAAA,QAAA,CAAS,eAAe,gBAAgB,CAAA,GAAxC,MAAAA,CAAAA,CAA2C,MAAA,EAAA,CAC3CnB,EAAe,MACjB","file":"index.js","sourcesContent":["/** Options accepted by DunefoxChat.init() */\nexport interface DunefoxChatOptions {\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\n tenantId: string;\n /**\n * Where to anchor the widget. Defaults to \"bottom-right\".\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\n */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Open the chat panel on load. Defaults to false. */\n defaultOpen?: boolean;\n /** Override the base URL (for self-hosted / staging). */\n baseUrl?: string;\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\n iconUrl?: string;\n}\n\nconst DEFAULT_BASE = 'https://app.dunefox.io';\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\nconst UUID_KEY = 'dunefox_chat_uuid';\n\n// ─── UUID generation ──────────────────────────────────────────────────────────\nfunction getOrCreateUUID(): string {\n try {\n let id = localStorage.getItem(UUID_KEY);\n if (!id) {\n id = crypto?.randomUUID?.()\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\n localStorage.setItem(UUID_KEY, id);\n }\n return id;\n } catch {\n // Incognito / storage blocked — generate ephemeral ID\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n }\n}\n\n// ─── CSS injector ─────────────────────────────────────────────────────────────\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\n if (document.getElementById('dunefox-styles')) return;\n\n const isTop = position.startsWith('top');\n const isLeft = position.endsWith('left');\n const hSide = isLeft ? 'left:16px' : 'right:16px';\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\n // Panel opens away from the button edge\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\n // Slide direction: panels below slide up, panels above slide down\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\n // Hover nudge direction\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\n // Mobile slide direction\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\n\n const css = `\n #dunefox-btn {\n position: fixed; ${vBtn}; ${hSide};\n width: 60px; height: 60px; border-radius: 50%;\n background: #1a1a1a; border: none; cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n z-index: 2147483646;\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\n transition: transform .25s ease;\n }\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\n #dunefox-frame {\n position: fixed; ${vFrame}; ${hSide};\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\n border-radius: 16px; border: none; z-index: 2147483645;\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\n opacity: 0; visibility: hidden;\n transform: ${slideOut};\n transition: all .4s cubic-bezier(.4,0,.2,1);\n }\n #dunefox-frame.df-open {\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\n }\n @media (max-width: 768px) {\n #dunefox-frame {\n width: 100vw; height: 100vh; max-height: none;\n inset: 0; border-radius: 0; transform: ${mobileSlideOut};\n bottom: unset; right: unset; left: unset; top: unset;\n }\n #dunefox-frame.df-open { transform: translateY(0); }\n }\n `;\n const tag = document.createElement('style');\n tag.id = 'dunefox-styles';\n tag.textContent = css;\n document.head.appendChild(tag);\n}\n\n// ─── SVG icons ────────────────────────────────────────────────────────────────\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\n\n// ─── Main init ────────────────────────────────────────────────────────────────\nlet _initialised = false;\n\n/**\n * Initialise the Dunefox chatbot widget.\n * Call once on DOMContentLoaded or after your framework has mounted.\n *\n * @example\n * import { init } from 'dunefox-chatbot';\n * init({ tenantId: 'YOUR_TENANT_ID' });\n */\nexport function init(options: DunefoxChatOptions | string): void {\n // Allow shorthand: init('tenantId')\n const opts: DunefoxChatOptions =\n typeof options === 'string' ? { tenantId: options } : options;\n\n if (_initialised) {\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\n return;\n }\n\n const {\n tenantId,\n position = 'bottom-right',\n defaultOpen = false,\n baseUrl = DEFAULT_BASE,\n iconUrl = DEFAULT_ICON,\n } = opts;\n\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\n\n // Wait for DOM if we're running during <head> parse\n const ready = (cb: () => void) =>\n document.readyState === 'loading'\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\n : cb();\n\n ready(() => {\n injectStyles(position);\n\n const uuid = getOrCreateUUID();\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\n\n // ── iframe ──\n const iframe = document.createElement('iframe');\n iframe.id = 'dunefox-frame';\n iframe.title = 'Dunefox Chat';\n iframe.loading = 'lazy';\n iframe.src = src;\n\n // ── toggle button ──\n const btn = document.createElement('button');\n btn.id = 'dunefox-btn';\n btn.setAttribute('aria-label', 'Open chat');\n btn.setAttribute('aria-expanded', 'false');\n\n const img = document.createElement('img');\n img.src = iconUrl;\n img.alt = '';\n img.width = 60;\n img.height = 60;\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\n\n const closeSpan = document.createElement('span');\n closeSpan.innerHTML = CLOSE_SVG;\n closeSpan.style.display = 'none';\n\n btn.append(img, closeSpan);\n\n // ── state ──\n let open = defaultOpen;\n const applyState = () => {\n iframe.classList.toggle('df-open', open);\n img.style.display = open ? 'none' : 'block';\n closeSpan.style.display = open ? 'block' : 'none';\n btn.setAttribute('aria-expanded', String(open));\n };\n\n btn.addEventListener('click', () => {\n open = !open;\n applyState();\n });\n\n document.body.append(iframe, btn);\n applyState();\n _initialised = true;\n });\n}\n\n/**\n * Programmatically open the chat panel.\n */\nexport function open(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.add('df-open');\n btn.setAttribute('aria-expanded', 'true');\n}\n\n/**\n * Programmatically close the chat panel.\n */\nexport function close(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.remove('df-open');\n btn.setAttribute('aria-expanded', 'false');\n}\n\n/**\n * Remove the widget entirely.\n */\nexport function destroy(): void {\n document.getElementById('dunefox-frame')?.remove();\n document.getElementById('dunefox-btn')?.remove();\n document.getElementById('dunefox-styles')?.remove();\n _initialised = false;\n}\n"]}
1
+ {"version":3,"sources":["../src/core.ts"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","close","destroy","_c"],"mappings":"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","file":"index.js","sourcesContent":["/** Options accepted by DunefoxChat.init() */\r\nexport interface DunefoxChatOptions {\r\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\r\n tenantId: string;\r\n /**\r\n * Where to anchor the widget. Defaults to \"bottom-right\".\r\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\r\n */\r\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\r\n /** Open the chat panel on load. Defaults to false. */\r\n defaultOpen?: boolean;\r\n /** Override the base URL (for self-hosted / staging). */\r\n baseUrl?: string;\r\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\r\n iconUrl?: string;\r\n}\r\n\r\nconst DEFAULT_BASE = 'https://app.dunefox.io';\r\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\r\nconst UUID_KEY = 'dunefox_chat_uuid';\r\n\r\n// ─── UUID generation ──────────────────────────────────────────────────────────\r\nfunction getOrCreateUUID(): string {\r\n try {\r\n let id = localStorage.getItem(UUID_KEY);\r\n if (!id) {\r\n id = crypto?.randomUUID?.()\r\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n localStorage.setItem(UUID_KEY, id);\r\n }\r\n return id;\r\n } catch {\r\n // Incognito / storage blocked — generate ephemeral ID\r\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n }\r\n}\r\n\r\n// ─── CSS injector ─────────────────────────────────────────────────────────────\r\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\r\n if (document.getElementById('dunefox-styles')) return;\r\n\r\n const isTop = position.startsWith('top');\r\n const isLeft = position.endsWith('left');\r\n const hSide = isLeft ? 'left:16px' : 'right:16px';\r\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\r\n // Panel opens away from the button edge\r\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\r\n // Slide direction: panels below slide up, panels above slide down\r\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\r\n // Hover nudge direction\r\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\r\n // Mobile slide direction\r\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\r\n\r\n const css = `\r\n #dunefox-btn {\r\n position: fixed; ${vBtn}; ${hSide};\r\n width: 60px; height: 60px; border-radius: 50%;\r\n background: #1a1a1a; border: none; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center;\r\n z-index: 2147483646;\r\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\r\n transition: transform .25s ease;\r\n }\r\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\r\n #dunefox-frame {\r\n position: fixed; ${vFrame}; ${hSide};\r\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\r\n border-radius: 16px; border: none; z-index: 2147483645;\r\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\r\n opacity: 0; visibility: hidden;\r\n transform: ${slideOut};\r\n transition: all .4s cubic-bezier(.4,0,.2,1);\r\n }\r\n #dunefox-frame.df-open {\r\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\r\n }\r\n @media (max-width: 768px) {\r\n #dunefox-btn {\r\n bottom: unset !important; top: 16px !important;\r\n right: 16px !important; left: unset !important;\r\n }\r\n #dunefox-frame {\r\n width: 100% !important; height: 100% !important; max-height: none !important;\r\n position: fixed !important; inset: 0 !important;\r\n border-radius: 0 !important;\r\n transform: ${mobileSlideOut} !important;\r\n }\r\n #dunefox-frame.df-open { transform: translateY(0) !important; }\r\n }\r\n `;\r\n const tag = document.createElement('style');\r\n tag.id = 'dunefox-styles';\r\n tag.textContent = css;\r\n document.head.appendChild(tag);\r\n}\r\n\r\n// ─── SVG icons ────────────────────────────────────────────────────────────────\r\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\r\n\r\n// ─── Main init ────────────────────────────────────────────────────────────────\r\nlet _initialised = false;\r\n\r\n/**\r\n * Initialise the Dunefox chatbot widget.\r\n * Call once on DOMContentLoaded or after your framework has mounted.\r\n *\r\n * @example\r\n * import { init } from 'dunefox-chatbot';\r\n * init({ tenantId: 'YOUR_TENANT_ID' });\r\n */\r\nexport function init(options: DunefoxChatOptions | string): void {\r\n // Allow shorthand: init('tenantId')\r\n const opts: DunefoxChatOptions =\r\n typeof options === 'string' ? { tenantId: options } : options;\r\n\r\n if (_initialised) {\r\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\r\n return;\r\n }\r\n\r\n const {\r\n tenantId,\r\n position = 'bottom-right',\r\n defaultOpen = false,\r\n baseUrl = DEFAULT_BASE,\r\n iconUrl = DEFAULT_ICON,\r\n } = opts;\r\n\r\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\r\n\r\n // Wait for DOM if we're running during <head> parse\r\n const ready = (cb: () => void) =>\r\n document.readyState === 'loading'\r\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\r\n : cb();\r\n\r\n ready(() => {\r\n injectStyles(position);\r\n\r\n const uuid = getOrCreateUUID();\r\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\r\n\r\n // ── iframe ──\r\n const iframe = document.createElement('iframe');\r\n iframe.id = 'dunefox-frame';\r\n iframe.title = 'Dunefox Chat';\r\n iframe.loading = 'lazy';\r\n iframe.src = src;\r\n\r\n // ── toggle button ──\r\n const btn = document.createElement('button');\r\n btn.id = 'dunefox-btn';\r\n btn.setAttribute('aria-label', 'Open chat');\r\n btn.setAttribute('aria-expanded', 'false');\r\n\r\n const img = document.createElement('img');\r\n img.src = iconUrl;\r\n img.alt = '';\r\n img.width = 60;\r\n img.height = 60;\r\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\r\n\r\n const closeSpan = document.createElement('span');\r\n closeSpan.innerHTML = CLOSE_SVG;\r\n closeSpan.style.display = 'none';\r\n\r\n btn.append(img, closeSpan);\r\n\r\n // ── state ──\r\n let open = defaultOpen;\r\n const applyState = () => {\r\n iframe.classList.toggle('df-open', open);\r\n img.style.display = open ? 'none' : 'block';\r\n closeSpan.style.display = open ? 'block' : 'none';\r\n btn.setAttribute('aria-expanded', String(open));\r\n };\r\n\r\n btn.addEventListener('click', () => {\r\n open = !open;\r\n applyState();\r\n });\r\n\r\n document.body.append(iframe, btn);\r\n applyState();\r\n _initialised = true;\r\n });\r\n}\r\n\r\n/**\r\n * Programmatically open the chat panel.\r\n */\r\nexport function open(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.add('df-open');\r\n btn.setAttribute('aria-expanded', 'true');\r\n}\r\n\r\n/**\r\n * Programmatically close the chat panel.\r\n */\r\nexport function close(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.remove('df-open');\r\n btn.setAttribute('aria-expanded', 'false');\r\n}\r\n\r\n/**\r\n * Remove the widget entirely.\r\n */\r\nexport function destroy(): void {\r\n document.getElementById('dunefox-frame')?.remove();\r\n document.getElementById('dunefox-btn')?.remove();\r\n document.getElementById('dunefox-styles')?.remove();\r\n _initialised = false;\r\n}\r\n"]}
package/dist/index.mjs CHANGED
@@ -22,13 +22,18 @@ var b="https://app.dunefox.io",y="https://dunefoxx.s3.ap-south-1.amazonaws.com/c
22
22
  opacity: 1; visibility: visible; transform: translateY(0) scale(1);
23
23
  }
24
24
  @media (max-width: 768px) {
25
+ #dunefox-btn {
26
+ bottom: unset !important; top: 16px !important;
27
+ right: 16px !important; left: unset !important;
28
+ }
25
29
  #dunefox-frame {
26
- width: 100vw; height: 100vh; max-height: none;
27
- inset: 0; border-radius: 0; transform: ${t?"translateY(-100%)":"translateY(100%)"};
28
- bottom: unset; right: unset; left: unset; top: unset;
30
+ width: 100% !important; height: 100% !important; max-height: none !important;
31
+ position: fixed !important; inset: 0 !important;
32
+ border-radius: 0 !important;
33
+ transform: ${t?"translateY(-100%)":"translateY(100%)"} !important;
29
34
  }
30
- #dunefox-frame.df-open { transform: translateY(0); }
35
+ #dunefox-frame.df-open { transform: translateY(0) !important; }
31
36
  }
32
- `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var w='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',u=false;function I(e){let t=typeof e=="string"?{tenantId:e}:e;if(u){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:p=false,baseUrl:f=b,iconUrl:m=y}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{E(d);let s=v(),c=`${f}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let a=document.createElement("button");a.id="dunefox-btn",a.setAttribute("aria-label","Open chat"),a.setAttribute("aria-expanded","false");let r=document.createElement("img");r.src=m,r.alt="",r.width=60,r.height=60,r.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=w,l.style.display="none",a.append(r,l);let i=p,x=()=>{o.classList.toggle("df-open",i),r.style.display=i?"none":"block",l.style.display=i?"block":"none",a.setAttribute("aria-expanded",String(i));};a.addEventListener("click",()=>{i=!i,x();}),document.body.append(o,a),x(),u=true;});}function S(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.add("df-open"),t.setAttribute("aria-expanded","true"));}function D(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.remove("df-open"),t.setAttribute("aria-expanded","false"));}function O(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),u=false;}
37
+ `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var w='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',p=false;function I(e){let t=typeof e=="string"?{tenantId:e}:e;if(p){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:m=false,baseUrl:u=b,iconUrl:f=y}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{E(d);let s=v(),c=`${u}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let a=document.createElement("button");a.id="dunefox-btn",a.setAttribute("aria-label","Open chat"),a.setAttribute("aria-expanded","false");let i=document.createElement("img");i.src=f,i.alt="",i.width=60,i.height=60,i.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=w,l.style.display="none",a.append(i,l);let r=m,x=()=>{o.classList.toggle("df-open",r),i.style.display=r?"none":"block",l.style.display=r?"block":"none",a.setAttribute("aria-expanded",String(r));};a.addEventListener("click",()=>{r=!r,x();}),document.body.append(o,a),x(),p=true;});}function S(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.add("df-open"),t.setAttribute("aria-expanded","true"));}function D(){let e=document.getElementById("dunefox-frame"),t=document.getElementById("dunefox-btn");!e||!t||(e.classList.remove("df-open"),t.setAttribute("aria-expanded","false"));}function O(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),p=false;}
33
38
  export{D as close,O as destroy,I as init,S as open};//# sourceMappingURL=index.mjs.map
34
39
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","close","destroy","_c"],"mappings":"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","file":"index.mjs","sourcesContent":["/** Options accepted by DunefoxChat.init() */\nexport interface DunefoxChatOptions {\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\n tenantId: string;\n /**\n * Where to anchor the widget. Defaults to \"bottom-right\".\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\n */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Open the chat panel on load. Defaults to false. */\n defaultOpen?: boolean;\n /** Override the base URL (for self-hosted / staging). */\n baseUrl?: string;\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\n iconUrl?: string;\n}\n\nconst DEFAULT_BASE = 'https://app.dunefox.io';\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\nconst UUID_KEY = 'dunefox_chat_uuid';\n\n// ─── UUID generation ──────────────────────────────────────────────────────────\nfunction getOrCreateUUID(): string {\n try {\n let id = localStorage.getItem(UUID_KEY);\n if (!id) {\n id = crypto?.randomUUID?.()\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\n localStorage.setItem(UUID_KEY, id);\n }\n return id;\n } catch {\n // Incognito / storage blocked — generate ephemeral ID\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n }\n}\n\n// ─── CSS injector ─────────────────────────────────────────────────────────────\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\n if (document.getElementById('dunefox-styles')) return;\n\n const isTop = position.startsWith('top');\n const isLeft = position.endsWith('left');\n const hSide = isLeft ? 'left:16px' : 'right:16px';\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\n // Panel opens away from the button edge\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\n // Slide direction: panels below slide up, panels above slide down\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\n // Hover nudge direction\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\n // Mobile slide direction\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\n\n const css = `\n #dunefox-btn {\n position: fixed; ${vBtn}; ${hSide};\n width: 60px; height: 60px; border-radius: 50%;\n background: #1a1a1a; border: none; cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n z-index: 2147483646;\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\n transition: transform .25s ease;\n }\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\n #dunefox-frame {\n position: fixed; ${vFrame}; ${hSide};\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\n border-radius: 16px; border: none; z-index: 2147483645;\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\n opacity: 0; visibility: hidden;\n transform: ${slideOut};\n transition: all .4s cubic-bezier(.4,0,.2,1);\n }\n #dunefox-frame.df-open {\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\n }\n @media (max-width: 768px) {\n #dunefox-frame {\n width: 100vw; height: 100vh; max-height: none;\n inset: 0; border-radius: 0; transform: ${mobileSlideOut};\n bottom: unset; right: unset; left: unset; top: unset;\n }\n #dunefox-frame.df-open { transform: translateY(0); }\n }\n `;\n const tag = document.createElement('style');\n tag.id = 'dunefox-styles';\n tag.textContent = css;\n document.head.appendChild(tag);\n}\n\n// ─── SVG icons ────────────────────────────────────────────────────────────────\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\n\n// ─── Main init ────────────────────────────────────────────────────────────────\nlet _initialised = false;\n\n/**\n * Initialise the Dunefox chatbot widget.\n * Call once on DOMContentLoaded or after your framework has mounted.\n *\n * @example\n * import { init } from 'dunefox-chatbot';\n * init({ tenantId: 'YOUR_TENANT_ID' });\n */\nexport function init(options: DunefoxChatOptions | string): void {\n // Allow shorthand: init('tenantId')\n const opts: DunefoxChatOptions =\n typeof options === 'string' ? { tenantId: options } : options;\n\n if (_initialised) {\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\n return;\n }\n\n const {\n tenantId,\n position = 'bottom-right',\n defaultOpen = false,\n baseUrl = DEFAULT_BASE,\n iconUrl = DEFAULT_ICON,\n } = opts;\n\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\n\n // Wait for DOM if we're running during <head> parse\n const ready = (cb: () => void) =>\n document.readyState === 'loading'\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\n : cb();\n\n ready(() => {\n injectStyles(position);\n\n const uuid = getOrCreateUUID();\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\n\n // ── iframe ──\n const iframe = document.createElement('iframe');\n iframe.id = 'dunefox-frame';\n iframe.title = 'Dunefox Chat';\n iframe.loading = 'lazy';\n iframe.src = src;\n\n // ── toggle button ──\n const btn = document.createElement('button');\n btn.id = 'dunefox-btn';\n btn.setAttribute('aria-label', 'Open chat');\n btn.setAttribute('aria-expanded', 'false');\n\n const img = document.createElement('img');\n img.src = iconUrl;\n img.alt = '';\n img.width = 60;\n img.height = 60;\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\n\n const closeSpan = document.createElement('span');\n closeSpan.innerHTML = CLOSE_SVG;\n closeSpan.style.display = 'none';\n\n btn.append(img, closeSpan);\n\n // ── state ──\n let open = defaultOpen;\n const applyState = () => {\n iframe.classList.toggle('df-open', open);\n img.style.display = open ? 'none' : 'block';\n closeSpan.style.display = open ? 'block' : 'none';\n btn.setAttribute('aria-expanded', String(open));\n };\n\n btn.addEventListener('click', () => {\n open = !open;\n applyState();\n });\n\n document.body.append(iframe, btn);\n applyState();\n _initialised = true;\n });\n}\n\n/**\n * Programmatically open the chat panel.\n */\nexport function open(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.add('df-open');\n btn.setAttribute('aria-expanded', 'true');\n}\n\n/**\n * Programmatically close the chat panel.\n */\nexport function close(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.remove('df-open');\n btn.setAttribute('aria-expanded', 'false');\n}\n\n/**\n * Remove the widget entirely.\n */\nexport function destroy(): void {\n document.getElementById('dunefox-frame')?.remove();\n document.getElementById('dunefox-btn')?.remove();\n document.getElementById('dunefox-styles')?.remove();\n _initialised = false;\n}\n"]}
1
+ {"version":3,"sources":["../src/core.ts"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","close","destroy","_c"],"mappings":"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","file":"index.mjs","sourcesContent":["/** Options accepted by DunefoxChat.init() */\r\nexport interface DunefoxChatOptions {\r\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\r\n tenantId: string;\r\n /**\r\n * Where to anchor the widget. Defaults to \"bottom-right\".\r\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\r\n */\r\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\r\n /** Open the chat panel on load. Defaults to false. */\r\n defaultOpen?: boolean;\r\n /** Override the base URL (for self-hosted / staging). */\r\n baseUrl?: string;\r\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\r\n iconUrl?: string;\r\n}\r\n\r\nconst DEFAULT_BASE = 'https://app.dunefox.io';\r\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\r\nconst UUID_KEY = 'dunefox_chat_uuid';\r\n\r\n// ─── UUID generation ──────────────────────────────────────────────────────────\r\nfunction getOrCreateUUID(): string {\r\n try {\r\n let id = localStorage.getItem(UUID_KEY);\r\n if (!id) {\r\n id = crypto?.randomUUID?.()\r\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n localStorage.setItem(UUID_KEY, id);\r\n }\r\n return id;\r\n } catch {\r\n // Incognito / storage blocked — generate ephemeral ID\r\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n }\r\n}\r\n\r\n// ─── CSS injector ─────────────────────────────────────────────────────────────\r\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\r\n if (document.getElementById('dunefox-styles')) return;\r\n\r\n const isTop = position.startsWith('top');\r\n const isLeft = position.endsWith('left');\r\n const hSide = isLeft ? 'left:16px' : 'right:16px';\r\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\r\n // Panel opens away from the button edge\r\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\r\n // Slide direction: panels below slide up, panels above slide down\r\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\r\n // Hover nudge direction\r\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\r\n // Mobile slide direction\r\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\r\n\r\n const css = `\r\n #dunefox-btn {\r\n position: fixed; ${vBtn}; ${hSide};\r\n width: 60px; height: 60px; border-radius: 50%;\r\n background: #1a1a1a; border: none; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center;\r\n z-index: 2147483646;\r\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\r\n transition: transform .25s ease;\r\n }\r\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\r\n #dunefox-frame {\r\n position: fixed; ${vFrame}; ${hSide};\r\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\r\n border-radius: 16px; border: none; z-index: 2147483645;\r\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\r\n opacity: 0; visibility: hidden;\r\n transform: ${slideOut};\r\n transition: all .4s cubic-bezier(.4,0,.2,1);\r\n }\r\n #dunefox-frame.df-open {\r\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\r\n }\r\n @media (max-width: 768px) {\r\n #dunefox-btn {\r\n bottom: unset !important; top: 16px !important;\r\n right: 16px !important; left: unset !important;\r\n }\r\n #dunefox-frame {\r\n width: 100% !important; height: 100% !important; max-height: none !important;\r\n position: fixed !important; inset: 0 !important;\r\n border-radius: 0 !important;\r\n transform: ${mobileSlideOut} !important;\r\n }\r\n #dunefox-frame.df-open { transform: translateY(0) !important; }\r\n }\r\n `;\r\n const tag = document.createElement('style');\r\n tag.id = 'dunefox-styles';\r\n tag.textContent = css;\r\n document.head.appendChild(tag);\r\n}\r\n\r\n// ─── SVG icons ────────────────────────────────────────────────────────────────\r\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\r\n\r\n// ─── Main init ────────────────────────────────────────────────────────────────\r\nlet _initialised = false;\r\n\r\n/**\r\n * Initialise the Dunefox chatbot widget.\r\n * Call once on DOMContentLoaded or after your framework has mounted.\r\n *\r\n * @example\r\n * import { init } from 'dunefox-chatbot';\r\n * init({ tenantId: 'YOUR_TENANT_ID' });\r\n */\r\nexport function init(options: DunefoxChatOptions | string): void {\r\n // Allow shorthand: init('tenantId')\r\n const opts: DunefoxChatOptions =\r\n typeof options === 'string' ? { tenantId: options } : options;\r\n\r\n if (_initialised) {\r\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\r\n return;\r\n }\r\n\r\n const {\r\n tenantId,\r\n position = 'bottom-right',\r\n defaultOpen = false,\r\n baseUrl = DEFAULT_BASE,\r\n iconUrl = DEFAULT_ICON,\r\n } = opts;\r\n\r\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\r\n\r\n // Wait for DOM if we're running during <head> parse\r\n const ready = (cb: () => void) =>\r\n document.readyState === 'loading'\r\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\r\n : cb();\r\n\r\n ready(() => {\r\n injectStyles(position);\r\n\r\n const uuid = getOrCreateUUID();\r\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\r\n\r\n // ── iframe ──\r\n const iframe = document.createElement('iframe');\r\n iframe.id = 'dunefox-frame';\r\n iframe.title = 'Dunefox Chat';\r\n iframe.loading = 'lazy';\r\n iframe.src = src;\r\n\r\n // ── toggle button ──\r\n const btn = document.createElement('button');\r\n btn.id = 'dunefox-btn';\r\n btn.setAttribute('aria-label', 'Open chat');\r\n btn.setAttribute('aria-expanded', 'false');\r\n\r\n const img = document.createElement('img');\r\n img.src = iconUrl;\r\n img.alt = '';\r\n img.width = 60;\r\n img.height = 60;\r\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\r\n\r\n const closeSpan = document.createElement('span');\r\n closeSpan.innerHTML = CLOSE_SVG;\r\n closeSpan.style.display = 'none';\r\n\r\n btn.append(img, closeSpan);\r\n\r\n // ── state ──\r\n let open = defaultOpen;\r\n const applyState = () => {\r\n iframe.classList.toggle('df-open', open);\r\n img.style.display = open ? 'none' : 'block';\r\n closeSpan.style.display = open ? 'block' : 'none';\r\n btn.setAttribute('aria-expanded', String(open));\r\n };\r\n\r\n btn.addEventListener('click', () => {\r\n open = !open;\r\n applyState();\r\n });\r\n\r\n document.body.append(iframe, btn);\r\n applyState();\r\n _initialised = true;\r\n });\r\n}\r\n\r\n/**\r\n * Programmatically open the chat panel.\r\n */\r\nexport function open(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.add('df-open');\r\n btn.setAttribute('aria-expanded', 'true');\r\n}\r\n\r\n/**\r\n * Programmatically close the chat panel.\r\n */\r\nexport function close(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.remove('df-open');\r\n btn.setAttribute('aria-expanded', 'false');\r\n}\r\n\r\n/**\r\n * Remove the widget entirely.\r\n */\r\nexport function destroy(): void {\r\n document.getElementById('dunefox-frame')?.remove();\r\n document.getElementById('dunefox-btn')?.remove();\r\n document.getElementById('dunefox-styles')?.remove();\r\n _initialised = false;\r\n}\r\n"]}
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var react=require('react');var v="https://app.dunefox.io",w="https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png",h="dunefox_chat_uuid";function E(){var e,t;try{let n=localStorage.getItem(h);return n||(n=(t=(e=crypto==null?void 0:crypto.randomUUID)==null?void 0:e.call(crypto))!=null?t:Math.random().toString(36).slice(2)+Date.now().toString(36),localStorage.setItem(h,n)),n}catch(n){return Math.random().toString(36).slice(2)+Date.now().toString(36)}}function I(e){if(document.getElementById("dunefox-styles"))return;let t=e.startsWith("top"),d=e.endsWith("left")?"left:16px":"right:16px",c=`
1
+ 'use strict';var react=require('react');var v="https://app.dunefox.io",E="https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png",h="dunefox_chat_uuid";function w(){var e,t;try{let n=localStorage.getItem(h);return n||(n=(t=(e=crypto==null?void 0:crypto.randomUUID)==null?void 0:e.call(crypto))!=null?t:Math.random().toString(36).slice(2)+Date.now().toString(36),localStorage.setItem(h,n)),n}catch(n){return Math.random().toString(36).slice(2)+Date.now().toString(36)}}function I(e){if(document.getElementById("dunefox-styles"))return;let t=e.startsWith("top"),d=e.endsWith("left")?"left:16px":"right:16px",c=`
2
2
  #dunefox-btn {
3
3
  position: fixed; ${t?"top:16px":"bottom:16px"}; ${d};
4
4
  width: 60px; height: 60px; border-radius: 50%;
@@ -22,13 +22,18 @@
22
22
  opacity: 1; visibility: visible; transform: translateY(0) scale(1);
23
23
  }
24
24
  @media (max-width: 768px) {
25
+ #dunefox-btn {
26
+ bottom: unset !important; top: 16px !important;
27
+ right: 16px !important; left: unset !important;
28
+ }
25
29
  #dunefox-frame {
26
- width: 100vw; height: 100vh; max-height: none;
27
- inset: 0; border-radius: 0; transform: ${t?"translateY(-100%)":"translateY(100%)"};
28
- bottom: unset; right: unset; left: unset; top: unset;
30
+ width: 100% !important; height: 100% !important; max-height: none !important;
31
+ position: fixed !important; inset: 0 !important;
32
+ border-radius: 0 !important;
33
+ transform: ${t?"translateY(-100%)":"translateY(100%)"} !important;
29
34
  }
30
- #dunefox-frame.df-open { transform: translateY(0); }
35
+ #dunefox-frame.df-open { transform: translateY(0) !important; }
31
36
  }
32
- `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var D='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',u=false;function b(e){let t=typeof e=="string"?{tenantId:e}:e;if(u){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:f=false,baseUrl:p=v,iconUrl:m=w}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{I(d);let s=E(),c=`${p}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let r=document.createElement("button");r.id="dunefox-btn",r.setAttribute("aria-label","Open chat"),r.setAttribute("aria-expanded","false");let i=document.createElement("img");i.src=m,i.alt="",i.width=60,i.height=60,i.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=D,l.style.display="none",r.append(i,l);let a=f,x=()=>{o.classList.toggle("df-open",a),i.style.display=a?"none":"block",l.style.display=a?"block":"none",r.setAttribute("aria-expanded",String(a));};r.addEventListener("click",()=>{a=!a,x();}),document.body.append(o,r),x(),u=true;});}function g(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),u=false;}function U(e){let t=react.useRef(e);return react.useEffect(()=>{if(typeof window!="undefined")return b(t.current),()=>{g();}},[]),null}
37
+ `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var D='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',p=false;function b(e){let t=typeof e=="string"?{tenantId:e}:e;if(p){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:u=false,baseUrl:f=v,iconUrl:m=E}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{I(d);let s=w(),c=`${f}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let r=document.createElement("button");r.id="dunefox-btn",r.setAttribute("aria-label","Open chat"),r.setAttribute("aria-expanded","false");let i=document.createElement("img");i.src=m,i.alt="",i.width=60,i.height=60,i.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=D,l.style.display="none",r.append(i,l);let a=u,x=()=>{o.classList.toggle("df-open",a),i.style.display=a?"none":"block",l.style.display=a?"block":"none",r.setAttribute("aria-expanded",String(a));};r.addEventListener("click",()=>{a=!a,x();}),document.body.append(o,r),x(),p=true;});}function g(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),p=false;}function U(e){let t=react.useRef(e);return react.useEffect(()=>{if(typeof window!="undefined")return b(t.current),()=>{g();}},[]),null}
33
38
  exports.DunefoxChatbot=U;//# sourceMappingURL=react.js.map
34
39
  //# sourceMappingURL=react.js.map
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts","../src/react.tsx"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","destroy","_c","DunefoxChatbot","props","optsRef","useRef","useEffect"],"mappings":"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","file":"react.js","sourcesContent":["/** Options accepted by DunefoxChat.init() */\nexport interface DunefoxChatOptions {\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\n tenantId: string;\n /**\n * Where to anchor the widget. Defaults to \"bottom-right\".\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\n */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Open the chat panel on load. Defaults to false. */\n defaultOpen?: boolean;\n /** Override the base URL (for self-hosted / staging). */\n baseUrl?: string;\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\n iconUrl?: string;\n}\n\nconst DEFAULT_BASE = 'https://app.dunefox.io';\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\nconst UUID_KEY = 'dunefox_chat_uuid';\n\n// ─── UUID generation ──────────────────────────────────────────────────────────\nfunction getOrCreateUUID(): string {\n try {\n let id = localStorage.getItem(UUID_KEY);\n if (!id) {\n id = crypto?.randomUUID?.()\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\n localStorage.setItem(UUID_KEY, id);\n }\n return id;\n } catch {\n // Incognito / storage blocked — generate ephemeral ID\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n }\n}\n\n// ─── CSS injector ─────────────────────────────────────────────────────────────\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\n if (document.getElementById('dunefox-styles')) return;\n\n const isTop = position.startsWith('top');\n const isLeft = position.endsWith('left');\n const hSide = isLeft ? 'left:16px' : 'right:16px';\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\n // Panel opens away from the button edge\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\n // Slide direction: panels below slide up, panels above slide down\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\n // Hover nudge direction\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\n // Mobile slide direction\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\n\n const css = `\n #dunefox-btn {\n position: fixed; ${vBtn}; ${hSide};\n width: 60px; height: 60px; border-radius: 50%;\n background: #1a1a1a; border: none; cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n z-index: 2147483646;\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\n transition: transform .25s ease;\n }\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\n #dunefox-frame {\n position: fixed; ${vFrame}; ${hSide};\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\n border-radius: 16px; border: none; z-index: 2147483645;\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\n opacity: 0; visibility: hidden;\n transform: ${slideOut};\n transition: all .4s cubic-bezier(.4,0,.2,1);\n }\n #dunefox-frame.df-open {\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\n }\n @media (max-width: 768px) {\n #dunefox-frame {\n width: 100vw; height: 100vh; max-height: none;\n inset: 0; border-radius: 0; transform: ${mobileSlideOut};\n bottom: unset; right: unset; left: unset; top: unset;\n }\n #dunefox-frame.df-open { transform: translateY(0); }\n }\n `;\n const tag = document.createElement('style');\n tag.id = 'dunefox-styles';\n tag.textContent = css;\n document.head.appendChild(tag);\n}\n\n// ─── SVG icons ────────────────────────────────────────────────────────────────\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\n\n// ─── Main init ────────────────────────────────────────────────────────────────\nlet _initialised = false;\n\n/**\n * Initialise the Dunefox chatbot widget.\n * Call once on DOMContentLoaded or after your framework has mounted.\n *\n * @example\n * import { init } from 'dunefox-chatbot';\n * init({ tenantId: 'YOUR_TENANT_ID' });\n */\nexport function init(options: DunefoxChatOptions | string): void {\n // Allow shorthand: init('tenantId')\n const opts: DunefoxChatOptions =\n typeof options === 'string' ? { tenantId: options } : options;\n\n if (_initialised) {\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\n return;\n }\n\n const {\n tenantId,\n position = 'bottom-right',\n defaultOpen = false,\n baseUrl = DEFAULT_BASE,\n iconUrl = DEFAULT_ICON,\n } = opts;\n\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\n\n // Wait for DOM if we're running during <head> parse\n const ready = (cb: () => void) =>\n document.readyState === 'loading'\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\n : cb();\n\n ready(() => {\n injectStyles(position);\n\n const uuid = getOrCreateUUID();\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\n\n // ── iframe ──\n const iframe = document.createElement('iframe');\n iframe.id = 'dunefox-frame';\n iframe.title = 'Dunefox Chat';\n iframe.loading = 'lazy';\n iframe.src = src;\n\n // ── toggle button ──\n const btn = document.createElement('button');\n btn.id = 'dunefox-btn';\n btn.setAttribute('aria-label', 'Open chat');\n btn.setAttribute('aria-expanded', 'false');\n\n const img = document.createElement('img');\n img.src = iconUrl;\n img.alt = '';\n img.width = 60;\n img.height = 60;\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\n\n const closeSpan = document.createElement('span');\n closeSpan.innerHTML = CLOSE_SVG;\n closeSpan.style.display = 'none';\n\n btn.append(img, closeSpan);\n\n // ── state ──\n let open = defaultOpen;\n const applyState = () => {\n iframe.classList.toggle('df-open', open);\n img.style.display = open ? 'none' : 'block';\n closeSpan.style.display = open ? 'block' : 'none';\n btn.setAttribute('aria-expanded', String(open));\n };\n\n btn.addEventListener('click', () => {\n open = !open;\n applyState();\n });\n\n document.body.append(iframe, btn);\n applyState();\n _initialised = true;\n });\n}\n\n/**\n * Programmatically open the chat panel.\n */\nexport function open(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.add('df-open');\n btn.setAttribute('aria-expanded', 'true');\n}\n\n/**\n * Programmatically close the chat panel.\n */\nexport function close(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.remove('df-open');\n btn.setAttribute('aria-expanded', 'false');\n}\n\n/**\n * Remove the widget entirely.\n */\nexport function destroy(): void {\n document.getElementById('dunefox-frame')?.remove();\n document.getElementById('dunefox-btn')?.remove();\n document.getElementById('dunefox-styles')?.remove();\n _initialised = false;\n}\n","import { useEffect, useRef } from 'react';\nimport { init, destroy } from './core';\nimport type { DunefoxChatOptions } from './core';\n\nexport interface DunefoxChatbotProps extends DunefoxChatOptions {}\n\n/**\n * React component wrapper for the Dunefox Chatbot widget.\n *\n * Drop it anywhere in your component tree — typically at the root layout level.\n * SSR-safe: the widget is only mounted in the browser via useEffect.\n *\n * @example\n * // Next.js App Router (app/layout.tsx)\n * import { DunefoxChatbot } from 'dunefox-chatbot/react';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html><body>\n * {children}\n * <DunefoxChatbot tenantId=\"YOUR_TENANT_ID\" />\n * </body></html>\n * );\n * }\n */\nexport function DunefoxChatbot(props: DunefoxChatbotProps) {\n // Capture props at mount time — we intentionally don't re-init on prop changes\n const optsRef = useRef(props);\n\n useEffect(() => {\n // Prevent running during SSR (window check is a safety net)\n if (typeof window === 'undefined') return;\n\n init(optsRef.current);\n\n return () => {\n destroy();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // This component renders nothing to the React tree — the widget is DOM-injected\n return null;\n}\n"]}
1
+ {"version":3,"sources":["../src/core.ts","../src/react.tsx"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","destroy","_c","DunefoxChatbot","props","optsRef","useRef","useEffect"],"mappings":"wCAiBA,IAAMA,CAAAA,CAAe,wBAAA,CACfC,CAAAA,CAAe,0DAAA,CACfC,CAAAA,CAAW,oBAGjB,SAASC,CAAAA,EAA0B,CAtBnC,IAAAC,CAAAA,CAAAC,EAuBE,GAAI,CACF,IAAIC,CAAAA,CAAK,YAAA,CAAa,OAAA,CAAQJ,CAAQ,CAAA,CACtC,OAAKI,IACHA,CAAAA,CAAAA,CAAKD,CAAAA,CAAAA,CAAAD,EAAA,MAAA,EAAA,IAAA,CAAA,KAAA,CAAA,CAAA,MAAA,CAAQ,UAAA,GAAR,IAAA,CAAA,KAAA,CAAA,CAAAA,CAAAA,CAAA,IAAA,CAAA,MAAA,CAAA,GAAA,IAAA,CAAAC,CAAAA,CACA,KAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAI,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,EACjE,YAAA,CAAa,OAAA,CAAQH,EAAUI,CAAE,CAAA,CAAA,CAE5BA,CACT,CAAA,MAAQC,CAAAA,CAAA,CAEN,OAAO,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,KAAA,CAAM,CAAC,EAAI,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CACrE,CACF,CAGA,SAASC,EAAaC,CAAAA,CAA2E,CAC/F,GAAI,QAAA,CAAS,cAAA,CAAe,gBAAgB,CAAA,CAAG,OAE/C,IAAMC,EAAUD,CAAAA,CAAS,UAAA,CAAW,KAAK,CAAA,CAEnCE,CAAAA,CADUF,CAAAA,CAAS,SAAS,MAAM,CAAA,CACd,WAAA,CAAgB,YAAA,CAWpCG,CAAAA,CAAM;AAAA;AAAA,uBAAA,EAVIF,CAAAA,CAAU,UAAA,CAAgB,aAYf,CAAA,EAAA,EAAKC,CAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAAA,EANdD,CAAAA,CAAQ,8BAAgC,8BAcb,CAAA;AAAA;AAAA,uBAAA,EAlBlCA,CAAAA,CAAU,UAAA,CAAgB,aAoBb,CAAA,EAAA,EAAKC,CAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAA,EAlBtBD,CAAAA,CAAS,+BAAiC,6BAuBlC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAA,EAnBDA,CAAAA,CAAQ,oBAAsB,kBAkCrB,CAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA,CAK3BG,CAAAA,CAAM,QAAA,CAAS,aAAA,CAAc,OAAO,EAC1CA,CAAAA,CAAI,EAAA,CAAK,gBAAA,CACTA,CAAAA,CAAI,YAAcD,CAAAA,CAClB,QAAA,CAAS,IAAA,CAAK,WAAA,CAAYC,CAAG,EAC/B,CAGA,IAAMC,CAAAA,CAAY,kOAAA,CAGdC,CAAAA,CAAe,KAAA,CAUZ,SAASC,EAAKC,CAAAA,CAA4C,CAE/D,IAAMC,CAAAA,CACJ,OAAOD,CAAAA,EAAY,QAAA,CAAW,CAAE,QAAA,CAAUA,CAAQ,CAAA,CAAIA,CAAAA,CAExD,GAAIF,CAAAA,CAAc,CAChB,OAAA,CAAQ,IAAA,CAAK,0DAA0D,EACvE,MACF,CAEA,GAAM,CACJ,SAAAI,CAAAA,CACA,QAAA,CAAAV,CAAAA,CAAW,cAAA,CACX,YAAAW,CAAAA,CAAc,KAAA,CACd,OAAA,CAAAC,CAAAA,CAAUrB,CAAAA,CACV,OAAA,CAAAsB,CAAAA,CAAUrB,CACZ,EAAIiB,CAAAA,CAEJ,GAAI,CAACC,CAAAA,CAAU,MAAM,IAAI,KAAA,CAAM,qCAAqC,CAAA,CAAA,CAGrDI,GACb,QAAA,CAAS,UAAA,GAAe,SAAA,CACpB,QAAA,CAAS,gBAAA,CAAiB,kBAAA,CAAoBA,CAAAA,CAAI,CAAE,KAAM,IAAK,CAAC,CAAA,CAChEA,CAAAA,IAEA,IAAM,CACVf,CAAAA,CAAaC,CAAQ,EAErB,IAAMe,CAAAA,CAAOrB,CAAAA,EAAgB,CACvBsB,CAAAA,CAAM,CAAA,EAAGJ,CAAO,CAAA,KAAA,EAAQF,CAAQ,CAAA,MAAA,EAASK,CAAI,CAAA,CAAA,CAG7CE,CAAAA,CAAS,SAAS,aAAA,CAAc,QAAQ,CAAA,CAC9CA,CAAAA,CAAO,GAAK,eAAA,CACZA,CAAAA,CAAO,KAAA,CAAQ,cAAA,CACfA,CAAAA,CAAO,OAAA,CAAU,MAAA,CACjBA,CAAAA,CAAO,IAAMD,CAAAA,CAGb,IAAME,CAAAA,CAAM,QAAA,CAAS,cAAc,QAAQ,CAAA,CAC3CA,CAAAA,CAAI,EAAA,CAAK,cACTA,CAAAA,CAAI,YAAA,CAAa,YAAA,CAAc,WAAW,CAAA,CAC1CA,CAAAA,CAAI,YAAA,CAAa,eAAA,CAAiB,OAAO,CAAA,CAEzC,IAAMC,CAAAA,CAAM,QAAA,CAAS,cAAc,KAAK,CAAA,CACxCA,CAAAA,CAAI,GAAA,CAAMN,EACVM,CAAAA,CAAI,GAAA,CAAM,EAAA,CACVA,CAAAA,CAAI,KAAA,CAAQ,EAAA,CACZA,CAAAA,CAAI,MAAA,CAAS,GACbA,CAAAA,CAAI,KAAA,CAAM,OAAA,CAAU,mDAAA,CAEpB,IAAMC,CAAAA,CAAY,QAAA,CAAS,aAAA,CAAc,MAAM,EAC/CA,CAAAA,CAAU,SAAA,CAAYf,CAAAA,CACtBe,CAAAA,CAAU,KAAA,CAAM,OAAA,CAAU,MAAA,CAE1BF,CAAAA,CAAI,OAAOC,CAAAA,CAAKC,CAAS,CAAA,CAGzB,IAAIC,EAAOV,CAAAA,CACLW,CAAAA,CAAa,IAAM,CACvBL,EAAO,SAAA,CAAU,MAAA,CAAO,SAAA,CAAWI,CAAI,CAAA,CACvCF,CAAAA,CAAI,KAAA,CAAM,OAAA,CAAUE,EAAO,MAAA,CAAS,OAAA,CACpCD,CAAAA,CAAU,KAAA,CAAM,QAAUC,CAAAA,CAAO,OAAA,CAAU,MAAA,CAC3CH,CAAAA,CAAI,aAAa,eAAA,CAAiB,MAAA,CAAOG,CAAI,CAAC,EAChD,CAAA,CAEAH,CAAAA,CAAI,gBAAA,CAAiB,QAAS,IAAM,CAClCG,CAAAA,CAAO,CAACA,EACRC,CAAAA,GACF,CAAC,CAAA,CAED,SAAS,IAAA,CAAK,MAAA,CAAOL,CAAAA,CAAQC,CAAG,CAAA,CAChCI,CAAAA,EAAW,CACXhB,CAAAA,CAAe,KACjB,CAAC,EACH,CA2BO,SAASiB,GAAgB,CAtNhC,IAAA5B,CAAAA,CAAAC,CAAAA,CAAA4B,GAuNE7B,CAAAA,CAAA,QAAA,CAAS,cAAA,CAAe,eAAe,CAAA,GAAvC,IAAA,EAAAA,CAAAA,CAA0C,MAAA,EAAA,CAAA,CAC1CC,EAAA,QAAA,CAAS,cAAA,CAAe,aAAa,CAAA,GAArC,MAAAA,CAAAA,CAAwC,MAAA,EAAA,CAAA,CACxC4B,CAAAA,CAAA,QAAA,CAAS,eAAe,gBAAgB,CAAA,GAAxC,IAAA,EAAAA,CAAAA,CAA2C,MAAA,EAAA,CAC3ClB,CAAAA,CAAe,MACjB,CClMO,SAASmB,CAAAA,CAAeC,CAAAA,CAA4B,CAEzD,IAAMC,EAAUC,YAAAA,CAAOF,CAAK,CAAA,CAE5B,OAAAG,gBAAU,IAAM,CAEd,GAAI,OAAO,QAAW,WAAA,CAEtB,OAAAtB,CAAAA,CAAKoB,CAAAA,CAAQ,OAAO,CAAA,CAEb,IAAM,CACXJ,CAAAA,GACF,CACF,CAAA,CAAG,EAAE,EAGE,IACT","file":"react.js","sourcesContent":["/** Options accepted by DunefoxChat.init() */\r\nexport interface DunefoxChatOptions {\r\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\r\n tenantId: string;\r\n /**\r\n * Where to anchor the widget. Defaults to \"bottom-right\".\r\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\r\n */\r\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\r\n /** Open the chat panel on load. Defaults to false. */\r\n defaultOpen?: boolean;\r\n /** Override the base URL (for self-hosted / staging). */\r\n baseUrl?: string;\r\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\r\n iconUrl?: string;\r\n}\r\n\r\nconst DEFAULT_BASE = 'https://app.dunefox.io';\r\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\r\nconst UUID_KEY = 'dunefox_chat_uuid';\r\n\r\n// ─── UUID generation ──────────────────────────────────────────────────────────\r\nfunction getOrCreateUUID(): string {\r\n try {\r\n let id = localStorage.getItem(UUID_KEY);\r\n if (!id) {\r\n id = crypto?.randomUUID?.()\r\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n localStorage.setItem(UUID_KEY, id);\r\n }\r\n return id;\r\n } catch {\r\n // Incognito / storage blocked — generate ephemeral ID\r\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n }\r\n}\r\n\r\n// ─── CSS injector ─────────────────────────────────────────────────────────────\r\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\r\n if (document.getElementById('dunefox-styles')) return;\r\n\r\n const isTop = position.startsWith('top');\r\n const isLeft = position.endsWith('left');\r\n const hSide = isLeft ? 'left:16px' : 'right:16px';\r\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\r\n // Panel opens away from the button edge\r\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\r\n // Slide direction: panels below slide up, panels above slide down\r\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\r\n // Hover nudge direction\r\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\r\n // Mobile slide direction\r\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\r\n\r\n const css = `\r\n #dunefox-btn {\r\n position: fixed; ${vBtn}; ${hSide};\r\n width: 60px; height: 60px; border-radius: 50%;\r\n background: #1a1a1a; border: none; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center;\r\n z-index: 2147483646;\r\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\r\n transition: transform .25s ease;\r\n }\r\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\r\n #dunefox-frame {\r\n position: fixed; ${vFrame}; ${hSide};\r\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\r\n border-radius: 16px; border: none; z-index: 2147483645;\r\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\r\n opacity: 0; visibility: hidden;\r\n transform: ${slideOut};\r\n transition: all .4s cubic-bezier(.4,0,.2,1);\r\n }\r\n #dunefox-frame.df-open {\r\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\r\n }\r\n @media (max-width: 768px) {\r\n #dunefox-btn {\r\n bottom: unset !important; top: 16px !important;\r\n right: 16px !important; left: unset !important;\r\n }\r\n #dunefox-frame {\r\n width: 100% !important; height: 100% !important; max-height: none !important;\r\n position: fixed !important; inset: 0 !important;\r\n border-radius: 0 !important;\r\n transform: ${mobileSlideOut} !important;\r\n }\r\n #dunefox-frame.df-open { transform: translateY(0) !important; }\r\n }\r\n `;\r\n const tag = document.createElement('style');\r\n tag.id = 'dunefox-styles';\r\n tag.textContent = css;\r\n document.head.appendChild(tag);\r\n}\r\n\r\n// ─── SVG icons ────────────────────────────────────────────────────────────────\r\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\r\n\r\n// ─── Main init ────────────────────────────────────────────────────────────────\r\nlet _initialised = false;\r\n\r\n/**\r\n * Initialise the Dunefox chatbot widget.\r\n * Call once on DOMContentLoaded or after your framework has mounted.\r\n *\r\n * @example\r\n * import { init } from 'dunefox-chatbot';\r\n * init({ tenantId: 'YOUR_TENANT_ID' });\r\n */\r\nexport function init(options: DunefoxChatOptions | string): void {\r\n // Allow shorthand: init('tenantId')\r\n const opts: DunefoxChatOptions =\r\n typeof options === 'string' ? { tenantId: options } : options;\r\n\r\n if (_initialised) {\r\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\r\n return;\r\n }\r\n\r\n const {\r\n tenantId,\r\n position = 'bottom-right',\r\n defaultOpen = false,\r\n baseUrl = DEFAULT_BASE,\r\n iconUrl = DEFAULT_ICON,\r\n } = opts;\r\n\r\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\r\n\r\n // Wait for DOM if we're running during <head> parse\r\n const ready = (cb: () => void) =>\r\n document.readyState === 'loading'\r\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\r\n : cb();\r\n\r\n ready(() => {\r\n injectStyles(position);\r\n\r\n const uuid = getOrCreateUUID();\r\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\r\n\r\n // ── iframe ──\r\n const iframe = document.createElement('iframe');\r\n iframe.id = 'dunefox-frame';\r\n iframe.title = 'Dunefox Chat';\r\n iframe.loading = 'lazy';\r\n iframe.src = src;\r\n\r\n // ── toggle button ──\r\n const btn = document.createElement('button');\r\n btn.id = 'dunefox-btn';\r\n btn.setAttribute('aria-label', 'Open chat');\r\n btn.setAttribute('aria-expanded', 'false');\r\n\r\n const img = document.createElement('img');\r\n img.src = iconUrl;\r\n img.alt = '';\r\n img.width = 60;\r\n img.height = 60;\r\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\r\n\r\n const closeSpan = document.createElement('span');\r\n closeSpan.innerHTML = CLOSE_SVG;\r\n closeSpan.style.display = 'none';\r\n\r\n btn.append(img, closeSpan);\r\n\r\n // ── state ──\r\n let open = defaultOpen;\r\n const applyState = () => {\r\n iframe.classList.toggle('df-open', open);\r\n img.style.display = open ? 'none' : 'block';\r\n closeSpan.style.display = open ? 'block' : 'none';\r\n btn.setAttribute('aria-expanded', String(open));\r\n };\r\n\r\n btn.addEventListener('click', () => {\r\n open = !open;\r\n applyState();\r\n });\r\n\r\n document.body.append(iframe, btn);\r\n applyState();\r\n _initialised = true;\r\n });\r\n}\r\n\r\n/**\r\n * Programmatically open the chat panel.\r\n */\r\nexport function open(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.add('df-open');\r\n btn.setAttribute('aria-expanded', 'true');\r\n}\r\n\r\n/**\r\n * Programmatically close the chat panel.\r\n */\r\nexport function close(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.remove('df-open');\r\n btn.setAttribute('aria-expanded', 'false');\r\n}\r\n\r\n/**\r\n * Remove the widget entirely.\r\n */\r\nexport function destroy(): void {\r\n document.getElementById('dunefox-frame')?.remove();\r\n document.getElementById('dunefox-btn')?.remove();\r\n document.getElementById('dunefox-styles')?.remove();\r\n _initialised = false;\r\n}\r\n","import { useEffect, useRef } from 'react';\nimport { init, destroy } from './core';\nimport type { DunefoxChatOptions } from './core';\n\nexport interface DunefoxChatbotProps extends DunefoxChatOptions {}\n\n/**\n * React component wrapper for the Dunefox Chatbot widget.\n *\n * Drop it anywhere in your component tree — typically at the root layout level.\n * SSR-safe: the widget is only mounted in the browser via useEffect.\n *\n * @example\n * // Next.js App Router (app/layout.tsx)\n * import { DunefoxChatbot } from 'dunefox-chatbot/react';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html><body>\n * {children}\n * <DunefoxChatbot tenantId=\"YOUR_TENANT_ID\" />\n * </body></html>\n * );\n * }\n */\nexport function DunefoxChatbot(props: DunefoxChatbotProps) {\n // Capture props at mount time — we intentionally don't re-init on prop changes\n const optsRef = useRef(props);\n\n useEffect(() => {\n // Prevent running during SSR (window check is a safety net)\n if (typeof window === 'undefined') return;\n\n init(optsRef.current);\n\n return () => {\n destroy();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // This component renders nothing to the React tree — the widget is DOM-injected\n return null;\n}\n"]}
package/dist/react.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import {useRef,useEffect}from'react';var v="https://app.dunefox.io",w="https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png",h="dunefox_chat_uuid";function E(){var e,t;try{let n=localStorage.getItem(h);return n||(n=(t=(e=crypto==null?void 0:crypto.randomUUID)==null?void 0:e.call(crypto))!=null?t:Math.random().toString(36).slice(2)+Date.now().toString(36),localStorage.setItem(h,n)),n}catch(n){return Math.random().toString(36).slice(2)+Date.now().toString(36)}}function I(e){if(document.getElementById("dunefox-styles"))return;let t=e.startsWith("top"),d=e.endsWith("left")?"left:16px":"right:16px",c=`
1
+ import {useRef,useEffect}from'react';var v="https://app.dunefox.io",E="https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png",h="dunefox_chat_uuid";function w(){var e,t;try{let n=localStorage.getItem(h);return n||(n=(t=(e=crypto==null?void 0:crypto.randomUUID)==null?void 0:e.call(crypto))!=null?t:Math.random().toString(36).slice(2)+Date.now().toString(36),localStorage.setItem(h,n)),n}catch(n){return Math.random().toString(36).slice(2)+Date.now().toString(36)}}function I(e){if(document.getElementById("dunefox-styles"))return;let t=e.startsWith("top"),d=e.endsWith("left")?"left:16px":"right:16px",c=`
2
2
  #dunefox-btn {
3
3
  position: fixed; ${t?"top:16px":"bottom:16px"}; ${d};
4
4
  width: 60px; height: 60px; border-radius: 50%;
@@ -22,13 +22,18 @@ import {useRef,useEffect}from'react';var v="https://app.dunefox.io",w="https://d
22
22
  opacity: 1; visibility: visible; transform: translateY(0) scale(1);
23
23
  }
24
24
  @media (max-width: 768px) {
25
+ #dunefox-btn {
26
+ bottom: unset !important; top: 16px !important;
27
+ right: 16px !important; left: unset !important;
28
+ }
25
29
  #dunefox-frame {
26
- width: 100vw; height: 100vh; max-height: none;
27
- inset: 0; border-radius: 0; transform: ${t?"translateY(-100%)":"translateY(100%)"};
28
- bottom: unset; right: unset; left: unset; top: unset;
30
+ width: 100% !important; height: 100% !important; max-height: none !important;
31
+ position: fixed !important; inset: 0 !important;
32
+ border-radius: 0 !important;
33
+ transform: ${t?"translateY(-100%)":"translateY(100%)"} !important;
29
34
  }
30
- #dunefox-frame.df-open { transform: translateY(0); }
35
+ #dunefox-frame.df-open { transform: translateY(0) !important; }
31
36
  }
32
- `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var D='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',u=false;function b(e){let t=typeof e=="string"?{tenantId:e}:e;if(u){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:f=false,baseUrl:p=v,iconUrl:m=w}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{I(d);let s=E(),c=`${p}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let r=document.createElement("button");r.id="dunefox-btn",r.setAttribute("aria-label","Open chat"),r.setAttribute("aria-expanded","false");let i=document.createElement("img");i.src=m,i.alt="",i.width=60,i.height=60,i.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=D,l.style.display="none",r.append(i,l);let a=f,x=()=>{o.classList.toggle("df-open",a),i.style.display=a?"none":"block",l.style.display=a?"block":"none",r.setAttribute("aria-expanded",String(a));};r.addEventListener("click",()=>{a=!a,x();}),document.body.append(o,r),x(),u=true;});}function g(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),u=false;}function U(e){let t=useRef(e);return useEffect(()=>{if(typeof window!="undefined")return b(t.current),()=>{g();}},[]),null}
37
+ `,o=document.createElement("style");o.id="dunefox-styles",o.textContent=c,document.head.appendChild(o);}var D='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>',p=false;function b(e){let t=typeof e=="string"?{tenantId:e}:e;if(p){console.warn("[DunefoxChat] Already initialised. Call destroy() first.");return}let{tenantId:n,position:d="bottom-right",defaultOpen:u=false,baseUrl:f=v,iconUrl:m=E}=t;if(!n)throw new Error("[DunefoxChat] tenantId is required.");(s=>document.readyState==="loading"?document.addEventListener("DOMContentLoaded",s,{once:true}):s())(()=>{I(d);let s=w(),c=`${f}/api/${n}?uuid=${s}`,o=document.createElement("iframe");o.id="dunefox-frame",o.title="Dunefox Chat",o.loading="lazy",o.src=c;let r=document.createElement("button");r.id="dunefox-btn",r.setAttribute("aria-label","Open chat"),r.setAttribute("aria-expanded","false");let i=document.createElement("img");i.src=m,i.alt="",i.width=60,i.height=60,i.style.cssText="display:block;border-radius:50%;object-fit:cover;";let l=document.createElement("span");l.innerHTML=D,l.style.display="none",r.append(i,l);let a=u,x=()=>{o.classList.toggle("df-open",a),i.style.display=a?"none":"block",l.style.display=a?"block":"none",r.setAttribute("aria-expanded",String(a));};r.addEventListener("click",()=>{a=!a,x();}),document.body.append(o,r),x(),p=true;});}function g(){var e,t,n;(e=document.getElementById("dunefox-frame"))==null||e.remove(),(t=document.getElementById("dunefox-btn"))==null||t.remove(),(n=document.getElementById("dunefox-styles"))==null||n.remove(),p=false;}function U(e){let t=useRef(e);return useEffect(()=>{if(typeof window!="undefined")return b(t.current),()=>{g();}},[]),null}
33
38
  export{U as DunefoxChatbot};//# sourceMappingURL=react.mjs.map
34
39
  //# sourceMappingURL=react.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts","../src/react.tsx"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","destroy","_c","DunefoxChatbot","props","optsRef","useRef","useEffect"],"mappings":"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","file":"react.mjs","sourcesContent":["/** Options accepted by DunefoxChat.init() */\nexport interface DunefoxChatOptions {\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\n tenantId: string;\n /**\n * Where to anchor the widget. Defaults to \"bottom-right\".\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\n */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n /** Open the chat panel on load. Defaults to false. */\n defaultOpen?: boolean;\n /** Override the base URL (for self-hosted / staging). */\n baseUrl?: string;\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\n iconUrl?: string;\n}\n\nconst DEFAULT_BASE = 'https://app.dunefox.io';\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\nconst UUID_KEY = 'dunefox_chat_uuid';\n\n// ─── UUID generation ──────────────────────────────────────────────────────────\nfunction getOrCreateUUID(): string {\n try {\n let id = localStorage.getItem(UUID_KEY);\n if (!id) {\n id = crypto?.randomUUID?.()\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\n localStorage.setItem(UUID_KEY, id);\n }\n return id;\n } catch {\n // Incognito / storage blocked — generate ephemeral ID\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\n }\n}\n\n// ─── CSS injector ─────────────────────────────────────────────────────────────\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\n if (document.getElementById('dunefox-styles')) return;\n\n const isTop = position.startsWith('top');\n const isLeft = position.endsWith('left');\n const hSide = isLeft ? 'left:16px' : 'right:16px';\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\n // Panel opens away from the button edge\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\n // Slide direction: panels below slide up, panels above slide down\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\n // Hover nudge direction\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\n // Mobile slide direction\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\n\n const css = `\n #dunefox-btn {\n position: fixed; ${vBtn}; ${hSide};\n width: 60px; height: 60px; border-radius: 50%;\n background: #1a1a1a; border: none; cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n z-index: 2147483646;\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\n transition: transform .25s ease;\n }\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\n #dunefox-frame {\n position: fixed; ${vFrame}; ${hSide};\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\n border-radius: 16px; border: none; z-index: 2147483645;\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\n opacity: 0; visibility: hidden;\n transform: ${slideOut};\n transition: all .4s cubic-bezier(.4,0,.2,1);\n }\n #dunefox-frame.df-open {\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\n }\n @media (max-width: 768px) {\n #dunefox-frame {\n width: 100vw; height: 100vh; max-height: none;\n inset: 0; border-radius: 0; transform: ${mobileSlideOut};\n bottom: unset; right: unset; left: unset; top: unset;\n }\n #dunefox-frame.df-open { transform: translateY(0); }\n }\n `;\n const tag = document.createElement('style');\n tag.id = 'dunefox-styles';\n tag.textContent = css;\n document.head.appendChild(tag);\n}\n\n// ─── SVG icons ────────────────────────────────────────────────────────────────\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\n\n// ─── Main init ────────────────────────────────────────────────────────────────\nlet _initialised = false;\n\n/**\n * Initialise the Dunefox chatbot widget.\n * Call once on DOMContentLoaded or after your framework has mounted.\n *\n * @example\n * import { init } from 'dunefox-chatbot';\n * init({ tenantId: 'YOUR_TENANT_ID' });\n */\nexport function init(options: DunefoxChatOptions | string): void {\n // Allow shorthand: init('tenantId')\n const opts: DunefoxChatOptions =\n typeof options === 'string' ? { tenantId: options } : options;\n\n if (_initialised) {\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\n return;\n }\n\n const {\n tenantId,\n position = 'bottom-right',\n defaultOpen = false,\n baseUrl = DEFAULT_BASE,\n iconUrl = DEFAULT_ICON,\n } = opts;\n\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\n\n // Wait for DOM if we're running during <head> parse\n const ready = (cb: () => void) =>\n document.readyState === 'loading'\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\n : cb();\n\n ready(() => {\n injectStyles(position);\n\n const uuid = getOrCreateUUID();\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\n\n // ── iframe ──\n const iframe = document.createElement('iframe');\n iframe.id = 'dunefox-frame';\n iframe.title = 'Dunefox Chat';\n iframe.loading = 'lazy';\n iframe.src = src;\n\n // ── toggle button ──\n const btn = document.createElement('button');\n btn.id = 'dunefox-btn';\n btn.setAttribute('aria-label', 'Open chat');\n btn.setAttribute('aria-expanded', 'false');\n\n const img = document.createElement('img');\n img.src = iconUrl;\n img.alt = '';\n img.width = 60;\n img.height = 60;\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\n\n const closeSpan = document.createElement('span');\n closeSpan.innerHTML = CLOSE_SVG;\n closeSpan.style.display = 'none';\n\n btn.append(img, closeSpan);\n\n // ── state ──\n let open = defaultOpen;\n const applyState = () => {\n iframe.classList.toggle('df-open', open);\n img.style.display = open ? 'none' : 'block';\n closeSpan.style.display = open ? 'block' : 'none';\n btn.setAttribute('aria-expanded', String(open));\n };\n\n btn.addEventListener('click', () => {\n open = !open;\n applyState();\n });\n\n document.body.append(iframe, btn);\n applyState();\n _initialised = true;\n });\n}\n\n/**\n * Programmatically open the chat panel.\n */\nexport function open(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.add('df-open');\n btn.setAttribute('aria-expanded', 'true');\n}\n\n/**\n * Programmatically close the chat panel.\n */\nexport function close(): void {\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\n const btn = document.getElementById('dunefox-btn');\n if (!iframe || !btn) return;\n iframe.classList.remove('df-open');\n btn.setAttribute('aria-expanded', 'false');\n}\n\n/**\n * Remove the widget entirely.\n */\nexport function destroy(): void {\n document.getElementById('dunefox-frame')?.remove();\n document.getElementById('dunefox-btn')?.remove();\n document.getElementById('dunefox-styles')?.remove();\n _initialised = false;\n}\n","import { useEffect, useRef } from 'react';\nimport { init, destroy } from './core';\nimport type { DunefoxChatOptions } from './core';\n\nexport interface DunefoxChatbotProps extends DunefoxChatOptions {}\n\n/**\n * React component wrapper for the Dunefox Chatbot widget.\n *\n * Drop it anywhere in your component tree — typically at the root layout level.\n * SSR-safe: the widget is only mounted in the browser via useEffect.\n *\n * @example\n * // Next.js App Router (app/layout.tsx)\n * import { DunefoxChatbot } from 'dunefox-chatbot/react';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html><body>\n * {children}\n * <DunefoxChatbot tenantId=\"YOUR_TENANT_ID\" />\n * </body></html>\n * );\n * }\n */\nexport function DunefoxChatbot(props: DunefoxChatbotProps) {\n // Capture props at mount time — we intentionally don't re-init on prop changes\n const optsRef = useRef(props);\n\n useEffect(() => {\n // Prevent running during SSR (window check is a safety net)\n if (typeof window === 'undefined') return;\n\n init(optsRef.current);\n\n return () => {\n destroy();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // This component renders nothing to the React tree — the widget is DOM-injected\n return null;\n}\n"]}
1
+ {"version":3,"sources":["../src/core.ts","../src/react.tsx"],"names":["DEFAULT_BASE","DEFAULT_ICON","UUID_KEY","getOrCreateUUID","_a","_b","id","e","injectStyles","position","isTop","hSide","css","tag","CLOSE_SVG","_initialised","init","options","opts","tenantId","defaultOpen","baseUrl","iconUrl","cb","uuid","src","iframe","btn","img","closeSpan","open","applyState","destroy","_c","DunefoxChatbot","props","optsRef","useRef","useEffect"],"mappings":"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","file":"react.mjs","sourcesContent":["/** Options accepted by DunefoxChat.init() */\r\nexport interface DunefoxChatOptions {\r\n /** Your Dunefox Tenant ID — found in Settings > Install Widget */\r\n tenantId: string;\r\n /**\r\n * Where to anchor the widget. Defaults to \"bottom-right\".\r\n * Supports: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"\r\n */\r\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\r\n /** Open the chat panel on load. Defaults to false. */\r\n defaultOpen?: boolean;\r\n /** Override the base URL (for self-hosted / staging). */\r\n baseUrl?: string;\r\n /** Icon image URL override. Falls back to Dunefox CDN asset. */\r\n iconUrl?: string;\r\n}\r\n\r\nconst DEFAULT_BASE = 'https://app.dunefox.io';\r\nconst DEFAULT_ICON = 'https://dunefoxx.s3.ap-south-1.amazonaws.com/chatbot.png';\r\nconst UUID_KEY = 'dunefox_chat_uuid';\r\n\r\n// ─── UUID generation ──────────────────────────────────────────────────────────\r\nfunction getOrCreateUUID(): string {\r\n try {\r\n let id = localStorage.getItem(UUID_KEY);\r\n if (!id) {\r\n id = crypto?.randomUUID?.()\r\n ?? Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n localStorage.setItem(UUID_KEY, id);\r\n }\r\n return id;\r\n } catch {\r\n // Incognito / storage blocked — generate ephemeral ID\r\n return Math.random().toString(36).slice(2) + Date.now().toString(36);\r\n }\r\n}\r\n\r\n// ─── CSS injector ─────────────────────────────────────────────────────────────\r\nfunction injectStyles(position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'): void {\r\n if (document.getElementById('dunefox-styles')) return;\r\n\r\n const isTop = position.startsWith('top');\r\n const isLeft = position.endsWith('left');\r\n const hSide = isLeft ? 'left:16px' : 'right:16px';\r\n const vBtn = isTop ? 'top:16px' : 'bottom:16px';\r\n // Panel opens away from the button edge\r\n const vFrame = isTop ? 'top:88px' : 'bottom:88px';\r\n // Slide direction: panels below slide up, panels above slide down\r\n const slideOut = isTop ? 'translateY(-24px) scale(.96)' : 'translateY(24px) scale(.96)';\r\n // Hover nudge direction\r\n const hoverTranslate = isTop ? 'translateY(2px) scale(1.05)' : 'translateY(-2px) scale(1.05)';\r\n // Mobile slide direction\r\n const mobileSlideOut = isTop ? 'translateY(-100%)' : 'translateY(100%)';\r\n\r\n const css = `\r\n #dunefox-btn {\r\n position: fixed; ${vBtn}; ${hSide};\r\n width: 60px; height: 60px; border-radius: 50%;\r\n background: #1a1a1a; border: none; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center;\r\n z-index: 2147483646;\r\n box-shadow: 0 4px 20px rgba(0,0,0,.25);\r\n transition: transform .25s ease;\r\n }\r\n #dunefox-btn:hover { transform: ${hoverTranslate}; }\r\n #dunefox-frame {\r\n position: fixed; ${vFrame}; ${hSide};\r\n width: 350px; height: calc(100vh - 160px); max-height: 600px;\r\n border-radius: 16px; border: none; z-index: 2147483645;\r\n box-shadow: 0 8px 32px rgba(0,0,0,.12);\r\n opacity: 0; visibility: hidden;\r\n transform: ${slideOut};\r\n transition: all .4s cubic-bezier(.4,0,.2,1);\r\n }\r\n #dunefox-frame.df-open {\r\n opacity: 1; visibility: visible; transform: translateY(0) scale(1);\r\n }\r\n @media (max-width: 768px) {\r\n #dunefox-btn {\r\n bottom: unset !important; top: 16px !important;\r\n right: 16px !important; left: unset !important;\r\n }\r\n #dunefox-frame {\r\n width: 100% !important; height: 100% !important; max-height: none !important;\r\n position: fixed !important; inset: 0 !important;\r\n border-radius: 0 !important;\r\n transform: ${mobileSlideOut} !important;\r\n }\r\n #dunefox-frame.df-open { transform: translateY(0) !important; }\r\n }\r\n `;\r\n const tag = document.createElement('style');\r\n tag.id = 'dunefox-styles';\r\n tag.textContent = css;\r\n document.head.appendChild(tag);\r\n}\r\n\r\n// ─── SVG icons ────────────────────────────────────────────────────────────────\r\nconst CLOSE_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>`;\r\n\r\n// ─── Main init ────────────────────────────────────────────────────────────────\r\nlet _initialised = false;\r\n\r\n/**\r\n * Initialise the Dunefox chatbot widget.\r\n * Call once on DOMContentLoaded or after your framework has mounted.\r\n *\r\n * @example\r\n * import { init } from 'dunefox-chatbot';\r\n * init({ tenantId: 'YOUR_TENANT_ID' });\r\n */\r\nexport function init(options: DunefoxChatOptions | string): void {\r\n // Allow shorthand: init('tenantId')\r\n const opts: DunefoxChatOptions =\r\n typeof options === 'string' ? { tenantId: options } : options;\r\n\r\n if (_initialised) {\r\n console.warn('[DunefoxChat] Already initialised. Call destroy() first.');\r\n return;\r\n }\r\n\r\n const {\r\n tenantId,\r\n position = 'bottom-right',\r\n defaultOpen = false,\r\n baseUrl = DEFAULT_BASE,\r\n iconUrl = DEFAULT_ICON,\r\n } = opts;\r\n\r\n if (!tenantId) throw new Error('[DunefoxChat] tenantId is required.');\r\n\r\n // Wait for DOM if we're running during <head> parse\r\n const ready = (cb: () => void) =>\r\n document.readyState === 'loading'\r\n ? document.addEventListener('DOMContentLoaded', cb, { once: true })\r\n : cb();\r\n\r\n ready(() => {\r\n injectStyles(position);\r\n\r\n const uuid = getOrCreateUUID();\r\n const src = `${baseUrl}/api/${tenantId}?uuid=${uuid}`;\r\n\r\n // ── iframe ──\r\n const iframe = document.createElement('iframe');\r\n iframe.id = 'dunefox-frame';\r\n iframe.title = 'Dunefox Chat';\r\n iframe.loading = 'lazy';\r\n iframe.src = src;\r\n\r\n // ── toggle button ──\r\n const btn = document.createElement('button');\r\n btn.id = 'dunefox-btn';\r\n btn.setAttribute('aria-label', 'Open chat');\r\n btn.setAttribute('aria-expanded', 'false');\r\n\r\n const img = document.createElement('img');\r\n img.src = iconUrl;\r\n img.alt = '';\r\n img.width = 60;\r\n img.height = 60;\r\n img.style.cssText = 'display:block;border-radius:50%;object-fit:cover;';\r\n\r\n const closeSpan = document.createElement('span');\r\n closeSpan.innerHTML = CLOSE_SVG;\r\n closeSpan.style.display = 'none';\r\n\r\n btn.append(img, closeSpan);\r\n\r\n // ── state ──\r\n let open = defaultOpen;\r\n const applyState = () => {\r\n iframe.classList.toggle('df-open', open);\r\n img.style.display = open ? 'none' : 'block';\r\n closeSpan.style.display = open ? 'block' : 'none';\r\n btn.setAttribute('aria-expanded', String(open));\r\n };\r\n\r\n btn.addEventListener('click', () => {\r\n open = !open;\r\n applyState();\r\n });\r\n\r\n document.body.append(iframe, btn);\r\n applyState();\r\n _initialised = true;\r\n });\r\n}\r\n\r\n/**\r\n * Programmatically open the chat panel.\r\n */\r\nexport function open(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.add('df-open');\r\n btn.setAttribute('aria-expanded', 'true');\r\n}\r\n\r\n/**\r\n * Programmatically close the chat panel.\r\n */\r\nexport function close(): void {\r\n const iframe = document.getElementById('dunefox-frame') as HTMLIFrameElement | null;\r\n const btn = document.getElementById('dunefox-btn');\r\n if (!iframe || !btn) return;\r\n iframe.classList.remove('df-open');\r\n btn.setAttribute('aria-expanded', 'false');\r\n}\r\n\r\n/**\r\n * Remove the widget entirely.\r\n */\r\nexport function destroy(): void {\r\n document.getElementById('dunefox-frame')?.remove();\r\n document.getElementById('dunefox-btn')?.remove();\r\n document.getElementById('dunefox-styles')?.remove();\r\n _initialised = false;\r\n}\r\n","import { useEffect, useRef } from 'react';\nimport { init, destroy } from './core';\nimport type { DunefoxChatOptions } from './core';\n\nexport interface DunefoxChatbotProps extends DunefoxChatOptions {}\n\n/**\n * React component wrapper for the Dunefox Chatbot widget.\n *\n * Drop it anywhere in your component tree — typically at the root layout level.\n * SSR-safe: the widget is only mounted in the browser via useEffect.\n *\n * @example\n * // Next.js App Router (app/layout.tsx)\n * import { DunefoxChatbot } from 'dunefox-chatbot/react';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html><body>\n * {children}\n * <DunefoxChatbot tenantId=\"YOUR_TENANT_ID\" />\n * </body></html>\n * );\n * }\n */\nexport function DunefoxChatbot(props: DunefoxChatbotProps) {\n // Capture props at mount time — we intentionally don't re-init on prop changes\n const optsRef = useRef(props);\n\n useEffect(() => {\n // Prevent running during SSR (window check is a safety net)\n if (typeof window === 'undefined') return;\n\n init(optsRef.current);\n\n return () => {\n destroy();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // This component renders nothing to the React tree — the widget is DOM-injected\n return null;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dunefox-chatbot",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Official Dunefox chatbot widget — add AI chat to any website in seconds",
5
5
  "keywords": [
6
6
  "dunefox",