@cas0570/chat-widget 0.0.4 → 0.0.5

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.
@@ -1,12 +1,14 @@
1
- (function(){"use strict";try{if(typeof document<"u"){var r=document.createElement("style");r.appendChild(document.createTextNode(':root{--gcw-color-white: #fff;--gcw-color-gray-50: #f9fafb;--gcw-color-gray-100: #f3f4f6;--gcw-color-gray-200: #e5e7eb;--gcw-color-gray-300: #d1d5db;--gcw-color-gray-400: #9ca3af;--gcw-color-gray-500: #6b7280;--gcw-color-gray-600: #4b5563;--gcw-color-gray-700: #374151;--gcw-color-gray-800: #1f2937;--gcw-color-gray-900: #111827;--gcw-color-primary: #3b82f6;--gcw-color-primary-hover: #2563eb;--gcw-color-primary-light: #eff6ff;--gcw-color-error: #ef4444;--gcw-color-success: #22c55e;--gcw-font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--gcw-font-size-xs: .625rem;--gcw-font-size-sm: .75rem;--gcw-font-size-base: .875rem;--gcw-font-size-lg: 1rem;--gcw-spacing-1: .25rem;--gcw-spacing-2: .5rem;--gcw-spacing-3: .75rem;--gcw-spacing-4: 1rem;--gcw-spacing-5: 1.25rem;--gcw-spacing-6: 1.5rem;--gcw-radius-sm: .25rem;--gcw-radius-md: .5rem;--gcw-radius-lg: .75rem;--gcw-radius-xl: 1rem;--gcw-radius-2xl: 1.25rem;--gcw-radius-full: 9999px;--gcw-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .05);--gcw-shadow-md: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--gcw-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--gcw-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--gcw-shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / .25);--gcw-transition-fast: .15s ease;--gcw-transition-base: .2s ease;--gcw-transition-slow: .3s ease;--gcw-z-widget: 9999}.gcw-widget,.gcw-widget *,.gcw-widget *:before,.gcw-widget *:after{box-sizing:border-box;margin:0;padding:0;font-family:var(--gcw-font-family);line-height:1.5}.gcw-widget{font-family:var(--gcw-font-family);font-size:var(--gcw-font-size-base);line-height:1.5;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--gcw-color-gray-800);text-align:left;letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;text-shadow:none;font-weight:400;font-style:normal}.gcw-container{position:fixed;z-index:var(--gcw-z-widget);display:flex;gap:var(--gcw-spacing-4)}.gcw-container--bottom-right{right:var(--gcw-spacing-4);bottom:var(--gcw-spacing-4);flex-direction:column-reverse;align-items:flex-end}.gcw-container--bottom-left{left:var(--gcw-spacing-4);bottom:var(--gcw-spacing-4);flex-direction:column-reverse;align-items:flex-start}.gcw-container--top-right{right:var(--gcw-spacing-4);top:var(--gcw-spacing-4);flex-direction:column;align-items:flex-end}.gcw-container--top-left{left:var(--gcw-spacing-4);top:var(--gcw-spacing-4);flex-direction:column;align-items:flex-start}.gcw-toggle{position:relative;width:3.5rem;height:3.5rem;border:none;border-radius:var(--gcw-radius-full);background-color:var(--gcw-color-primary);color:var(--gcw-color-white);cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:var(--gcw-shadow-lg);transition:transform var(--gcw-transition-base),box-shadow var(--gcw-transition-base)}.gcw-toggle:hover{transform:scale(1.1);box-shadow:var(--gcw-shadow-xl)}.gcw-toggle:active{transform:scale(.95)}.gcw-toggle__icon{width:1.5rem;height:1.5rem;transition:transform var(--gcw-transition-slow)}.gcw-toggle__badge{position:absolute;top:-.25rem;right:-.25rem;width:1rem;height:1rem;border-radius:var(--gcw-radius-full);display:flex;align-items:center;justify-content:center;font-size:var(--gcw-font-size-xs);font-weight:700;animation:gcw-pulse 2s infinite}.gcw-toggle__badge--unread{background-color:var(--gcw-color-error);color:var(--gcw-color-white)}.gcw-toggle__badge--popout{background-color:var(--gcw-color-success)}.gcw-window{display:flex;flex-direction:column;background-color:var(--gcw-color-white);border-radius:var(--gcw-radius-2xl);box-shadow:var(--gcw-shadow-2xl);border:1px solid var(--gcw-color-gray-200);overflow:hidden;animation:gcw-slide-up var(--gcw-transition-slow) ease-out}.gcw-window--small{width:320px;height:450px}.gcw-window--medium{width:380px;height:560px}.gcw-window--large{width:480px;height:680px}.gcw-window--fullscreen{width:calc(100vw - 2rem);height:calc(100vh - 6rem);max-width:56rem}.gcw-window{max-height:90vh;transition:width var(--gcw-transition-base),height var(--gcw-transition-base)}.gcw-header{display:flex;align-items:center;justify-content:space-between;padding:var(--gcw-spacing-3) var(--gcw-spacing-4);color:var(--gcw-color-white);flex-shrink:0}.gcw-header__left{display:flex;align-items:center;gap:var(--gcw-spacing-3)}.gcw-header__avatar{width:2.5rem;height:2.5rem;border-radius:var(--gcw-radius-full);background-color:#fff3;display:flex;align-items:center;justify-content:center}.gcw-header__avatar-icon{width:1.25rem;height:1.25rem}.gcw-header__info{display:flex;flex-direction:column;min-width:0;flex:1}.gcw-header__title{font-size:var(--gcw-font-size-base);font-weight:600;line-height:1.4;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gcw-header__subtitle{font-size:var(--gcw-font-size-sm);font-weight:400;line-height:1.4;opacity:.9;margin:0;word-wrap:break-word;overflow-wrap:break-word}.gcw-header__actions{display:flex;align-items:center;gap:.125rem}.gcw-header__btn{width:2rem;height:2rem;border:none;border-radius:var(--gcw-radius-full);background-color:transparent;color:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color var(--gcw-transition-fast)}.gcw-header__btn:hover{background-color:#fff3}.gcw-header__btn-icon{width:1rem;height:1rem}.gcw-messages{flex:1;overflow-y:auto;padding:var(--gcw-spacing-4);display:flex;flex-direction:column;gap:var(--gcw-spacing-4)}.gcw-messages::-webkit-scrollbar{width:6px}.gcw-messages::-webkit-scrollbar-track{background:transparent}.gcw-messages::-webkit-scrollbar-thumb{background-color:var(--gcw-color-gray-300);border-radius:3px}.gcw-messages::-webkit-scrollbar-thumb:hover{background-color:var(--gcw-color-gray-400)}.gcw-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--gcw-spacing-6);color:var(--gcw-color-gray-400);text-align:center}.gcw-empty__icon{width:4rem;height:4rem;margin-bottom:var(--gcw-spacing-4);opacity:.5}.gcw-empty__text{font-size:var(--gcw-font-size-base);font-weight:400;line-height:1.5;margin:0}.gcw-bubble-row{display:flex}.gcw-bubble-row--user{justify-content:flex-end}.gcw-bubble-row--assistant{justify-content:flex-start}.gcw-bubble-wrapper{max-width:85%;display:flex;flex-direction:column}.gcw-bubble-wrapper--user{align-items:flex-end}.gcw-bubble-wrapper--assistant{align-items:flex-start}.gcw-bubble{padding:var(--gcw-spacing-2) var(--gcw-spacing-4);border-radius:var(--gcw-radius-2xl);font-size:var(--gcw-font-size-base);font-weight:400;line-height:1.6;letter-spacing:normal;word-wrap:break-word}.gcw-bubble--user{color:var(--gcw-color-white);border-bottom-right-radius:var(--gcw-radius-sm)}.gcw-bubble--assistant{background-color:var(--gcw-color-gray-100);color:var(--gcw-color-gray-800);border-bottom-left-radius:var(--gcw-radius-sm)}.gcw-bubble__timestamp{font-size:var(--gcw-font-size-xs);color:var(--gcw-color-gray-400);margin-top:var(--gcw-spacing-1);padding:0 var(--gcw-spacing-1)}.gcw-content p{margin-bottom:var(--gcw-spacing-2)}.gcw-content p:last-child{margin-bottom:0}.gcw-content strong{font-weight:600}.gcw-content em{font-style:italic}.gcw-content ul,.gcw-content ol{margin:var(--gcw-spacing-2) 0;padding-left:var(--gcw-spacing-6)}.gcw-content li{margin-bottom:var(--gcw-spacing-1)}.gcw-content code{background-color:#0000001a;padding:.125rem .375rem;border-radius:var(--gcw-radius-sm);font-size:.875em;font-family:SF Mono,Monaco,Consolas,monospace}.gcw-bubble--user .gcw-content code{background-color:#fff3}.gcw-content pre{background-color:var(--gcw-color-gray-800);color:var(--gcw-color-gray-100);padding:var(--gcw-spacing-3);border-radius:var(--gcw-radius-md);overflow-x:auto;margin:var(--gcw-spacing-2) 0}.gcw-content pre code{background-color:transparent;padding:0;font-size:var(--gcw-font-size-sm)}.gcw-content a{color:var(--gcw-color-primary);text-decoration:underline}.gcw-content a:hover{color:var(--gcw-color-primary-hover)}.gcw-bubble--user .gcw-content a{color:#ffffffe6}.gcw-md-heading{font-weight:600;margin-top:var(--gcw-spacing-3);margin-bottom:var(--gcw-spacing-1)}.gcw-md-heading--h2{font-size:var(--gcw-font-size-lg);font-weight:700}.gcw-md-heading--h3,.gcw-md-heading--h4{font-size:var(--gcw-font-size-base)}.gcw-md-heading--h5{font-size:var(--gcw-font-size-sm)}.gcw-md-paragraph{margin-bottom:var(--gcw-spacing-2)}.gcw-md-paragraph:last-child{margin-bottom:0}.gcw-md-list{margin:var(--gcw-spacing-2) 0;padding-left:var(--gcw-spacing-4)}.gcw-md-list--ul{list-style-type:disc}.gcw-md-list--ol{list-style-type:decimal}.gcw-md-list__item{font-size:var(--gcw-font-size-base);margin-bottom:var(--gcw-spacing-1)}.gcw-md-bold{font-weight:600}.gcw-md-italic{font-style:italic}.gcw-md-code{background-color:var(--gcw-color-gray-200);padding:.125rem var(--gcw-spacing-2);border-radius:var(--gcw-radius-sm);font-size:var(--gcw-font-size-sm);font-family:SF Mono,Monaco,Consolas,monospace}.gcw-bubble--user .gcw-md-code{background-color:#fff3}.gcw-md-code-block{background-color:var(--gcw-color-gray-800);color:var(--gcw-color-gray-100);padding:var(--gcw-spacing-3);border-radius:var(--gcw-radius-lg);font-size:var(--gcw-font-size-sm);overflow-x:auto;margin:var(--gcw-spacing-2) 0}.gcw-md-code-block code{font-family:SF Mono,Monaco,Consolas,monospace}.gcw-md-link{color:var(--gcw-color-primary);text-decoration:underline}.gcw-md-link:hover{color:var(--gcw-color-primary-hover)}.gcw-bubble--user .gcw-md-link{color:#ffffffe6}.gcw-sources{display:flex;flex-wrap:wrap;gap:var(--gcw-spacing-2);margin-top:var(--gcw-spacing-2)}.gcw-source{display:inline-flex;align-items:center;gap:var(--gcw-spacing-1);padding:var(--gcw-spacing-1) var(--gcw-spacing-2);border-radius:var(--gcw-radius-full);background-color:var(--gcw-color-primary-light);color:var(--gcw-color-primary);font-size:var(--gcw-font-size-sm);text-decoration:none;transition:background-color var(--gcw-transition-fast)}.gcw-source:hover{background-color:#dbeafe}.gcw-source__icon{width:.75rem;height:.75rem}.gcw-typing{display:flex;justify-content:flex-start}.gcw-typing__bubble{background-color:var(--gcw-color-gray-100);padding:var(--gcw-spacing-3) var(--gcw-spacing-4);border-radius:var(--gcw-radius-2xl);border-bottom-left-radius:var(--gcw-radius-sm)}.gcw-typing__dots{display:flex;gap:var(--gcw-spacing-1)}.gcw-typing__dot{width:.5rem;height:.5rem;background-color:var(--gcw-color-gray-400);border-radius:var(--gcw-radius-full);animation:gcw-typing-bounce 1.4s infinite ease-in-out both}.gcw-typing__dot:nth-child(1){animation-delay:-.32s}.gcw-typing__dot:nth-child(2){animation-delay:-.16s}.gcw-input-area{padding:var(--gcw-spacing-3);border-top:1px solid var(--gcw-color-gray-200);background-color:var(--gcw-color-white);flex-shrink:0}.gcw-input-row{display:flex;align-items:flex-end;gap:var(--gcw-spacing-2)}.gcw-input{flex:1;min-height:44px;max-height:120px;padding:var(--gcw-spacing-2) var(--gcw-spacing-4);border:1px solid var(--gcw-color-gray-200);border-radius:var(--gcw-radius-xl);background-color:var(--gcw-color-white);color:var(--gcw-color-gray-800);font-family:var(--gcw-font-family);font-size:var(--gcw-font-size-base);font-weight:400;line-height:1.5;letter-spacing:normal;resize:none;outline:none;transition:border-color var(--gcw-transition-fast),box-shadow var(--gcw-transition-fast)}.gcw-input:focus{border-color:var(--gcw-color-primary);box-shadow:0 0 0 3px #3b82f61a}.gcw-input:disabled{background-color:var(--gcw-color-gray-50);cursor:not-allowed}.gcw-input::placeholder{color:var(--gcw-color-gray-400)}.gcw-send-btn{width:2.5rem;height:2.5rem;flex-shrink:0;border:none;border-radius:var(--gcw-radius-lg);color:var(--gcw-color-white);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:opacity var(--gcw-transition-fast),transform var(--gcw-transition-fast)}.gcw-send-btn:hover:not(:disabled){opacity:.9}.gcw-send-btn:active:not(:disabled){transform:scale(.95)}.gcw-send-btn:disabled{opacity:.5;cursor:not-allowed}.gcw-send-btn__icon{width:1.25rem;height:1.25rem}.gcw-input-hint{font-size:var(--gcw-font-size-xs);color:var(--gcw-color-gray-400);text-align:center;margin-top:var(--gcw-spacing-2)}@keyframes gcw-slide-up{0%{opacity:0;transform:translateY(1rem)}to{opacity:1;transform:translateY(0)}}@keyframes gcw-pulse{0%,to{opacity:1}50%{opacity:.5}}@keyframes gcw-typing-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}@keyframes gcw-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.gcw-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.gcw-spin{animation:gcw-spin 1s linear infinite}')),document.head.appendChild(r)}}catch(o){console.error("vite-plugin-css-injected-by-js",o)}})();
2
- (function(v,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],e):(v=typeof globalThis<"u"?globalThis:v||self,e(v.GeoAppsChatWidget={},v.React,v.React))})(this,function(v,e,c){"use strict";const ae="gcw_chat_",ie="gcw_popout_",le="gcw_read_";let G=!1;function U(t){return`${ae}${t||"default"}`}function ce(t,n,s){if(!G)try{G=!0;const a={messages:t.map(r=>({id:r.id,role:r.role,content:r.content,timestamp:r.timestamp.toISOString(),sources:r.sources})),sessionId:n,lastUpdated:new Date().toISOString()};localStorage.setItem(U(s),JSON.stringify(a))}catch(a){console.warn("Failed to save chat state:",a)}finally{G=!1}}function Z(t){try{const n=localStorage.getItem(U(t));if(!n)return null;const s=JSON.parse(n),a=new Date(s.lastUpdated);return(Date.now()-a.getTime())/(1e3*60*60)>24?(R(t),null):{messages:s.messages.map(o=>({id:o.id,role:o.role,content:o.content,timestamp:new Date(o.timestamp),sources:o.sources})),sessionId:s.sessionId}}catch(n){return console.warn("Failed to load chat state:",n),null}}function R(t){try{localStorage.removeItem(U(t))}catch(n){console.warn("Failed to clear chat state:",n)}}function de(t,n){const s=U(t),a=r=>{if(r.key===s){if(!r.newValue){n(null);return}try{const o=JSON.parse(r.newValue);n({messages:o.messages.map(i=>({id:i.id,role:i.role,content:i.content,timestamp:new Date(i.timestamp),sources:i.sources})),sessionId:o.sessionId})}catch{}}};return window.addEventListener("storage",a),()=>window.removeEventListener("storage",a)}function J(t){return`${ie}${t||"default"}`}function V(t,n){try{t?localStorage.setItem(J(n),"true"):localStorage.removeItem(J(n))}catch(s){console.warn("Failed to save popout state:",s)}}function ue(t){try{return localStorage.getItem(J(t))==="true"}catch{return!1}}function Y(t){return`${le}${t||"default"}`}function q(t,n){try{t?localStorage.setItem(Y(n),t):localStorage.removeItem(Y(n))}catch(s){console.warn("Failed to save read state:",s)}}function pe(t){try{return localStorage.getItem(Y(t))}catch{return null}}function ee(t){const{apiUrl:n,tenantId:s,sessionId:a,headers:r={},onError:o,persist:i=!0}=t,p=c.useRef(!1),[h,l]=c.useState(()=>{if(i){const d=Z(s);if(d)return d.messages}return[]}),[f,y]=c.useState(!1),[L,M]=c.useState(null),[g,w]=c.useState(()=>{if(i){const d=Z(s);if(d)return d.sessionId}return a||null}),j=c.useRef(null);c.useEffect(()=>{p.current||i&&h.length>0&&ce(h,g,s)},[h,g,s,i]),c.useEffect(()=>i?de(s,S=>{p.current=!0,S?(l(S.messages),w(S.sessionId)):(l([]),w(null)),setTimeout(()=>{p.current=!1},0)}):void 0,[s,i]);const P=()=>`msg_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,X=c.useCallback(async d=>{var D;if(!d.trim()||f)return;j.current&&j.current.abort(),j.current=new AbortController;const S={id:P(),role:"user",content:d.trim(),timestamp:new Date};l(u=>[...u,S]),y(!0),M(null);const T=P(),O={id:T,role:"assistant",content:"",timestamp:new Date,isStreaming:!0};l(u=>[...u,O]);try{const u=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",...s&&{"X-Tenant-ID":s},...r},body:JSON.stringify({message:d.trim(),session_id:g}),signal:j.current.signal});if(!u.ok){const m=await u.json().catch(()=>({}));throw new Error(m.detail||`Request failed with status ${u.status}`)}const k=u.headers.get("content-type");if(k!=null&&k.includes("text/event-stream"))await Q(u,T);else{const m=await u.json(),I=(D=m.message.citations)==null?void 0:D.map(x=>({title:x.title,url:x.url,relevance:x.relevance_score}));l(x=>x.map(B=>B.id===T?{...B,content:m.message.content,isStreaming:!1,sources:I}:B)),m.session_id&&w(m.session_id)}}catch(u){if(u.name==="AbortError")return;const k=u instanceof Error?u:new Error("An error occurred");M(k),o==null||o(k),l(m=>m.map(I=>I.id===T?{...I,content:"Sorry, an error occurred. Please try again.",isStreaming:!1}:I))}finally{y(!1),j.current=null}},[n,s,g,r,f,o]),Q=async(d,S)=>{var u;const T=(u=d.body)==null?void 0:u.getReader();if(!T)throw new Error("No response body");const O=new TextDecoder;let D="";try{for(;;){const{done:k,value:m}=await T.read();if(k)break;const x=O.decode(m,{stream:!0}).split(`
3
- `);for(const B of x)if(B.startsWith("data: ")){const K=B.slice(6);if(K==="[DONE]")continue;try{const C=JSON.parse(K);C.type==="content"&&C.content?(D+=C.content,l(H=>H.map($=>$.id===S?{...$,content:D}:$))):C.type==="sources"&&C.sources?l(H=>H.map($=>$.id===S?{...$,sources:C.sources}:$)):C.conversation_id&&w(C.conversation_id)}catch{}}}}finally{l(k=>k.map(m=>m.id===S?{...m,isStreaming:!1}:m))}},E=c.useCallback(()=>{l([]),w(null),M(null),i&&R(s)},[i,s]);return{messages:h,isLoading:f,error:L,sendMessage:X,clearMessages:E,sessionId:g}}let W=null;function he(t,n,s){const[a,r]=c.useState(()=>ue(t.tenantId)),o=c.useRef(W);c.useEffect(()=>{if(a&&!o.current){const l=window.open("","GeoAppsChatPopout");l&&l.location.href!=="about:blank"&&!l.closed?(o.current=l,W=l):(r(!1),V(!1,t.tenantId))}},[a,t.tenantId]),c.useEffect(()=>{if(!o.current)return;const l=setInterval(()=>{var f;(f=o.current)!=null&&f.closed&&(r(!1),o.current=null,W=null,V(!1,t.tenantId))},500);return()=>clearInterval(l)},[t.tenantId,s]);const i=c.useCallback(()=>{if(o.current&&!o.current.closed){o.current.focus();return}const l={small:{width:380,height:520},medium:{width:440,height:660},large:{width:560,height:780},fullscreen:{width:700,height:800}},{width:f,height:y}=l[n],L=(window.screen.width-f)/2,M=(window.screen.height-y)/2,g=window.open("","GeoAppsChatPopout",`width=${f},height=${y},left=${L},top=${M},resizable=yes,scrollbars=no`);if(!g){console.error("Failed to open popup window. Check if popups are blocked.");return}g.__CHAT_CONFIG__=t,g.document.write(ge(t)),g.document.close(),o.current=g,W=g,r(!0),V(!0,t.tenantId)},[t,n]),p=c.useCallback(()=>{o.current&&!o.current.closed&&o.current.close(),o.current=null,W=null,r(!1),V(!1,t.tenantId)},[t.tenantId]),h=c.useCallback(()=>{o.current&&!o.current.closed&&o.current.focus()},[]);return{isPoppedOut:a,openPopout:i,closePopout:p,focusPopout:h}}function ge(t){const n=t.messages.map(s=>({...s,timestamp:s.timestamp.toISOString()}));return`
1
+ (function(){"use strict";try{if(typeof document<"u"){var r=document.createElement("style");r.appendChild(document.createTextNode(':root{--gcw-color-white: #fff;--gcw-color-gray-50: #f9fafb;--gcw-color-gray-100: #f3f4f6;--gcw-color-gray-200: #e5e7eb;--gcw-color-gray-300: #d1d5db;--gcw-color-gray-400: #9ca3af;--gcw-color-gray-500: #6b7280;--gcw-color-gray-600: #4b5563;--gcw-color-gray-700: #374151;--gcw-color-gray-800: #1f2937;--gcw-color-gray-900: #111827;--gcw-color-primary: #3b82f6;--gcw-color-primary-hover: #2563eb;--gcw-color-primary-light: #eff6ff;--gcw-color-error: #ef4444;--gcw-color-success: #22c55e;--gcw-font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--gcw-font-size-xs: .625rem;--gcw-font-size-sm: .75rem;--gcw-font-size-base: .875rem;--gcw-font-size-lg: 1rem;--gcw-spacing-1: .25rem;--gcw-spacing-2: .5rem;--gcw-spacing-3: .75rem;--gcw-spacing-4: 1rem;--gcw-spacing-6: 1.5rem;--gcw-spacing-8: 2rem;--gcw-spacing-10: 2.5rem;--gcw-spacing-12: 3rem;--gcw-spacing-16: 4rem;--gcw-spacing-20: 5rem;--gcw-radius-sm: .25rem;--gcw-radius-md: .5rem;--gcw-radius-lg: .75rem;--gcw-radius-xl: 1rem;--gcw-radius-2xl: 1.25rem;--gcw-radius-full: 9999px;--gcw-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .05);--gcw-shadow-md: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--gcw-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--gcw-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--gcw-shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / .25);--gcw-transition-fast: .15s ease;--gcw-transition-base: .2s ease;--gcw-transition-slow: .3s ease;--gcw-z-widget: 9999}.gcw-widget,.gcw-widget *,.gcw-widget *:before,.gcw-widget *:after{box-sizing:border-box;margin:0;padding:0;font-family:var(--gcw-font-family);line-height:1.5}.gcw-widget{font-family:var(--gcw-font-family);font-size:var(--gcw-font-size-base);line-height:1.5;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:var(--gcw-color-gray-800);text-align:left;letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;text-shadow:none;font-weight:400;font-style:normal}.gcw-container{position:fixed;z-index:var(--gcw-z-widget);display:flex;gap:var(--gcw-spacing-4)}.gcw-container--bottom-right{right:var(--gcw-spacing-4);bottom:var(--gcw-spacing-4);flex-direction:column-reverse;align-items:flex-end}.gcw-container--bottom-left{left:var(--gcw-spacing-4);bottom:var(--gcw-spacing-4);flex-direction:column-reverse;align-items:flex-start}.gcw-container--top-right{right:var(--gcw-spacing-4);top:var(--gcw-spacing-4);flex-direction:column;align-items:flex-end}.gcw-container--top-left{left:var(--gcw-spacing-4);top:var(--gcw-spacing-4);flex-direction:column;align-items:flex-start}.gcw-toggle{position:relative;width:3.5rem;height:3.5rem;border:none;border-radius:var(--gcw-radius-full);background-color:var(--gcw-color-primary);color:var(--gcw-color-white);cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:var(--gcw-shadow-lg);transition:transform var(--gcw-transition-base),box-shadow var(--gcw-transition-base)}.gcw-toggle:hover{transform:scale(1.1);box-shadow:var(--gcw-shadow-xl)}.gcw-toggle:active{transform:scale(.95)}.gcw-toggle__icon{width:1.5rem;height:1.5rem;transition:transform var(--gcw-transition-slow)}.gcw-toggle__badge{position:absolute;top:-.25rem;right:-.25rem;width:1rem;height:1rem;border-radius:var(--gcw-radius-full);display:flex;align-items:center;justify-content:center;font-size:var(--gcw-font-size-xs);font-weight:700;animation:gcw-pulse 2s infinite}.gcw-toggle__badge--unread{background-color:var(--gcw-color-error);color:var(--gcw-color-white)}.gcw-toggle__badge--popout{background-color:var(--gcw-color-success)}.gcw-window{display:flex;flex-direction:column;background-color:var(--gcw-color-white);border-radius:var(--gcw-radius-2xl);box-shadow:var(--gcw-shadow-2xl);border:1px solid var(--gcw-color-gray-200);overflow:hidden;animation:gcw-slide-up var(--gcw-transition-slow) ease-out}.gcw-window--small{width:320px;height:450px}.gcw-window--medium{width:380px;height:560px}.gcw-window--large{width:480px;height:680px}.gcw-window--fullscreen{width:calc(100vw - 2rem);height:calc(100vh - 6rem);max-width:56rem}.gcw-window{max-height:90vh;transition:width var(--gcw-transition-base),height var(--gcw-transition-base)}.gcw-header{display:flex;align-items:center;justify-content:space-between;padding:var(--gcw-spacing-3) var(--gcw-spacing-4);color:var(--gcw-color-white);flex-shrink:0}.gcw-header__left{display:flex;align-items:center;gap:var(--gcw-spacing-3)}.gcw-header__avatar{width:2.5rem;height:2.5rem;border-radius:var(--gcw-radius-full);background-color:#fff3;display:flex;align-items:center;justify-content:center}.gcw-header__avatar-icon{width:1.25rem;height:1.25rem}.gcw-header__info{display:flex;flex-direction:column;min-width:0;flex:1}.gcw-header__title{font-size:var(--gcw-font-size-base);font-weight:600;line-height:1.4;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gcw-header__subtitle{font-size:var(--gcw-font-size-sm);font-weight:400;line-height:1.4;opacity:.9;margin:0;word-wrap:break-word;overflow-wrap:break-word}.gcw-header__actions{display:flex;align-items:center;gap:.125rem}.gcw-header__btn{width:2rem;height:2rem;border:none;border-radius:var(--gcw-radius-full);background-color:transparent;color:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color var(--gcw-transition-fast)}.gcw-header__btn:hover{background-color:#fff3}.gcw-header__btn-icon{width:1rem;height:1rem}.gcw-messages{flex:1;overflow-y:auto;padding:var(--gcw-spacing-4);display:flex;flex-direction:column;gap:var(--gcw-spacing-4)}.gcw-messages::-webkit-scrollbar{width:6px}.gcw-messages::-webkit-scrollbar-track{background:transparent}.gcw-messages::-webkit-scrollbar-thumb{background-color:var(--gcw-color-gray-300);border-radius:3px}.gcw-messages::-webkit-scrollbar-thumb:hover{background-color:var(--gcw-color-gray-400)}.gcw-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--gcw-spacing-6);color:var(--gcw-color-gray-400);text-align:center}.gcw-empty__icon{width:4rem;height:4rem;margin-bottom:var(--gcw-spacing-4);opacity:.5}.gcw-empty__text{font-size:var(--gcw-font-size-base);font-weight:400;line-height:1.5;margin:0}.gcw-session-loading{display:flex;flex-direction:column;align-items:center;gap:var(--gcw-spacing-3)}.gcw-session-loading__spinner{width:2rem;height:2rem;border:3px solid var(--gcw-color-gray-200);border-top-color:var(--gcw-color-primary);border-radius:50%;animation:gcw-spin .8s linear infinite}@keyframes gcw-spin{to{transform:rotate(360deg)}}.gcw-bubble-row{display:flex}.gcw-bubble-row--user{justify-content:flex-end}.gcw-bubble-row--assistant{justify-content:flex-start}.gcw-bubble-wrapper{max-width:85%;display:flex;flex-direction:column}.gcw-bubble-wrapper--user{align-items:flex-end}.gcw-bubble-wrapper--assistant{align-items:flex-start}.gcw-bubble{padding:var(--gcw-spacing-2) var(--gcw-spacing-4);border-radius:var(--gcw-radius-2xl);font-size:var(--gcw-font-size-base);font-weight:400;line-height:1.6;letter-spacing:normal;word-wrap:break-word}.gcw-bubble--user{color:var(--gcw-color-white);border-bottom-right-radius:var(--gcw-radius-sm)}.gcw-bubble--assistant{background-color:var(--gcw-color-gray-100);color:var(--gcw-color-gray-800);border-bottom-left-radius:var(--gcw-radius-sm)}.gcw-bubble__timestamp{font-size:var(--gcw-font-size-xs);color:var(--gcw-color-gray-400);margin-top:var(--gcw-spacing-1);padding:0 var(--gcw-spacing-1)}.gcw-content p{margin-bottom:var(--gcw-spacing-2)}.gcw-content p:last-child{margin-bottom:0}.gcw-content strong{font-weight:600}.gcw-content em{font-style:italic}.gcw-content ul,.gcw-content ol{margin:var(--gcw-spacing-2) 0;padding-left:var(--gcw-spacing-6)}.gcw-content li{margin-bottom:var(--gcw-spacing-1)}.gcw-content code{background-color:#0000001a;padding:.125rem .375rem;border-radius:var(--gcw-radius-sm);font-size:.875em;font-family:SF Mono,Monaco,Consolas,monospace}.gcw-bubble--user .gcw-content code{background-color:#fff3}.gcw-content pre{background-color:var(--gcw-color-gray-800);color:var(--gcw-color-gray-100);padding:var(--gcw-spacing-3);border-radius:var(--gcw-radius-md);overflow-x:auto;margin:var(--gcw-spacing-2) 0}.gcw-content pre code{background-color:transparent;padding:0;font-size:var(--gcw-font-size-sm)}.gcw-content a{color:var(--gcw-color-primary);text-decoration:underline}.gcw-content a:hover{color:var(--gcw-color-primary-hover)}.gcw-bubble--user .gcw-content a{color:#ffffffe6}.gcw-md-heading{font-weight:600;margin-top:var(--gcw-spacing-3);margin-bottom:var(--gcw-spacing-1)}.gcw-md-heading--h2{font-size:var(--gcw-font-size-lg);font-weight:700}.gcw-md-heading--h3,.gcw-md-heading--h4{font-size:var(--gcw-font-size-base)}.gcw-md-heading--h5{font-size:var(--gcw-font-size-sm)}.gcw-md-paragraph{margin-bottom:var(--gcw-spacing-2)}.gcw-md-paragraph:last-child{margin-bottom:0}.gcw-md-list{margin:var(--gcw-spacing-2) 0;padding-left:var(--gcw-spacing-4)}.gcw-md-list--ul{list-style-type:disc}.gcw-md-list--ol{list-style-type:decimal}.gcw-md-list__item{font-size:var(--gcw-font-size-base);margin-bottom:var(--gcw-spacing-1)}.gcw-md-bold{font-weight:600}.gcw-md-italic{font-style:italic}.gcw-md-code{background-color:var(--gcw-color-gray-200);padding:.125rem var(--gcw-spacing-2);border-radius:var(--gcw-radius-sm);font-size:var(--gcw-font-size-sm);font-family:SF Mono,Monaco,Consolas,monospace}.gcw-bubble--user .gcw-md-code{background-color:#fff3}.gcw-md-code-block{background-color:var(--gcw-color-gray-800);color:var(--gcw-color-gray-100);padding:var(--gcw-spacing-3);border-radius:var(--gcw-radius-lg);font-size:var(--gcw-font-size-sm);overflow-x:auto;margin:var(--gcw-spacing-2) 0}.gcw-md-code-block code{font-family:SF Mono,Monaco,Consolas,monospace}.gcw-md-link{color:var(--gcw-color-primary);text-decoration:underline}.gcw-md-link:hover{color:var(--gcw-color-primary-hover)}.gcw-bubble--user .gcw-md-link{color:#ffffffe6}.gcw-sources{display:flex;flex-wrap:wrap;gap:var(--gcw-spacing-2);margin-top:var(--gcw-spacing-2)}.gcw-source{display:inline-flex;align-items:center;gap:var(--gcw-spacing-1);padding:var(--gcw-spacing-1) var(--gcw-spacing-2);border-radius:var(--gcw-radius-full);background-color:var(--gcw-color-primary-light);color:var(--gcw-color-primary);font-size:var(--gcw-font-size-sm);text-decoration:none;transition:background-color var(--gcw-transition-fast)}.gcw-source:hover{background-color:#dbeafe}.gcw-source__icon{width:.75rem;height:.75rem}.gcw-typing{display:flex;justify-content:flex-start}.gcw-typing__bubble{background-color:var(--gcw-color-gray-100);padding:var(--gcw-spacing-3) var(--gcw-spacing-4);border-radius:var(--gcw-radius-2xl);border-bottom-left-radius:var(--gcw-radius-sm)}.gcw-typing__dots{display:flex;gap:var(--gcw-spacing-1)}.gcw-typing__dot{width:.5rem;height:.5rem;background-color:var(--gcw-color-gray-400);border-radius:var(--gcw-radius-full);animation:gcw-typing-bounce 1.4s infinite ease-in-out both}.gcw-typing__dot:nth-child(1){animation-delay:-.32s}.gcw-typing__dot:nth-child(2){animation-delay:-.16s}.gcw-input-area{padding:var(--gcw-spacing-3);border-top:1px solid var(--gcw-color-gray-200);background-color:var(--gcw-color-white);flex-shrink:0}.gcw-input-row{display:flex;align-items:flex-end;gap:var(--gcw-spacing-2)}.gcw-input{flex:1;min-height:44px;max-height:120px;padding:var(--gcw-spacing-2) var(--gcw-spacing-4);border:1px solid var(--gcw-color-gray-200);border-radius:var(--gcw-radius-xl);background-color:var(--gcw-color-white);color:var(--gcw-color-gray-800);font-family:var(--gcw-font-family);font-size:var(--gcw-font-size-base);font-weight:400;line-height:1.5;letter-spacing:normal;resize:none;outline:none;transition:border-color var(--gcw-transition-fast),box-shadow var(--gcw-transition-fast)}.gcw-input:focus{border-color:var(--gcw-color-primary);box-shadow:0 0 0 3px #3b82f61a}.gcw-input:disabled{background-color:var(--gcw-color-gray-50);cursor:not-allowed}.gcw-input::placeholder{color:var(--gcw-color-gray-400)}.gcw-send-btn{width:2.5rem;height:2.5rem;flex-shrink:0;border:none;border-radius:var(--gcw-radius-lg);color:var(--gcw-color-white);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:opacity var(--gcw-transition-fast),transform var(--gcw-transition-fast)}.gcw-send-btn:hover:not(:disabled){opacity:.9}.gcw-send-btn:active:not(:disabled){transform:scale(.95)}.gcw-send-btn:disabled{opacity:.5;cursor:not-allowed}.gcw-send-btn__icon{width:1.25rem;height:1.25rem}.gcw-input-hint{font-size:var(--gcw-font-size-xs);color:var(--gcw-color-gray-400);text-align:center;margin-top:var(--gcw-spacing-2)}@keyframes gcw-slide-up{0%{opacity:0;transform:translateY(1rem)}to{opacity:1;transform:translateY(0)}}@keyframes gcw-pulse{0%,to{opacity:1}50%{opacity:.5}}@keyframes gcw-typing-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}@keyframes gcw-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.gcw-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.gcw-spin{animation:gcw-spin 1s linear infinite}')),document.head.appendChild(r)}}catch(o){console.error("vite-plugin-css-injected-by-js",o)}})();
2
+ (function(x,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],e):(x=typeof globalThis<"u"?globalThis:x||self,e(x.GeoAppsChatWidget={},x.React,x.React))})(this,function(x,e,l){"use strict";const le="gcw_session_",ce="gcw_popout_",de="gcw_read_";function K(t){return`${le}${t||"default"}`}function ue(t,n){try{const s=K(n);t?localStorage.setItem(s,t):localStorage.removeItem(s)}catch(s){console.warn("Failed to save session ID:",s)}}function pe(t){try{return localStorage.getItem(K(t))}catch{return null}}function Y(t){try{localStorage.removeItem(K(t)),localStorage.removeItem(q(t))}catch(n){console.warn("Failed to clear session:",n)}}function he(t,n){const s=K(t),i=r=>{r.key===s&&n(r.newValue)};return window.addEventListener("storage",i),()=>window.removeEventListener("storage",i)}function Q(t){return`${ce}${t||"default"}`}function G(t,n){try{t?localStorage.setItem(Q(n),"true"):localStorage.removeItem(Q(n))}catch(s){console.warn("Failed to save popout state:",s)}}function ge(t){try{return localStorage.getItem(Q(t))==="true"}catch{return!1}}function q(t){return`${de}${t||"default"}`}function Z(t,n){try{t?localStorage.setItem(q(n),t):localStorage.removeItem(q(n))}catch(s){console.warn("Failed to save read state:",s)}}function me(t){try{return localStorage.getItem(q(t))}catch{return null}}function se(t){const{apiUrl:n,tenantId:s,sessionId:i,headers:r={},onError:o,persist:a=!0}=t,[m,u]=l.useState([]),[d,M]=l.useState(!1),[C,S]=l.useState(!1),[B,f]=l.useState(null),[g,N]=l.useState(()=>i||(a?pe(s):null)),P=l.useRef(null),F=l.useRef(!1),X=l.useCallback(()=>n.replace(/\/chat(\/stream)?\/?$/,""),[n]),L=l.useCallback(async E=>{S(!0);try{const b=X(),_=await fetch(`${b}/sessions/${E}`,{method:"GET",headers:{"Content-Type":"application/json",...s&&{"X-Tenant-ID":s},...r}});if(_.status===404)return console.info("Session not found, starting fresh"),a&&Y(s),N(null),!1;if(!_.ok)throw new Error(`Failed to load session: ${_.status}`);const T=(await _.json()).messages.map(p=>{var y;return{id:p.id,role:p.role,content:p.content,timestamp:new Date(p.timestamp),sources:(y=p.citations)==null?void 0:y.map(h=>({title:h.title,url:h.url,relevance:h.relevance_score}))}});return u(T),N(E),!0}catch(b){return console.error("Failed to load session:",b),a&&Y(s),N(null),!1}finally{S(!1)}},[X,s,r,a]);l.useEffect(()=>{F.current||(F.current=!0,g&&L(g))},[]),l.useEffect(()=>{a&&ue(g,s)},[g,s,a]),l.useEffect(()=>a?he(s,b=>{b&&b!==g?L(b):b||(u([]),N(null))}):void 0,[s,a,g,L]);const w=l.useCallback(async E=>{var T;if(!E.trim()||d)return;P.current&&P.current.abort(),P.current=new AbortController;const b={id:`temp_${Date.now()}`,role:"user",content:E.trim(),timestamp:new Date};u(p=>[...p,b]),M(!0),f(null);const _=`temp_${Date.now()}_assistant`,W={id:_,role:"assistant",content:"",timestamp:new Date,isStreaming:!0};u(p=>[...p,W]);try{const p=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",...s&&{"X-Tenant-ID":s},...r},body:JSON.stringify({message:E.trim(),session_id:g}),signal:P.current.signal});if(!p.ok){const h=await p.json().catch(()=>({}));throw new Error(h.detail||`Request failed with status ${p.status}`)}const y=p.headers.get("content-type");if(y!=null&&y.includes("text/event-stream"))await R(p,_);else{const h=await p.json(),I=(T=h.message.citations)==null?void 0:T.map($=>({title:$.title,url:$.url,relevance:$.relevance_score}));u($=>$.map(z=>z.id===_?{...z,content:h.message.content,isStreaming:!1,sources:I}:z)),h.session_id&&N(h.session_id)}}catch(p){if(p.name==="AbortError")return;const y=p instanceof Error?p:new Error("An error occurred");f(y),o==null||o(y),u(h=>h.map(I=>I.id===_?{...I,content:"Sorry, an error occurred. Please try again.",isStreaming:!1}:I))}finally{M(!1),P.current=null}},[n,s,g,r,d,o]),R=async(E,b)=>{var y;const _=(y=E.body)==null?void 0:y.getReader();if(!_)throw new Error("No response body");const W=new TextDecoder;let T="",p="";try{for(;;){const{done:h,value:I}=await _.read();if(h)break;p+=W.decode(I,{stream:!0});const $=p.split(`
3
+
4
+ `);p=$.pop()||"";for(const z of $){if(!z.trim())continue;const te=z.split(`
5
+ `);let V="",O="";for(const v of te)v.startsWith("event: ")?V=v.slice(7).trim():v.startsWith("data: ")&&(O=v.slice(6));if(!(!V||!O))try{const v=JSON.parse(O);switch(V){case"connected":v.session_id&&N(v.session_id);break;case"content_delta":v.content&&(T+=v.content,u(D=>D.map(c=>c.id===b?{...c,content:T}:c)));break;case"citations":if(v.citations){const D=v.citations.map(c=>({title:c.title,url:c.url,relevance:c.relevance_score}));u(c=>c.map(k=>k.id===b?{...k,sources:D}:k))}break;case"done":break;case"error":v.message&&u(D=>D.map(c=>c.id===b?{...c,content:v.message}:c));break;case"no_answer":u(D=>D.map(c=>c.id===b?{...c,content:v.message||"I could not find an answer to your question."}:c));break}}catch(v){O&&O!=="[DONE]"&&console.warn("Failed to parse SSE data:",v)}}}}finally{u(h=>h.map(I=>I.id===b?{...I,isStreaming:!1}:I))}},ee=l.useCallback(()=>{u([]),N(null),f(null),F.current=!1,a&&Y(s)},[a,s]);return{messages:m,isLoading:d,isLoadingSession:C,error:B,sendMessage:w,clearMessages:ee,sessionId:g}}let A=null;function fe(t,n,s){const[i,r]=l.useState(()=>ge(t.tenantId)),o=l.useRef(A);l.useEffect(()=>{if(i&&!o.current){const d=window.open("","GeoAppsChatPopout");d&&d.location.href!=="about:blank"&&!d.closed?(o.current=d,A=d):(r(!1),G(!1,t.tenantId))}},[i,t.tenantId]),l.useEffect(()=>{if(!o.current)return;const d=setInterval(()=>{var M;(M=o.current)!=null&&M.closed&&(r(!1),o.current=null,A=null,G(!1,t.tenantId))},500);return()=>clearInterval(d)},[t.tenantId,s]);const a=l.useCallback(()=>{if(o.current&&!o.current.closed){o.current.focus();return}const d={small:{width:380,height:520},medium:{width:440,height:660},large:{width:560,height:780},fullscreen:{width:700,height:800}},{width:M,height:C}=d[n],S=(window.screen.width-M)/2,B=(window.screen.height-C)/2,f=window.open("","GeoAppsChatPopout",`width=${M},height=${C},left=${S},top=${B},resizable=yes,scrollbars=no`);if(!f){console.error("Failed to open popup window. Check if popups are blocked.");return}f.__CHAT_CONFIG__=t,f.document.write(we(t)),f.document.close(),o.current=f,A=f,r(!0),G(!0,t.tenantId)},[t,n]),m=l.useCallback(()=>{o.current&&!o.current.closed&&o.current.close(),o.current=null,A=null,r(!1),G(!1,t.tenantId)},[t.tenantId]),u=l.useCallback(()=>{o.current&&!o.current.closed&&o.current.focus()},[]);return{isPoppedOut:i,openPopout:a,closePopout:m,focusPopout:u}}function we(t){const n=t.messages.map(s=>({...s,timestamp:s.timestamp.toISOString()}));return`
4
6
  <!DOCTYPE html>
5
7
  <html lang="en">
6
8
  <head>
7
9
  <meta charset="UTF-8">
8
10
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
9
- <title>${F(t.title)}</title>
11
+ <title>${J(t.title)}</title>
10
12
  <style>
11
13
  * { margin: 0; padding: 0; box-sizing: border-box; }
12
14
  html, body, #chat-root { height: 100%; width: 100%; }
@@ -305,8 +307,8 @@
305
307
  </svg>
306
308
  </div>
307
309
  <div class="popout-header-info">
308
- <div class="popout-title">${F(t.title)}</div>
309
- <div class="popout-subtitle">${F(t.subtitle)}</div>
310
+ <div class="popout-title">${J(t.title)}</div>
311
+ <div class="popout-subtitle">${J(t.subtitle)}</div>
310
312
  </div>
311
313
  <div class="popout-header-actions">
312
314
  <button class="popout-header-btn" id="clear-btn" title="Verwijder chatgeschiedenis">
@@ -322,7 +324,7 @@
322
324
  <textarea
323
325
  class="popout-textarea"
324
326
  id="message-input"
325
- placeholder="${F(t.placeholder)}"
327
+ placeholder="${J(t.placeholder)}"
326
328
  rows="1"
327
329
  ></textarea>
328
330
  <button
@@ -593,6 +595,6 @@
593
595
  <\/script>
594
596
  </body>
595
597
  </html>
596
- `}function F(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function me({content:t,className:n}){if(!t)return null;const s=fe(t);return e.jsx("div",{className:n,children:s.map((a,r)=>e.jsx(c.Fragment,{children:a},r))})}function fe(t){const n=t.split(`
597
- `),s=[];let a=null;const r=()=>{a&&(a.type==="ul"?s.push(e.jsx("ul",{className:"gcw-md-list gcw-md-list--ul",children:a.items.map((o,i)=>e.jsx("li",{className:"gcw-md-list__item",children:o},i))},`list-${s.length}`)):s.push(e.jsx("ol",{className:"gcw-md-list gcw-md-list--ol",children:a.items.map((o,i)=>e.jsx("li",{className:"gcw-md-list__item",children:o},i))},`list-${s.length}`)),a=null)};for(let o=0;o<n.length;o++){const i=n[o];if(i.startsWith("#### ")){r(),s.push(e.jsx("h5",{className:"gcw-md-heading gcw-md-heading--h5",children:z(i.slice(5))},o));continue}if(i.startsWith("### ")){r(),s.push(e.jsx("h4",{className:"gcw-md-heading gcw-md-heading--h4",children:z(i.slice(4))},o));continue}if(i.startsWith("## ")){r(),s.push(e.jsx("h3",{className:"gcw-md-heading gcw-md-heading--h3",children:z(i.slice(3))},o));continue}if(i.startsWith("# ")){r(),s.push(e.jsx("h2",{className:"gcw-md-heading gcw-md-heading--h2",children:z(i.slice(2))},o));continue}const p=i.match(/^[\s]*[-*•]\s+(.+)/);if(p){(!a||a.type!=="ul")&&(r(),a={type:"ul",items:[]}),a.items.push(z(p[1]));continue}const h=i.match(/^[\s]*(\d+)[.)]\s+(.+)/);if(h){(!a||a.type!=="ol")&&(r(),a={type:"ol",items:[]}),a.items.push(z(h[2]));continue}if(i.startsWith("```")){r();const l=[];for(o++;o<n.length&&!n[o].startsWith("```");)l.push(n[o]),o++;s.push(e.jsx("pre",{className:"gcw-md-code-block",children:e.jsx("code",{children:l.join(`
598
- `)})},`code-${s.length}`));continue}if(i.trim()===""){r();continue}r(),s.push(e.jsx("p",{className:"gcw-md-paragraph",children:z(i)},o))}return r(),s}function z(t){if(!t)return null;const n=[];let s=t,a=0;for(;s.length>0;){const r=s.match(/^\*\*(.+?)\*\*/);if(r){n.push(e.jsx("strong",{className:"gcw-md-bold",children:r[1]},a++)),s=s.slice(r[0].length);continue}const o=s.match(/^\*([^*]+?)\*/);if(o){n.push(e.jsx("em",{className:"gcw-md-italic",children:o[1]},a++)),s=s.slice(o[0].length);continue}const i=s.match(/^`([^`]+)`/);if(i){n.push(e.jsx("code",{className:"gcw-md-code",children:i[1]},a++)),s=s.slice(i[0].length);continue}const p=s.match(/^\[([^\]]+)\]\(([^)]+)\)/);if(p){n.push(e.jsx("a",{href:p[2],target:"_blank",rel:"noopener noreferrer",className:"gcw-md-link",children:p[1]},a++)),s=s.slice(p[0].length);continue}const h=s.search(/[\*`\[]/);if(h===-1){n.push(s);break}else h===0?(n.push(s[0]),s=s.slice(1)):(n.push(s.slice(0,h)),s=s.slice(h))}return n.length===1?n[0]:n}function we(){return e.jsxs("div",{className:"gcw-typing__dots",children:[e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"})]})}function be({className:t}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"})})}function ve(t){return t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function ye(t,n){return t.length<=n?t:t.slice(0,n-3)+"..."}function te({message:t,primaryColor:n}){const s=t.role==="user",a=s?"user":"assistant";return e.jsx("div",{className:`gcw-bubble-row gcw-bubble-row--${a}`,children:e.jsxs("div",{className:`gcw-bubble-wrapper gcw-bubble-wrapper--${a}`,children:[e.jsx("div",{className:`gcw-bubble gcw-bubble--${a}`,style:s?{backgroundColor:n}:void 0,children:t.isStreaming&&!t.content?e.jsx(we,{}):e.jsx(me,{content:t.content,className:"gcw-content"})}),t.sources&&t.sources.length>0&&e.jsx("div",{className:"gcw-sources",children:t.sources.slice(0,3).map((r,o)=>e.jsxs("a",{href:r.url,target:"_blank",rel:"noopener noreferrer",className:"gcw-source",children:[e.jsx(be,{className:"gcw-source__icon"}),ye(r.title,25)]},o))}),e.jsx("span",{className:"gcw-bubble__timestamp",children:ve(t.timestamp)})]})})}function ke(){return e.jsx("div",{className:"gcw-typing",children:e.jsx("div",{className:"gcw-typing__bubble",children:e.jsxs("div",{className:"gcw-typing__dots",children:[e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"})]})})})}function se({messages:t,isLoading:n,primaryColor:s}){var r;const a=c.useRef(null);return c.useEffect(()=>{var o;(o=a.current)==null||o.scrollIntoView({behavior:"smooth"})},[t,n]),t.length===0&&!n?e.jsxs("div",{className:"gcw-empty",children:[e.jsx("svg",{className:"gcw-empty__icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1.5,d:"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"})}),e.jsx("p",{className:"gcw-empty__text",children:"Begin een gesprek door hieronder een bericht te typen"})]}):e.jsxs("div",{className:"gcw-messages",children:[t.map(o=>e.jsx(te,{message:o,primaryColor:s},o.id)),n&&((r=t[t.length-1])==null?void 0:r.role)!=="assistant"&&e.jsx(ke,{}),e.jsx("div",{ref:a})]})}function ne({placeholder:t,isLoading:n,onSendMessage:s,primaryColor:a}){const[r,o]=c.useState(""),i=c.useRef(null);c.useEffect(()=>{const l=i.current;l&&(l.style.height="auto",l.style.height=`${Math.min(l.scrollHeight,120)}px`)},[r]);const p=()=>{r.trim()&&!n&&(s(r),o(""),i.current&&(i.current.style.height="auto"))},h=l=>{l.key==="Enter"&&!l.shiftKey&&(l.preventDefault(),p())};return e.jsxs("div",{className:"gcw-input-area",children:[e.jsxs("div",{className:"gcw-input-row",children:[e.jsx("textarea",{ref:i,value:r,onChange:l=>o(l.target.value),onKeyDown:h,placeholder:t,disabled:n,rows:1,className:"gcw-input"}),e.jsx("button",{onClick:p,disabled:!r.trim()||n,className:"gcw-send-btn",style:{backgroundColor:a},title:"Verstuur bericht",children:n?e.jsxs("svg",{className:"gcw-send-btn__icon gcw-spin",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{style:{opacity:.25},cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{style:{opacity:.75},fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}):e.jsx("svg",{className:"gcw-send-btn__icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 19l9 2-9-18-9 18 9-2zm0 0v-8"})})})]}),e.jsx("p",{className:"gcw-input-hint",children:"Druk op Enter om te verzenden, Shift+Enter voor een nieuwe regel"})]})}function xe({size:t,className:n="gcw-w-4 gcw-h-4"}){switch(t){case"small":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"})});case"medium":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"})});case"large":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"})});case"fullscreen":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25"})})}}function Me({className:t="gcw-w-4 gcw-h-4"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})})}function _e({className:t="gcw-w-4 gcw-h-4"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})}function Se({className:t="gcw-w-4 gcw-h-4"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"})})}function Ie({className:t="gcw-w-6 gcw-h-6"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"})})}const Ce={small:"gcw-window--small",medium:"gcw-window--medium",large:"gcw-window--large",fullscreen:"gcw-window--fullscreen"};function oe({title:t,subtitle:n,placeholder:s,messages:a,isLoading:r,onSendMessage:o,onClose:i,onClear:p,onSizeChange:h,onPopout:l,primaryColor:f,size:y}){const L=()=>{const M=["small","medium","large","fullscreen"],w=(M.indexOf(y)+1)%M.length;h(M[w])};return e.jsxs("div",{className:`gcw-window ${Ce[y]}`,children:[e.jsxs("div",{className:"gcw-header",style:{backgroundColor:f},children:[e.jsxs("div",{className:"gcw-header__left",children:[e.jsx("div",{className:"gcw-header__avatar",children:e.jsx(Ie,{className:"gcw-header__avatar-icon"})}),e.jsxs("div",{className:"gcw-header__info",children:[e.jsx("h3",{className:"gcw-header__title",children:t}),e.jsx("p",{className:"gcw-header__subtitle",children:n})]})]}),e.jsxs("div",{className:"gcw-header__actions",children:[e.jsx("button",{onClick:L,className:"gcw-header__btn",title:`Grootte: ${y} (klik om te wisselen)`,children:e.jsx(xe,{size:y,className:"gcw-header__btn-icon"})}),e.jsx("button",{onClick:l,className:"gcw-header__btn",title:"Open in new window",children:e.jsx(Me,{className:"gcw-header__btn-icon"})}),e.jsx("button",{onClick:p,className:"gcw-header__btn",title:"Verwijder chatgeschiedenis",children:e.jsx(Se,{className:"gcw-header__btn-icon"})}),e.jsx("button",{onClick:i,className:"gcw-header__btn",title:"Sluiten",children:e.jsx(_e,{className:"gcw-header__btn-icon"})})]})]}),e.jsx(se,{messages:a,isLoading:r,primaryColor:f}),e.jsx(ne,{placeholder:s,isLoading:r,onSendMessage:o,primaryColor:f})]})}function re({isOpen:t,onClick:n,primaryColor:s,hasUnread:a,isPoppedOut:r}){return e.jsxs("button",{onClick:n,className:"gcw-toggle",style:{backgroundColor:s},title:r?"Chat is open in een ander venster":t?"Sluit chat":"Open chat",children:[a&&!t&&e.jsx("span",{className:"gcw-toggle__badge gcw-toggle__badge--unread",children:"!"}),r&&e.jsx("span",{className:"gcw-toggle__badge gcw-toggle__badge--popout"}),e.jsx("div",{className:"gcw-toggle__icon",children:r?e.jsx("svg",{fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})}):t?e.jsx("svg",{fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})}):e.jsx("svg",{fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"})})})]})}function Ne({apiUrl:t,tenantId:n,title:s="Chat Assistent",subtitle:a="Hoe kan ik je helpen?",placeholder:r="Typ een bericht...",greeting:o,primaryColor:i="#3b82f6",position:p="bottom-right",defaultOpen:h=!1,defaultSize:l="medium",headers:f,onOpen:y,onClose:L,onMessageSent:M,onResponseReceived:g}){const[w,j]=c.useState(h),[P,X]=c.useState(l),[Q,E]=c.useState(!1),{messages:d,isLoading:S,sendMessage:T,clearMessages:O,sessionId:D}=ee({apiUrl:t,tenantId:n,headers:f}),[u,k]=c.useState(()=>d.length>0),[m,I]=c.useState([]);c.useEffect(()=>{w&&o&&!u&&d.length===0&&k(!0)},[w,o,u,d.length]),c.useEffect(()=>{d.length>0&&k(!0)},[d.length]),c.useEffect(()=>{u&&o&&d.length===0?I([{id:"greeting",role:"assistant",content:o,timestamp:new Date}]):o&&d.length>0?I([{id:"greeting",role:"assistant",content:o,timestamp:new Date},...d]):I(d)},[d,u,o]);const{isPoppedOut:x,openPopout:B,focusPopout:K}=he({apiUrl:t,tenantId:n,title:s,subtitle:a,placeholder:r,primaryColor:i,sessionId:D,messages:m,headers:f},P,()=>{});c.useEffect(()=>{if(w||x){const b=[...d].reverse().find(_=>!_.isStreaming&&_.content);b&&q(b.id,n),E(!1)}else{const b=d.filter(N=>!N.isStreaming&&N.content),_=pe(n);if(b.length===0){E(!1);return}if(!_){E(b.some(N=>N.role==="assistant"));return}const A=b.findIndex(N=>N.id===_);if(A===-1){E(b.some(N=>N.role==="assistant"));return}const $e=b.slice(A+1).some(N=>N.role==="assistant");E($e)}},[w,x,d,n]);const C=()=>{if(x){K();return}const b=!w;if(j(b),b){y==null||y();const _=[...d].reverse().find(A=>!A.isStreaming&&A.content);_&&q(_.id,n),E(!1)}else L==null||L()},H=async b=>{M==null||M(b),await T(b);const _=d[d.length-1];(_==null?void 0:_.role)==="assistant"&&(g==null||g(_.content))},$=()=>{O(),k(!1),I([]),E(!1),q(null,n)},Le=b=>{X(b)},Ee=()=>{j(!1),B()},Te=`gcw-container--${p}`;return e.jsxs("div",{className:`gcw-widget gcw-container ${Te}`,children:[e.jsx(re,{isOpen:w,onClick:C,primaryColor:i,hasUnread:Q&&!w&&!x,isPoppedOut:x}),w&&!x&&e.jsx(oe,{title:s,subtitle:a,placeholder:r,messages:m,isLoading:S,onSendMessage:H,onClose:C,onClear:$,onSizeChange:Le,onPopout:Ee,primaryColor:i,size:P})]})}v.ChatBubble=te,v.ChatWidget=Ne,v.ChatWindow=oe,v.MessageInput=ne,v.MessageList=se,v.ToggleButton=re,v.useChat=ee,Object.defineProperty(v,Symbol.toStringTag,{value:"Module"})});
598
+ `}function J(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function be({content:t,className:n}){if(!t)return null;const s=ve(t);return e.jsx("div",{className:n,children:s.map((i,r)=>e.jsx(l.Fragment,{children:i},r))})}function ve(t){const n=t.split(`
599
+ `),s=[];let i=null;const r=()=>{i&&(i.type==="ul"?s.push(e.jsx("ul",{className:"gcw-md-list gcw-md-list--ul",children:i.items.map((o,a)=>e.jsx("li",{className:"gcw-md-list__item",children:o},a))},`list-${s.length}`)):s.push(e.jsx("ol",{className:"gcw-md-list gcw-md-list--ol",children:i.items.map((o,a)=>e.jsx("li",{className:"gcw-md-list__item",children:o},a))},`list-${s.length}`)),i=null)};for(let o=0;o<n.length;o++){const a=n[o];if(a.startsWith("#### ")){r(),s.push(e.jsx("h5",{className:"gcw-md-heading gcw-md-heading--h5",children:H(a.slice(5))},o));continue}if(a.startsWith("### ")){r(),s.push(e.jsx("h4",{className:"gcw-md-heading gcw-md-heading--h4",children:H(a.slice(4))},o));continue}if(a.startsWith("## ")){r(),s.push(e.jsx("h3",{className:"gcw-md-heading gcw-md-heading--h3",children:H(a.slice(3))},o));continue}if(a.startsWith("# ")){r(),s.push(e.jsx("h2",{className:"gcw-md-heading gcw-md-heading--h2",children:H(a.slice(2))},o));continue}const m=a.match(/^[\s]*[-*•]\s+(.+)/);if(m){(!i||i.type!=="ul")&&(r(),i={type:"ul",items:[]}),i.items.push(H(m[1]));continue}const u=a.match(/^[\s]*(\d+)[.)]\s+(.+)/);if(u){(!i||i.type!=="ol")&&(r(),i={type:"ol",items:[]}),i.items.push(H(u[2]));continue}if(a.startsWith("```")){r();const d=[];for(o++;o<n.length&&!n[o].startsWith("```");)d.push(n[o]),o++;s.push(e.jsx("pre",{className:"gcw-md-code-block",children:e.jsx("code",{children:d.join(`
600
+ `)})},`code-${s.length}`));continue}if(a.trim()===""){r();continue}r(),s.push(e.jsx("p",{className:"gcw-md-paragraph",children:H(a)},o))}return r(),s}function H(t){if(!t)return null;const n=[];let s=t,i=0;for(;s.length>0;){const r=s.match(/^\*\*(.+?)\*\*/);if(r){n.push(e.jsx("strong",{className:"gcw-md-bold",children:r[1]},i++)),s=s.slice(r[0].length);continue}const o=s.match(/^\*([^*]+?)\*/);if(o){n.push(e.jsx("em",{className:"gcw-md-italic",children:o[1]},i++)),s=s.slice(o[0].length);continue}const a=s.match(/^`([^`]+)`/);if(a){n.push(e.jsx("code",{className:"gcw-md-code",children:a[1]},i++)),s=s.slice(a[0].length);continue}const m=s.match(/^\[([^\]]+)\]\(([^)]+)\)/);if(m){n.push(e.jsx("a",{href:m[2],target:"_blank",rel:"noopener noreferrer",className:"gcw-md-link",children:m[1]},i++)),s=s.slice(m[0].length);continue}const u=s.search(/[\*`\[]/);if(u===-1){n.push(s);break}else u===0?(n.push(s[0]),s=s.slice(1)):(n.push(s.slice(0,u)),s=s.slice(u))}return n.length===1?n[0]:n}function ye(){return e.jsxs("div",{className:"gcw-typing__dots",children:[e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"})]})}function ke({className:t}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"})})}function xe(t){return t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function _e(t,n){return t.length<=n?t:t.slice(0,n-3)+"..."}function ne({message:t,primaryColor:n}){const s=t.role==="user",i=s?"user":"assistant";return e.jsx("div",{className:`gcw-bubble-row gcw-bubble-row--${i}`,children:e.jsxs("div",{className:`gcw-bubble-wrapper gcw-bubble-wrapper--${i}`,children:[e.jsx("div",{className:`gcw-bubble gcw-bubble--${i}`,style:s?{backgroundColor:n}:void 0,children:t.isStreaming&&!t.content?e.jsx(ye,{}):e.jsx(be,{content:t.content,className:"gcw-content"})}),t.sources&&t.sources.length>0&&e.jsx("div",{className:"gcw-sources",children:t.sources.slice(0,3).map((r,o)=>e.jsxs("a",{href:r.url,target:"_blank",rel:"noopener noreferrer",className:"gcw-source",children:[e.jsx(ke,{className:"gcw-source__icon"}),_e(r.title,25)]},o))}),e.jsx("span",{className:"gcw-bubble__timestamp",children:xe(t.timestamp)})]})})}function Me(){return e.jsx("div",{className:"gcw-typing",children:e.jsx("div",{className:"gcw-typing__bubble",children:e.jsxs("div",{className:"gcw-typing__dots",children:[e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"}),e.jsx("span",{className:"gcw-typing__dot"})]})})})}function oe({messages:t,isLoading:n,isLoadingSession:s=!1,primaryColor:i}){var o;const r=l.useRef(null);return l.useEffect(()=>{var a;(a=r.current)==null||a.scrollIntoView({behavior:"smooth"})},[t,n]),s?e.jsx("div",{className:"gcw-empty",children:e.jsxs("div",{className:"gcw-session-loading",children:[e.jsx("div",{className:"gcw-session-loading__spinner"}),e.jsx("p",{className:"gcw-empty__text",children:"Chatgeschiedenis laden..."})]})}):t.length===0&&!n?e.jsxs("div",{className:"gcw-empty",children:[e.jsx("svg",{className:"gcw-empty__icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1.5,d:"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"})}),e.jsx("p",{className:"gcw-empty__text",children:"Begin een gesprek door hieronder een bericht te typen"})]}):e.jsxs("div",{className:"gcw-messages",children:[t.map(a=>e.jsx(ne,{message:a,primaryColor:i},a.id)),n&&((o=t[t.length-1])==null?void 0:o.role)!=="assistant"&&e.jsx(Me,{}),e.jsx("div",{ref:r})]})}function re({placeholder:t,isLoading:n,onSendMessage:s,primaryColor:i}){const[r,o]=l.useState(""),a=l.useRef(null);l.useEffect(()=>{const d=a.current;d&&(d.style.height="auto",d.style.height=`${Math.min(d.scrollHeight,120)}px`)},[r]);const m=()=>{r.trim()&&!n&&(s(r),o(""),a.current&&(a.current.style.height="auto"))},u=d=>{d.key==="Enter"&&!d.shiftKey&&(d.preventDefault(),m())};return e.jsxs("div",{className:"gcw-input-area",children:[e.jsxs("div",{className:"gcw-input-row",children:[e.jsx("textarea",{ref:a,value:r,onChange:d=>o(d.target.value),onKeyDown:u,placeholder:t,disabled:n,rows:1,className:"gcw-input"}),e.jsx("button",{onClick:m,disabled:!r.trim()||n,className:"gcw-send-btn",style:{backgroundColor:i},title:"Verstuur bericht",children:n?e.jsxs("svg",{className:"gcw-send-btn__icon gcw-spin",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{style:{opacity:.25},cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{style:{opacity:.75},fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}):e.jsx("svg",{className:"gcw-send-btn__icon",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 19l9 2-9-18-9 18 9-2zm0 0v-8"})})})]}),e.jsx("p",{className:"gcw-input-hint",children:"Druk op Enter om te verzenden, Shift+Enter voor een nieuwe regel"})]})}function Se({size:t,className:n="gcw-w-4 gcw-h-4"}){switch(t){case"small":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"})});case"medium":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"})});case"large":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"})});case"fullscreen":return e.jsx("svg",{className:n,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25"})})}}function Ie({className:t="gcw-w-4 gcw-h-4"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})})}function Ce({className:t="gcw-w-4 gcw-h-4"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})}function Ne({className:t="gcw-w-4 gcw-h-4"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"})})}function Le({className:t="gcw-w-6 gcw-h-6"}){return e.jsx("svg",{className:t,fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"})})}const Ee={small:"gcw-window--small",medium:"gcw-window--medium",large:"gcw-window--large",fullscreen:"gcw-window--fullscreen"};function ae({title:t,subtitle:n,placeholder:s,messages:i,isLoading:r,isLoadingSession:o=!1,onSendMessage:a,onClose:m,onClear:u,onSizeChange:d,onPopout:M,primaryColor:C,size:S}){const B=()=>{const f=["small","medium","large","fullscreen"],N=(f.indexOf(S)+1)%f.length;d(f[N])};return e.jsxs("div",{className:`gcw-window ${Ee[S]}`,children:[e.jsxs("div",{className:"gcw-header",style:{backgroundColor:C},children:[e.jsxs("div",{className:"gcw-header__left",children:[e.jsx("div",{className:"gcw-header__avatar",children:e.jsx(Le,{className:"gcw-header__avatar-icon"})}),e.jsxs("div",{className:"gcw-header__info",children:[e.jsx("h3",{className:"gcw-header__title",children:t}),e.jsx("p",{className:"gcw-header__subtitle",children:n})]})]}),e.jsxs("div",{className:"gcw-header__actions",children:[e.jsx("button",{onClick:B,className:"gcw-header__btn",title:`Grootte: ${S} (klik om te wisselen)`,children:e.jsx(Se,{size:S,className:"gcw-header__btn-icon"})}),e.jsx("button",{onClick:M,className:"gcw-header__btn",title:"Open in new window",children:e.jsx(Ie,{className:"gcw-header__btn-icon"})}),e.jsx("button",{onClick:u,className:"gcw-header__btn",title:"Verwijder chatgeschiedenis",children:e.jsx(Ne,{className:"gcw-header__btn-icon"})}),e.jsx("button",{onClick:m,className:"gcw-header__btn",title:"Sluiten",children:e.jsx(Ce,{className:"gcw-header__btn-icon"})})]})]}),e.jsx(oe,{messages:i,isLoading:r,isLoadingSession:o,primaryColor:C}),e.jsx(re,{placeholder:s,isLoading:r,onSendMessage:a,primaryColor:C})]})}function ie({isOpen:t,onClick:n,primaryColor:s,hasUnread:i,isPoppedOut:r}){return e.jsxs("button",{onClick:n,className:"gcw-toggle",style:{backgroundColor:s},title:r?"Chat is open in een ander venster":t?"Sluit chat":"Open chat",children:[i&&!t&&e.jsx("span",{className:"gcw-toggle__badge gcw-toggle__badge--unread",children:"!"}),r&&e.jsx("span",{className:"gcw-toggle__badge gcw-toggle__badge--popout"}),e.jsx("div",{className:"gcw-toggle__icon",children:r?e.jsx("svg",{fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})}):t?e.jsx("svg",{fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})}):e.jsx("svg",{fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"})})})]})}function Te({apiUrl:t,tenantId:n,title:s="Chat Assistent",subtitle:i="Hoe kan ik je helpen?",placeholder:r="Typ een bericht...",greeting:o,primaryColor:a="#3b82f6",position:m="bottom-right",defaultOpen:u=!1,defaultSize:d="medium",headers:M,onOpen:C,onClose:S,onMessageSent:B,onResponseReceived:f}){const[g,N]=l.useState(u),[P,F]=l.useState(d),[X,L]=l.useState(!1),{messages:w,isLoading:R,isLoadingSession:ee,sendMessage:E,clearMessages:b,sessionId:_}=se({apiUrl:t,tenantId:n,headers:M}),[W,T]=l.useState(()=>w.length>0),[p,y]=l.useState([]);l.useEffect(()=>{g&&o&&!W&&w.length===0&&T(!0)},[g,o,W,w.length]),l.useEffect(()=>{w.length>0&&T(!0)},[w.length]),l.useEffect(()=>{W&&o&&w.length===0?y([{id:"greeting",role:"assistant",content:o,timestamp:new Date}]):o&&w.length>0?y([{id:"greeting",role:"assistant",content:o,timestamp:new Date},...w]):y(w)},[w,W,o]);const{isPoppedOut:h,openPopout:I,focusPopout:$}=fe({apiUrl:t,tenantId:n,title:s,subtitle:i,placeholder:r,primaryColor:a,sessionId:_,messages:p,headers:M},P,()=>{});l.useEffect(()=>{if(g||h){const c=[...w].reverse().find(k=>!k.isStreaming&&k.content);c&&Z(c.id,n),L(!1)}else{const c=w.filter(j=>!j.isStreaming&&j.content),k=me(n);if(c.length===0){L(!1);return}if(!k){L(c.some(j=>j.role==="assistant"));return}const U=c.findIndex(j=>j.id===k);if(U===-1){L(c.some(j=>j.role==="assistant"));return}const $e=c.slice(U+1).some(j=>j.role==="assistant");L($e)}},[g,h,w,n]);const z=()=>{if(h){$();return}const c=!g;if(N(c),c){C==null||C();const k=[...w].reverse().find(U=>!U.isStreaming&&U.content);k&&Z(k.id,n),L(!1)}else S==null||S()},te=async c=>{B==null||B(c),await E(c);const k=w[w.length-1];(k==null?void 0:k.role)==="assistant"&&(f==null||f(k.content))},V=()=>{b(),T(!1),y([]),L(!1),Z(null,n)},O=c=>{F(c)},v=()=>{N(!1),I()},D=`gcw-container--${m}`;return e.jsxs("div",{className:`gcw-widget gcw-container ${D}`,children:[e.jsx(ie,{isOpen:g,onClick:z,primaryColor:a,hasUnread:X&&!g&&!h,isPoppedOut:h}),g&&!h&&e.jsx(ae,{title:s,subtitle:i,placeholder:r,messages:p,isLoading:R,isLoadingSession:ee,onSendMessage:te,onClose:z,onClear:V,onSizeChange:O,onPopout:v,primaryColor:a,size:P})]})}x.ChatBubble=ne,x.ChatWidget=Te,x.ChatWindow=ae,x.MessageInput=re,x.MessageList=oe,x.ToggleButton=ie,x.useChat=se,Object.defineProperty(x,Symbol.toStringTag,{value:"Module"})});
@@ -8,10 +8,16 @@ interface UseChatOptions extends ChatConfig {
8
8
  interface UseChatReturn {
9
9
  messages: Message[];
10
10
  isLoading: boolean;
11
+ isLoadingSession: boolean;
11
12
  error: Error | null;
12
13
  sendMessage: (content: string) => Promise<void>;
13
14
  clearMessages: () => void;
14
15
  sessionId: string | null;
15
16
  }
17
+ /**
18
+ * Custom hook for chat functionality with backend session management.
19
+ * Messages are stored in the backend (Redis) - this is the source of truth.
20
+ * localStorage only stores the sessionId for reconnection.
21
+ */
16
22
  export declare function useChat(options: UseChatOptions): UseChatReturn;
17
23
  export {};
package/dist/types.d.ts CHANGED
@@ -68,3 +68,26 @@ export interface StreamChunk {
68
68
  sources?: Source[];
69
69
  error?: string;
70
70
  }
71
+ /**
72
+ * Response from GET /sessions/{id} endpoint
73
+ */
74
+ export interface SessionResponse {
75
+ id: string;
76
+ organization_id: string;
77
+ user_id: string;
78
+ messages: Array<{
79
+ id: string;
80
+ role: 'user' | 'assistant';
81
+ content: string;
82
+ timestamp: string;
83
+ citations?: Array<{
84
+ title: string;
85
+ url: string;
86
+ relevance_score?: number;
87
+ }>;
88
+ }>;
89
+ title: string | null;
90
+ created_at: string;
91
+ updated_at: string;
92
+ message_count: number;
93
+ }
@@ -1,27 +1,22 @@
1
1
  import { Message } from '../types';
2
2
 
3
3
  /**
4
- * Save chat state to localStorage
4
+ * Save session ID to localStorage
5
+ * Messages are stored in the backend (Redis) - this is the source of truth
5
6
  */
6
- export declare function saveChatState(messages: Message[], sessionId: string | null, tenantId?: string): void;
7
+ export declare function saveSessionId(sessionId: string | null, tenantId?: string): void;
7
8
  /**
8
- * Load chat state from localStorage
9
+ * Load session ID from localStorage
9
10
  */
10
- export declare function loadChatState(tenantId?: string): {
11
- messages: Message[];
12
- sessionId: string | null;
13
- } | null;
11
+ export declare function loadSessionId(tenantId?: string): string | null;
14
12
  /**
15
- * Clear chat state from localStorage
13
+ * Clear session from localStorage
16
14
  */
17
- export declare function clearChatState(tenantId?: string): void;
15
+ export declare function clearSession(tenantId?: string): void;
18
16
  /**
19
- * Subscribe to chat state changes from other windows/tabs
17
+ * Subscribe to session ID changes from other windows/tabs
20
18
  */
21
- export declare function subscribeToChatStateChanges(tenantId: string | undefined, onStateChange: (state: {
22
- messages: Message[];
23
- sessionId: string | null;
24
- } | null) => void): () => void;
19
+ export declare function subscribeToSessionChanges(tenantId: string | undefined, onSessionChange: (sessionId: string | null) => void): () => void;
25
20
  /**
26
21
  * Save popout state to localStorage
27
22
  */
@@ -1 +1 @@
1
- export { saveChatState, loadChatState, clearChatState, subscribeToChatStateChanges, savePopoutState, loadPopoutState, saveLastReadMessageId, loadLastReadMessageId, hasUnreadMessages, } from './chatPersistence';
1
+ export { saveSessionId, loadSessionId, clearSession, subscribeToSessionChanges, savePopoutState, loadPopoutState, saveLastReadMessageId, loadLastReadMessageId, hasUnreadMessages, } from './chatPersistence';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cas0570/chat-widget",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Embeddable chat widget for GeoApps documentation assistant. Easy to integrate via npm",
5
5
  "type": "module",
6
6
  "main": "./dist/geoapps-chat-widget.umd.cjs",
@@ -37,6 +37,19 @@
37
37
  "bugs": {
38
38
  "url": "https://github.com/Cas0570/geoapps-chat-widget/issues"
39
39
  },
40
+ "scripts": {
41
+ "dev": "vite",
42
+ "build": "tsc && vite build",
43
+ "build:lib": "tsc && vite build --mode lib",
44
+ "preview": "vite preview",
45
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
46
+ "type-check": "tsc --noEmit",
47
+ "test": "vitest",
48
+ "test:run": "vitest run",
49
+ "test:coverage": "vitest run --coverage",
50
+ "prepublishOnly": "pnpm run build:lib"
51
+ },
52
+ "packageManager": "pnpm@10.28.2",
40
53
  "devDependencies": {
41
54
  "@testing-library/jest-dom": "^6.9.1",
42
55
  "@testing-library/react": "^16.3.2",
@@ -64,16 +77,5 @@
64
77
  },
65
78
  "sideEffects": [
66
79
  "*.css"
67
- ],
68
- "scripts": {
69
- "dev": "vite",
70
- "build": "tsc && vite build",
71
- "build:lib": "tsc && vite build --mode lib",
72
- "preview": "vite preview",
73
- "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
74
- "type-check": "tsc --noEmit",
75
- "test": "vitest",
76
- "test:run": "vitest run",
77
- "test:coverage": "vitest run --coverage"
78
- }
79
- }
80
+ ]
81
+ }