@lookalike/widget 1.0.0-beta.1 → 1.0.0-beta.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/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v="https://your-app-name.up.railway.app",a={WIDGET_READY:"lookalike-widget-ready",WIDGET_RESIZE:"lookalike-widget-resize",SESSION_START:"lookalike-session-start",SESSION_END:"lookalike-session-end",MESSAGE:"lookalike-message",ERROR:"lookalike-error",INIT_CHANNEL:"lookalike-init-channel",COMMAND:"lookalike-command"},S={EXPAND:"expand",COLLAPSE:"collapse"};class E{constructor(e){this.events={},this.iframe=null,this.container=null,this.port=null,this.expanded=!1,this.mounted=!1,this.messageHandler=null,this.config={handle:e.handle,variant:e.variant??"floating",anchor:e.anchor??"bottom-right",collapsible:e.collapsible??!1,modes:e.modes??["text","audio","video"],baseUrl:e.baseUrl??v,theme:e.theme}}on(e,t){return this.events[e]=t,this}off(e){return delete this.events[e],this}mount(e){if(this.mounted){console.warn("LookalikeWidget: Already mounted");return}if(typeof e=="string"){const t=document.querySelector(e);if(!t)throw new Error(`LookalikeWidget: Container "${e}" not found`);this.container=t}else this.container=e;this.iframe=document.createElement("iframe"),this.iframe.src=this.buildIframeUrl(),this.iframe.style.cssText=this.getIframeStyles(),this.iframe.setAttribute("allow","camera; microphone; autoplay"),this.iframe.setAttribute("allowfullscreen",""),this.iframe.onload=()=>{console.log("[Widget] Iframe loaded successfully")},this.iframe.onerror=t=>{console.error("[Widget] Iframe error:",t)},this.messageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.messageHandler),console.log("[Widget] Message listener added"),this.container.appendChild(this.iframe),this.mounted=!0,console.log("[Widget] Iframe mounted, URL:",this.iframe.src)}expand(){this.sendCommand(S.EXPAND)}collapse(){this.sendCommand(S.COLLAPSE)}destroy(){this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.port&&(this.port.close(),this.port=null),this.iframe&&this.container&&(this.container.removeChild(this.iframe),this.iframe=null),this.container=null,this.mounted=!1,this.expanded=!1}isExpanded(){return this.expanded}buildIframeUrl(){const e=new URL(`/${this.config.handle}/chat`,this.config.baseUrl);if(e.searchParams.set("embed",""),e.searchParams.set("variant",this.config.variant),this.config.variant==="floating"&&e.searchParams.set("anchor",this.config.anchor),this.config.variant==="inline"&&this.config.collapsible&&e.searchParams.set("collapsible",""),e.searchParams.set("modes",this.config.modes.join(",")),this.config.theme){const t=[];this.config.theme.primaryColor&&t.push(`primary:${this.config.theme.primaryColor}`),this.config.theme.accentColor&&t.push(`accent:${this.config.theme.accentColor}`),this.config.theme.borderRadius&&t.push(`radius:${this.config.theme.borderRadius}`),t.length>0&&e.searchParams.set("theme",t.join(","))}return e.toString()}getIframeStyles(){if(this.config.variant==="floating"){const e=this.config.anchor;return`
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const v="https://your-app-name.up.railway.app",a={WIDGET_READY:"lookalike-widget-ready",WIDGET_RESIZE:"lookalike-widget-resize",SESSION_START:"lookalike-session-start",SESSION_END:"lookalike-session-end",MESSAGE:"lookalike-message",ERROR:"lookalike-error",INIT_CHANNEL:"lookalike-init-channel",COMMAND:"lookalike-command"},E={EXPAND:"expand",COLLAPSE:"collapse"};class u{constructor(e){this.events={},this.iframe=null,this.container=null,this.port=null,this.expanded=!1,this.mounted=!1,this.messageHandler=null,this.config={handle:e.handle,variant:e.variant??"floating",anchor:e.anchor??"bottom-right",collapsible:e.collapsible??!1,modes:e.modes??["text","audio","video"],baseUrl:e.baseUrl??v,theme:e.theme}}on(e,t){return this.events[e]=t,this}off(e){return delete this.events[e],this}mount(e){if(this.mounted){console.warn("LookalikeWidget: Already mounted");return}if(typeof e=="string"){const t=document.querySelector(e);if(!t)throw new Error(`LookalikeWidget: Container "${e}" not found`);this.container=t}else this.container=e;this.iframe=document.createElement("iframe"),this.iframe.src=this.buildIframeUrl(),this.iframe.style.cssText=this.getIframeStyles(),this.iframe.setAttribute("allow","camera; microphone; autoplay"),this.iframe.setAttribute("allowfullscreen",""),this.iframe.onload=()=>{console.log("[Widget] Iframe loaded successfully")},this.iframe.onerror=t=>{console.error("[Widget] Iframe error:",t)},this.messageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.messageHandler),console.log("[Widget] Message listener added"),this.container.appendChild(this.iframe),this.mounted=!0,console.log("[Widget] Iframe mounted, URL:",this.iframe.src)}expand(){this.sendCommand(E.EXPAND)}collapse(){this.sendCommand(E.COLLAPSE)}destroy(){this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.port&&(this.port.close(),this.port=null),this.iframe&&this.container&&(this.container.removeChild(this.iframe),this.iframe=null),this.container=null,this.mounted=!1,this.expanded=!1}isExpanded(){return this.expanded}buildIframeUrl(){const e=new URL(`/${this.config.handle}/chat`,this.config.baseUrl);if(e.searchParams.set("embed",""),e.searchParams.set("variant",this.config.variant),this.config.variant==="floating"&&e.searchParams.set("anchor",this.config.anchor),this.config.variant==="inline"&&this.config.collapsible&&e.searchParams.set("collapsible",""),e.searchParams.set("modes",this.config.modes.join(",")),this.config.theme){const t=[];this.config.theme.primaryColor&&t.push(`primary:${this.config.theme.primaryColor}`),this.config.theme.accentColor&&t.push(`accent:${this.config.theme.accentColor}`),this.config.theme.borderRadius&&t.push(`radius:${this.config.theme.borderRadius}`),t.length>0&&e.searchParams.set("theme",t.join(","))}return e.toString()}getIframeStyles(){if(this.config.variant==="floating"){const e=this.config.anchor;return`
2
2
  position: fixed;
3
3
  ${{"bottom-right":"bottom: 20px; right: 20px;","bottom-left":"bottom: 20px; left: 20px;","top-right":"top: 20px; right: 20px;","top-left":"top: 20px; left: 20px;"}[e]}
4
4
  width: 380px;
@@ -14,5 +14,5 @@
14
14
  min-height: 400px;
15
15
  border: none;
16
16
  border-radius: 16px;
17
- `.replace(/\s+/g," ").trim()}handleMessage(e){var o,i,n,r,l,h,d,c,m,g,f,p,u;if(console.log("[Widget] Received message:",e.data,"from:",e.source===((o=this.iframe)==null?void 0:o.contentWindow)?"iframe":"unknown"),this.iframe&&e.source!==this.iframe.contentWindow){console.log("[Widget] Ignoring message - not from iframe");return}const{type:t,...s}=e.data||{};switch(t){case a.WIDGET_READY:console.log("[Widget] WIDGET_READY event received!"),this.initMessageChannel(),(n=(i=this.events).onReady)==null||n.call(i);break;case a.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:s.collapsed,expanded:!s.collapsed}),this.expanded=!s.collapsed,this.updateIframeSize(s.collapsed),(l=(r=this.events).onResize)==null||l.call(r,s.collapsed);break;case a.SESSION_START:(d=(h=this.events).onSessionStart)==null||d.call(h,s.mode);break;case a.SESSION_END:(m=(c=this.events).onSessionEnd)==null||m.call(c);break;case a.MESSAGE:(f=(g=this.events).onMessage)==null||f.call(g,s.role,s.content);break;case a.ERROR:(u=(p=this.events).onError)==null||u.call(p,s.code,s.message);break}}initMessageChannel(){var t;if(!((t=this.iframe)!=null&&t.contentWindow))return;const e=new MessageChannel;this.port=e.port1,this.port.onmessage=s=>{var n,r,l,h,d,c,m,g,f,p;console.log("[Widget] Port message received:",s.data);const{type:o,...i}=s.data||{};switch(o){case a.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:i.collapsed,expanded:!i.collapsed}),this.expanded=!i.collapsed,this.updateIframeSize(i.collapsed),(r=(n=this.events).onResize)==null||r.call(n,i.collapsed);break;case a.SESSION_START:(h=(l=this.events).onSessionStart)==null||h.call(l,i.mode);break;case a.SESSION_END:(c=(d=this.events).onSessionEnd)==null||c.call(d);break;case a.MESSAGE:(g=(m=this.events).onMessage)==null||g.call(m,i.role,i.content);break;case a.ERROR:(p=(f=this.events).onError)==null||p.call(f,i.code,i.message);break}},this.iframe.contentWindow.postMessage({type:a.INIT_CHANNEL},"*",[e.port2])}sendCommand(e,t){var o;const s={type:a.COMMAND,action:e,payload:t};this.port?this.port.postMessage(s):(o=this.iframe)!=null&&o.contentWindow&&this.iframe.contentWindow.postMessage(s,"*")}updateIframeSize(e){if(console.log("[Widget] updateIframeSize called:",{collapsed:e,variant:this.config.variant,hasIframe:!!this.iframe}),!this.iframe||this.config.variant!=="floating"){console.log("[Widget] updateIframeSize skipped - no iframe or not floating variant");return}e?(console.log("[Widget] Setting collapsed size: 380x72"),this.iframe.style.width="380px",this.iframe.style.height="72px",this.iframe.style.maxHeight="72px"):(console.log("[Widget] Setting expanded size: 380x520"),this.iframe.style.width="380px",this.iframe.style.height="520px",this.iframe.style.maxHeight="calc(100vh - 40px)")}}exports.LookalikeWidget=E;exports.Widget=E;
17
+ `.replace(/\s+/g," ").trim()}handleMessage(e){var o,i,n,r,l,h,d,c,m,g,f,p,S;if(console.log("[Widget] Received message:",e.data,"from:",e.source===((o=this.iframe)==null?void 0:o.contentWindow)?"iframe":"unknown"),this.iframe&&e.source!==this.iframe.contentWindow){console.log("[Widget] Ignoring message - not from iframe");return}const{type:t,...s}=e.data||{};switch(t){case a.WIDGET_READY:console.log("[Widget] WIDGET_READY event received!"),this.initMessageChannel(),(n=(i=this.events).onReady)==null||n.call(i);break;case a.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:s.collapsed,expanded:!s.collapsed}),this.expanded=!s.collapsed,this.updateIframeSize(s.collapsed),(l=(r=this.events).onResize)==null||l.call(r,s.collapsed);break;case a.SESSION_START:(d=(h=this.events).onSessionStart)==null||d.call(h,s.mode);break;case a.SESSION_END:(m=(c=this.events).onSessionEnd)==null||m.call(c);break;case a.MESSAGE:(f=(g=this.events).onMessage)==null||f.call(g,s.role,s.content);break;case a.ERROR:(S=(p=this.events).onError)==null||S.call(p,s.code,s.message);break}}initMessageChannel(){var t;if(!((t=this.iframe)!=null&&t.contentWindow))return;const e=new MessageChannel;this.port=e.port1,this.port.onmessage=s=>{var n,r,l,h,d,c,m,g,f,p;console.log("[Widget] Port message received:",s.data);const{type:o,...i}=s.data||{};switch(o){case a.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:i.collapsed,expanded:!i.collapsed}),this.expanded=!i.collapsed,this.updateIframeSize(i.collapsed),(r=(n=this.events).onResize)==null||r.call(n,i.collapsed);break;case a.SESSION_START:(h=(l=this.events).onSessionStart)==null||h.call(l,i.mode);break;case a.SESSION_END:(c=(d=this.events).onSessionEnd)==null||c.call(d);break;case a.MESSAGE:(g=(m=this.events).onMessage)==null||g.call(m,i.role,i.content);break;case a.ERROR:(p=(f=this.events).onError)==null||p.call(f,i.code,i.message);break}},this.iframe.contentWindow.postMessage({type:a.INIT_CHANNEL},"*",[e.port2])}sendCommand(e,t){var o;const s={type:a.COMMAND,action:e,payload:t};this.port?this.port.postMessage(s):(o=this.iframe)!=null&&o.contentWindow&&this.iframe.contentWindow.postMessage(s,"*")}updateIframeSize(e){if(console.log("[Widget] updateIframeSize called:",{collapsed:e,variant:this.config.variant,hasIframe:!!this.iframe}),!this.iframe||this.config.variant!=="floating"){console.log("[Widget] updateIframeSize skipped - no iframe or not floating variant");return}e?(console.log("[Widget] Setting collapsed size: 380x72"),this.iframe.style.width="380px",this.iframe.style.height="72px",this.iframe.style.maxHeight="72px"):(console.log("[Widget] Setting expanded size: 380x520"),this.iframe.style.width="380px",this.iframe.style.height="520px",this.iframe.style.maxHeight="calc(100vh - 40px)")}}exports.LookalikeWidget=u;exports.Widget=u;exports.default=u;
18
18
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/widget.ts"],"sourcesContent":["import type {\r\n LookalikeWidgetConfig,\r\n LookalikeWidgetEvents,\r\n LookalikeWidgetInstance,\r\n ChatMode,\r\n} from './types'\r\n\r\n// Use production URL if defined, otherwise fallback to lookalike.com\r\nconst DEFAULT_BASE_URL = typeof __PRODUCTION_BASE_URL__ !== 'undefined' \r\n ? __PRODUCTION_BASE_URL__ \r\n : 'https://lookalike.com'\r\n\r\n// Event type constants\r\nconst EVENTS = {\r\n WIDGET_READY: 'lookalike-widget-ready',\r\n WIDGET_RESIZE: 'lookalike-widget-resize',\r\n SESSION_START: 'lookalike-session-start',\r\n SESSION_END: 'lookalike-session-end',\r\n MESSAGE: 'lookalike-message',\r\n ERROR: 'lookalike-error',\r\n INIT_CHANNEL: 'lookalike-init-channel',\r\n COMMAND: 'lookalike-command',\r\n} as const\r\n\r\n// Command constants\r\nconst COMMANDS = {\r\n EXPAND: 'expand',\r\n COLLAPSE: 'collapse',\r\n} as const\r\n\r\n/**\r\n * Lookalike Widget - Embed conversational AI in your website\r\n *\r\n * @example\r\n * ```javascript\r\n * const widget = new LookalikeWidget({\r\n * handle: 'john-doe',\r\n * variant: 'floating',\r\n * theme: { primaryColor: '#3b82f6' }\r\n * });\r\n *\r\n * widget.on('ready', () => console.log('Widget ready'));\r\n * widget.on('message', (role, content) => console.log(`${role}: ${content}`));\r\n *\r\n * widget.mount(document.body);\r\n * ```\r\n */\r\nexport class LookalikeWidget implements LookalikeWidgetInstance {\r\n private config: Required<Omit<LookalikeWidgetConfig, 'theme'>> & { theme?: LookalikeWidgetConfig['theme'] }\r\n private events: LookalikeWidgetEvents = {}\r\n private iframe: HTMLIFrameElement | null = null\r\n private container: HTMLElement | null = null\r\n private port: MessagePort | null = null\r\n private expanded = false\r\n private mounted = false\r\n private messageHandler: ((e: MessageEvent) => void) | null = null\r\n\r\n constructor(config: LookalikeWidgetConfig) {\r\n this.config = {\r\n handle: config.handle,\r\n variant: config.variant ?? 'floating',\r\n anchor: config.anchor ?? 'bottom-right',\r\n collapsible: config.collapsible ?? false,\r\n modes: config.modes ?? ['text', 'audio', 'video'],\r\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\r\n theme: config.theme,\r\n }\r\n }\r\n\r\n /**\r\n * Register an event handler\r\n */\r\n on<K extends keyof LookalikeWidgetEvents>(\r\n event: K,\r\n handler: NonNullable<LookalikeWidgetEvents[K]>\r\n ): this {\r\n this.events[event] = handler as LookalikeWidgetEvents[K]\r\n return this\r\n }\r\n\r\n /**\r\n * Remove an event handler\r\n */\r\n off<K extends keyof LookalikeWidgetEvents>(event: K): this {\r\n delete this.events[event]\r\n return this\r\n }\r\n\r\n /**\r\n * Mount the widget to a container element\r\n */\r\n mount(container: string | HTMLElement): void {\r\n if (this.mounted) {\r\n console.warn('LookalikeWidget: Already mounted')\r\n return\r\n }\r\n\r\n // Resolve container\r\n if (typeof container === 'string') {\r\n const el = document.querySelector(container)\r\n if (!el) {\r\n throw new Error(`LookalikeWidget: Container \"${container}\" not found`)\r\n }\r\n this.container = el as HTMLElement\r\n } else {\r\n this.container = container\r\n }\r\n\r\n // Create iframe\r\n this.iframe = document.createElement('iframe')\r\n this.iframe.src = this.buildIframeUrl()\r\n this.iframe.style.cssText = this.getIframeStyles()\r\n this.iframe.setAttribute('allow', 'camera; microphone; autoplay')\r\n this.iframe.setAttribute('allowfullscreen', '')\r\n \r\n // Add load event listener for debugging\r\n this.iframe.onload = () => {\r\n console.log('[Widget] Iframe loaded successfully')\r\n }\r\n this.iframe.onerror = (error) => {\r\n console.error('[Widget] Iframe error:', error)\r\n }\r\n\r\n // Set up message listener for handshake\r\n this.messageHandler = this.handleMessage.bind(this)\r\n window.addEventListener('message', this.messageHandler)\r\n console.log('[Widget] Message listener added')\r\n\r\n // Append iframe\r\n this.container.appendChild(this.iframe)\r\n this.mounted = true\r\n console.log('[Widget] Iframe mounted, URL:', this.iframe.src)\r\n }\r\n\r\n /**\r\n * Expand the widget\r\n */\r\n expand(): void {\r\n this.sendCommand(COMMANDS.EXPAND)\r\n }\r\n\r\n /**\r\n * Collapse the widget\r\n */\r\n collapse(): void {\r\n this.sendCommand(COMMANDS.COLLAPSE)\r\n }\r\n\r\n /**\r\n * Destroy the widget and clean up\r\n */\r\n destroy(): void {\r\n if (this.messageHandler) {\r\n window.removeEventListener('message', this.messageHandler)\r\n this.messageHandler = null\r\n }\r\n\r\n if (this.port) {\r\n this.port.close()\r\n this.port = null\r\n }\r\n\r\n if (this.iframe && this.container) {\r\n this.container.removeChild(this.iframe)\r\n this.iframe = null\r\n }\r\n\r\n this.container = null\r\n this.mounted = false\r\n this.expanded = false\r\n }\r\n\r\n /**\r\n * Check if widget is currently expanded\r\n */\r\n isExpanded(): boolean {\r\n return this.expanded\r\n }\r\n\r\n private buildIframeUrl(): string {\r\n const url = new URL(`/${this.config.handle}/chat`, this.config.baseUrl)\r\n\r\n // Add embed flag\r\n url.searchParams.set('embed', '')\r\n\r\n // Add variant\r\n url.searchParams.set('variant', this.config.variant)\r\n\r\n // Add anchor for floating\r\n if (this.config.variant === 'floating') {\r\n url.searchParams.set('anchor', this.config.anchor)\r\n }\r\n\r\n // Add collapsible for inline\r\n if (this.config.variant === 'inline' && this.config.collapsible) {\r\n url.searchParams.set('collapsible', '')\r\n }\r\n\r\n // Add modes\r\n url.searchParams.set('modes', this.config.modes.join(','))\r\n\r\n // Add theme\r\n if (this.config.theme) {\r\n const themeParts: string[] = []\r\n if (this.config.theme.primaryColor) {\r\n themeParts.push(`primary:${this.config.theme.primaryColor}`)\r\n }\r\n if (this.config.theme.accentColor) {\r\n themeParts.push(`accent:${this.config.theme.accentColor}`)\r\n }\r\n if (this.config.theme.borderRadius) {\r\n themeParts.push(`radius:${this.config.theme.borderRadius}`)\r\n }\r\n if (themeParts.length > 0) {\r\n url.searchParams.set('theme', themeParts.join(','))\r\n }\r\n }\r\n\r\n return url.toString()\r\n }\r\n\r\n private getIframeStyles(): string {\r\n if (this.config.variant === 'floating') {\r\n // Floating: positioned in corner, needs to resize based on collapsed state\r\n const anchor = this.config.anchor\r\n const position = {\r\n 'bottom-right': 'bottom: 20px; right: 20px;',\r\n 'bottom-left': 'bottom: 20px; left: 20px;',\r\n 'top-right': 'top: 20px; right: 20px;',\r\n 'top-left': 'top: 20px; left: 20px;',\r\n }[anchor]\r\n\r\n return `\r\n position: fixed;\r\n ${position}\r\n width: 380px;\r\n height: 72px;\r\n max-height: 72px;\r\n border: none;\r\n border-radius: 16px;\r\n z-index: 9999;\r\n transition: all 0.3s ease;\r\n `.replace(/\\s+/g, ' ').trim()\r\n }\r\n\r\n // Inline: fills container\r\n return `\r\n width: 100%;\r\n height: 100%;\r\n min-height: 400px;\r\n border: none;\r\n border-radius: 16px;\r\n `.replace(/\\s+/g, ' ').trim()\r\n }\r\n\r\n private handleMessage(e: MessageEvent): void {\r\n console.log('[Widget] Received message:', e.data, 'from:', e.source === this.iframe?.contentWindow ? 'iframe' : 'unknown')\r\n // Only accept messages from our iframe\r\n if (this.iframe && e.source !== this.iframe.contentWindow) {\r\n console.log('[Widget] Ignoring message - not from iframe')\r\n return\r\n }\r\n\r\n const { type, ...payload } = e.data || {}\r\n\r\n switch (type) {\r\n case EVENTS.WIDGET_READY:\r\n console.log('[Widget] WIDGET_READY event received!')\r\n this.initMessageChannel()\r\n this.events.onReady?.()\r\n break\r\n\r\n case EVENTS.WIDGET_RESIZE:\r\n console.log('[Widget] Received resize event:', { collapsed: payload.collapsed, expanded: !payload.collapsed })\r\n this.expanded = !payload.collapsed\r\n this.updateIframeSize(payload.collapsed)\r\n this.events.onResize?.(payload.collapsed)\r\n break\r\n\r\n case EVENTS.SESSION_START:\r\n this.events.onSessionStart?.(payload.mode as ChatMode)\r\n break\r\n\r\n case EVENTS.SESSION_END:\r\n this.events.onSessionEnd?.()\r\n break\r\n\r\n case EVENTS.MESSAGE:\r\n this.events.onMessage?.(payload.role, payload.content)\r\n break\r\n\r\n case EVENTS.ERROR:\r\n this.events.onError?.(payload.code, payload.message)\r\n break\r\n }\r\n }\r\n\r\n private initMessageChannel(): void {\r\n if (!this.iframe?.contentWindow) return\r\n\r\n // Create a MessageChannel for secure communication\r\n const channel = new MessageChannel()\r\n this.port = channel.port1\r\n\r\n // Set up port message handler\r\n this.port.onmessage = (e) => {\r\n console.log('[Widget] Port message received:', e.data)\r\n // For MessageChannel, we don't need to check source since the channel is secure\r\n const { type, ...payload } = e.data || {}\r\n \r\n switch (type) {\r\n case EVENTS.WIDGET_RESIZE:\r\n console.log('[Widget] Received resize event:', { collapsed: payload.collapsed, expanded: !payload.collapsed })\r\n this.expanded = !payload.collapsed\r\n this.updateIframeSize(payload.collapsed)\r\n this.events.onResize?.(payload.collapsed)\r\n break\r\n\r\n case EVENTS.SESSION_START:\r\n this.events.onSessionStart?.(payload.mode as ChatMode)\r\n break\r\n\r\n case EVENTS.SESSION_END:\r\n this.events.onSessionEnd?.()\r\n break\r\n\r\n case EVENTS.MESSAGE:\r\n this.events.onMessage?.(payload.role, payload.content)\r\n break\r\n\r\n case EVENTS.ERROR:\r\n this.events.onError?.(payload.code, payload.message)\r\n break\r\n }\r\n }\r\n\r\n // Send port2 to iframe\r\n this.iframe.contentWindow.postMessage(\r\n { type: EVENTS.INIT_CHANNEL },\r\n '*',\r\n [channel.port2]\r\n )\r\n }\r\n\r\n private sendCommand(action: string, payload?: unknown): void {\r\n const message = { type: EVENTS.COMMAND, action, payload }\r\n\r\n if (this.port) {\r\n this.port.postMessage(message)\r\n } else if (this.iframe?.contentWindow) {\r\n this.iframe.contentWindow.postMessage(message, '*')\r\n }\r\n }\r\n\r\n private updateIframeSize(collapsed: boolean): void {\r\n console.log('[Widget] updateIframeSize called:', { collapsed, variant: this.config.variant, hasIframe: !!this.iframe })\r\n if (!this.iframe || this.config.variant !== 'floating') {\r\n console.log('[Widget] updateIframeSize skipped - no iframe or not floating variant')\r\n return\r\n }\r\n\r\n if (collapsed) {\r\n // Match the online widget's collapsed height more closely\r\n console.log('[Widget] Setting collapsed size: 380x72')\r\n this.iframe.style.width = '380px'\r\n this.iframe.style.height = '72px'\r\n this.iframe.style.maxHeight = '72px'\r\n } else {\r\n // Match the online widget's expanded dimensions\r\n console.log('[Widget] Setting expanded size: 380x520')\r\n this.iframe.style.width = '380px'\r\n this.iframe.style.height = '520px'\r\n this.iframe.style.maxHeight = 'calc(100vh - 40px)'\r\n }\r\n }\r\n}\r\n\r\n// Also export as Widget for convenience with UMD\r\nexport { LookalikeWidget as Widget }\r\n"],"names":["DEFAULT_BASE_URL","EVENTS","COMMANDS","LookalikeWidget","config","event","handler","container","el","error","url","themeParts","anchor","_a","type","payload","_c","_b","_e","_d","_g","_f","_i","_h","_k","_j","_m","_l","channel","e","action","message","collapsed"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/widget.ts"],"sourcesContent":["import type {\r\n LookalikeWidgetConfig,\r\n LookalikeWidgetEvents,\r\n LookalikeWidgetInstance,\r\n ChatMode,\r\n} from './types'\r\n\r\n// Use production URL if defined, otherwise fallback to lookalike.com\r\nconst DEFAULT_BASE_URL = typeof __PRODUCTION_BASE_URL__ !== 'undefined' \r\n ? __PRODUCTION_BASE_URL__ \r\n : 'https://lookalike.com'\r\n\r\n// Event type constants\r\nconst EVENTS = {\r\n WIDGET_READY: 'lookalike-widget-ready',\r\n WIDGET_RESIZE: 'lookalike-widget-resize',\r\n SESSION_START: 'lookalike-session-start',\r\n SESSION_END: 'lookalike-session-end',\r\n MESSAGE: 'lookalike-message',\r\n ERROR: 'lookalike-error',\r\n INIT_CHANNEL: 'lookalike-init-channel',\r\n COMMAND: 'lookalike-command',\r\n} as const\r\n\r\n// Command constants\r\nconst COMMANDS = {\r\n EXPAND: 'expand',\r\n COLLAPSE: 'collapse',\r\n} as const\r\n\r\n/**\r\n * Lookalike Widget - Embed conversational AI in your website\r\n *\r\n * @example\r\n * ```javascript\r\n * const widget = new LookalikeWidget({\r\n * handle: 'john-doe',\r\n * variant: 'floating',\r\n * theme: { primaryColor: '#3b82f6' }\r\n * });\r\n *\r\n * widget.on('ready', () => console.log('Widget ready'));\r\n * widget.on('message', (role, content) => console.log(`${role}: ${content}`));\r\n *\r\n * widget.mount(document.body);\r\n * ```\r\n */\r\nexport class LookalikeWidget implements LookalikeWidgetInstance {\r\n private config: Required<Omit<LookalikeWidgetConfig, 'theme'>> & { theme?: LookalikeWidgetConfig['theme'] }\r\n private events: LookalikeWidgetEvents = {}\r\n private iframe: HTMLIFrameElement | null = null\r\n private container: HTMLElement | null = null\r\n private port: MessagePort | null = null\r\n private expanded = false\r\n private mounted = false\r\n private messageHandler: ((e: MessageEvent) => void) | null = null\r\n\r\n constructor(config: LookalikeWidgetConfig) {\r\n this.config = {\r\n handle: config.handle,\r\n variant: config.variant ?? 'floating',\r\n anchor: config.anchor ?? 'bottom-right',\r\n collapsible: config.collapsible ?? false,\r\n modes: config.modes ?? ['text', 'audio', 'video'],\r\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\r\n theme: config.theme,\r\n }\r\n }\r\n\r\n /**\r\n * Register an event handler\r\n */\r\n on<K extends keyof LookalikeWidgetEvents>(\r\n event: K,\r\n handler: NonNullable<LookalikeWidgetEvents[K]>\r\n ): this {\r\n this.events[event] = handler as LookalikeWidgetEvents[K]\r\n return this\r\n }\r\n\r\n /**\r\n * Remove an event handler\r\n */\r\n off<K extends keyof LookalikeWidgetEvents>(event: K): this {\r\n delete this.events[event]\r\n return this\r\n }\r\n\r\n /**\r\n * Mount the widget to a container element\r\n */\r\n mount(container: string | HTMLElement): void {\r\n if (this.mounted) {\r\n console.warn('LookalikeWidget: Already mounted')\r\n return\r\n }\r\n\r\n // Resolve container\r\n if (typeof container === 'string') {\r\n const el = document.querySelector(container)\r\n if (!el) {\r\n throw new Error(`LookalikeWidget: Container \"${container}\" not found`)\r\n }\r\n this.container = el as HTMLElement\r\n } else {\r\n this.container = container\r\n }\r\n\r\n // Create iframe\r\n this.iframe = document.createElement('iframe')\r\n this.iframe.src = this.buildIframeUrl()\r\n this.iframe.style.cssText = this.getIframeStyles()\r\n this.iframe.setAttribute('allow', 'camera; microphone; autoplay')\r\n this.iframe.setAttribute('allowfullscreen', '')\r\n \r\n // Add load event listener for debugging\r\n this.iframe.onload = () => {\r\n console.log('[Widget] Iframe loaded successfully')\r\n }\r\n this.iframe.onerror = (error) => {\r\n console.error('[Widget] Iframe error:', error)\r\n }\r\n\r\n // Set up message listener for handshake\r\n this.messageHandler = this.handleMessage.bind(this)\r\n window.addEventListener('message', this.messageHandler)\r\n console.log('[Widget] Message listener added')\r\n\r\n // Append iframe\r\n this.container.appendChild(this.iframe)\r\n this.mounted = true\r\n console.log('[Widget] Iframe mounted, URL:', this.iframe.src)\r\n }\r\n\r\n /**\r\n * Expand the widget\r\n */\r\n expand(): void {\r\n this.sendCommand(COMMANDS.EXPAND)\r\n }\r\n\r\n /**\r\n * Collapse the widget\r\n */\r\n collapse(): void {\r\n this.sendCommand(COMMANDS.COLLAPSE)\r\n }\r\n\r\n /**\r\n * Destroy the widget and clean up\r\n */\r\n destroy(): void {\r\n if (this.messageHandler) {\r\n window.removeEventListener('message', this.messageHandler)\r\n this.messageHandler = null\r\n }\r\n\r\n if (this.port) {\r\n this.port.close()\r\n this.port = null\r\n }\r\n\r\n if (this.iframe && this.container) {\r\n this.container.removeChild(this.iframe)\r\n this.iframe = null\r\n }\r\n\r\n this.container = null\r\n this.mounted = false\r\n this.expanded = false\r\n }\r\n\r\n /**\r\n * Check if widget is currently expanded\r\n */\r\n isExpanded(): boolean {\r\n return this.expanded\r\n }\r\n\r\n private buildIframeUrl(): string {\r\n const url = new URL(`/${this.config.handle}/chat`, this.config.baseUrl)\r\n\r\n // Add embed flag\r\n url.searchParams.set('embed', '')\r\n\r\n // Add variant\r\n url.searchParams.set('variant', this.config.variant)\r\n\r\n // Add anchor for floating\r\n if (this.config.variant === 'floating') {\r\n url.searchParams.set('anchor', this.config.anchor)\r\n }\r\n\r\n // Add collapsible for inline\r\n if (this.config.variant === 'inline' && this.config.collapsible) {\r\n url.searchParams.set('collapsible', '')\r\n }\r\n\r\n // Add modes\r\n url.searchParams.set('modes', this.config.modes.join(','))\r\n\r\n // Add theme\r\n if (this.config.theme) {\r\n const themeParts: string[] = []\r\n if (this.config.theme.primaryColor) {\r\n themeParts.push(`primary:${this.config.theme.primaryColor}`)\r\n }\r\n if (this.config.theme.accentColor) {\r\n themeParts.push(`accent:${this.config.theme.accentColor}`)\r\n }\r\n if (this.config.theme.borderRadius) {\r\n themeParts.push(`radius:${this.config.theme.borderRadius}`)\r\n }\r\n if (themeParts.length > 0) {\r\n url.searchParams.set('theme', themeParts.join(','))\r\n }\r\n }\r\n\r\n return url.toString()\r\n }\r\n\r\n private getIframeStyles(): string {\r\n if (this.config.variant === 'floating') {\r\n // Floating: positioned in corner, needs to resize based on collapsed state\r\n const anchor = this.config.anchor\r\n const position = {\r\n 'bottom-right': 'bottom: 20px; right: 20px;',\r\n 'bottom-left': 'bottom: 20px; left: 20px;',\r\n 'top-right': 'top: 20px; right: 20px;',\r\n 'top-left': 'top: 20px; left: 20px;',\r\n }[anchor]\r\n\r\n return `\r\n position: fixed;\r\n ${position}\r\n width: 380px;\r\n height: 72px;\r\n max-height: 72px;\r\n border: none;\r\n border-radius: 16px;\r\n z-index: 9999;\r\n transition: all 0.3s ease;\r\n `.replace(/\\s+/g, ' ').trim()\r\n }\r\n\r\n // Inline: fills container\r\n return `\r\n width: 100%;\r\n height: 100%;\r\n min-height: 400px;\r\n border: none;\r\n border-radius: 16px;\r\n `.replace(/\\s+/g, ' ').trim()\r\n }\r\n\r\n private handleMessage(e: MessageEvent): void {\r\n console.log('[Widget] Received message:', e.data, 'from:', e.source === this.iframe?.contentWindow ? 'iframe' : 'unknown')\r\n // Only accept messages from our iframe\r\n if (this.iframe && e.source !== this.iframe.contentWindow) {\r\n console.log('[Widget] Ignoring message - not from iframe')\r\n return\r\n }\r\n\r\n const { type, ...payload } = e.data || {}\r\n\r\n switch (type) {\r\n case EVENTS.WIDGET_READY:\r\n console.log('[Widget] WIDGET_READY event received!')\r\n this.initMessageChannel()\r\n this.events.onReady?.()\r\n break\r\n\r\n case EVENTS.WIDGET_RESIZE:\r\n console.log('[Widget] Received resize event:', { collapsed: payload.collapsed, expanded: !payload.collapsed })\r\n this.expanded = !payload.collapsed\r\n this.updateIframeSize(payload.collapsed)\r\n this.events.onResize?.(payload.collapsed)\r\n break\r\n\r\n case EVENTS.SESSION_START:\r\n this.events.onSessionStart?.(payload.mode as ChatMode)\r\n break\r\n\r\n case EVENTS.SESSION_END:\r\n this.events.onSessionEnd?.()\r\n break\r\n\r\n case EVENTS.MESSAGE:\r\n this.events.onMessage?.(payload.role, payload.content)\r\n break\r\n\r\n case EVENTS.ERROR:\r\n this.events.onError?.(payload.code, payload.message)\r\n break\r\n }\r\n }\r\n\r\n private initMessageChannel(): void {\r\n if (!this.iframe?.contentWindow) return\r\n\r\n // Create a MessageChannel for secure communication\r\n const channel = new MessageChannel()\r\n this.port = channel.port1\r\n\r\n // Set up port message handler\r\n this.port.onmessage = (e) => {\r\n console.log('[Widget] Port message received:', e.data)\r\n // For MessageChannel, we don't need to check source since the channel is secure\r\n const { type, ...payload } = e.data || {}\r\n \r\n switch (type) {\r\n case EVENTS.WIDGET_RESIZE:\r\n console.log('[Widget] Received resize event:', { collapsed: payload.collapsed, expanded: !payload.collapsed })\r\n this.expanded = !payload.collapsed\r\n this.updateIframeSize(payload.collapsed)\r\n this.events.onResize?.(payload.collapsed)\r\n break\r\n\r\n case EVENTS.SESSION_START:\r\n this.events.onSessionStart?.(payload.mode as ChatMode)\r\n break\r\n\r\n case EVENTS.SESSION_END:\r\n this.events.onSessionEnd?.()\r\n break\r\n\r\n case EVENTS.MESSAGE:\r\n this.events.onMessage?.(payload.role, payload.content)\r\n break\r\n\r\n case EVENTS.ERROR:\r\n this.events.onError?.(payload.code, payload.message)\r\n break\r\n }\r\n }\r\n\r\n // Send port2 to iframe\r\n this.iframe.contentWindow.postMessage(\r\n { type: EVENTS.INIT_CHANNEL },\r\n '*',\r\n [channel.port2]\r\n )\r\n }\r\n\r\n private sendCommand(action: string, payload?: unknown): void {\r\n const message = { type: EVENTS.COMMAND, action, payload }\r\n\r\n if (this.port) {\r\n this.port.postMessage(message)\r\n } else if (this.iframe?.contentWindow) {\r\n this.iframe.contentWindow.postMessage(message, '*')\r\n }\r\n }\r\n\r\n private updateIframeSize(collapsed: boolean): void {\r\n console.log('[Widget] updateIframeSize called:', { collapsed, variant: this.config.variant, hasIframe: !!this.iframe })\r\n if (!this.iframe || this.config.variant !== 'floating') {\r\n console.log('[Widget] updateIframeSize skipped - no iframe or not floating variant')\r\n return\r\n }\r\n\r\n if (collapsed) {\r\n // Match the online widget's collapsed height more closely\r\n console.log('[Widget] Setting collapsed size: 380x72')\r\n this.iframe.style.width = '380px'\r\n this.iframe.style.height = '72px'\r\n this.iframe.style.maxHeight = '72px'\r\n } else {\r\n // Match the online widget's expanded dimensions\r\n console.log('[Widget] Setting expanded size: 380x520')\r\n this.iframe.style.width = '380px'\r\n this.iframe.style.height = '520px'\r\n this.iframe.style.maxHeight = 'calc(100vh - 40px)'\r\n }\r\n }\r\n}\r\n\r\n// Also export as Widget for convenience with UMD\r\nexport { LookalikeWidget as Widget }\r\n"],"names":["DEFAULT_BASE_URL","EVENTS","COMMANDS","LookalikeWidget","config","event","handler","container","el","error","url","themeParts","anchor","_a","type","payload","_c","_b","_e","_d","_g","_f","_i","_h","_k","_j","_m","_l","channel","e","action","message","collapsed"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { LookalikeWidget } from './widget';
1
2
  export { LookalikeWidget, Widget } from './widget';
2
3
  export type { LookalikeWidgetConfig, LookalikeWidgetEvents, LookalikeWidgetInstance, LookalikeTheme, WidgetVariant, WidgetAnchor, ChatMode, } from './types';
4
+ export default LookalikeWidget;
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAClD,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,aAAa,EACb,YAAY,EACZ,QAAQ,GACT,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAClD,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,aAAa,EACb,YAAY,EACZ,QAAQ,GACT,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,eAAe,eAAe,CAAA"}
package/dist/index.js CHANGED
@@ -117,7 +117,7 @@ class v {
117
117
  `.replace(/\s+/g, " ").trim();
118
118
  }
119
119
  handleMessage(e) {
120
- var o, i, n, r, l, h, d, c, m, g, f, p, u;
120
+ var o, i, n, r, l, h, d, c, m, f, g, p, u;
121
121
  if (console.log("[Widget] Received message:", e.data, "from:", e.source === ((o = this.iframe) == null ? void 0 : o.contentWindow) ? "iframe" : "unknown"), this.iframe && e.source !== this.iframe.contentWindow) {
122
122
  console.log("[Widget] Ignoring message - not from iframe");
123
123
  return;
@@ -137,7 +137,7 @@ class v {
137
137
  (m = (c = this.events).onSessionEnd) == null || m.call(c);
138
138
  break;
139
139
  case a.MESSAGE:
140
- (f = (g = this.events).onMessage) == null || f.call(g, s.role, s.content);
140
+ (g = (f = this.events).onMessage) == null || g.call(f, s.role, s.content);
141
141
  break;
142
142
  case a.ERROR:
143
143
  (u = (p = this.events).onError) == null || u.call(p, s.code, s.message);
@@ -149,7 +149,7 @@ class v {
149
149
  if (!((t = this.iframe) != null && t.contentWindow)) return;
150
150
  const e = new MessageChannel();
151
151
  this.port = e.port1, this.port.onmessage = (s) => {
152
- var n, r, l, h, d, c, m, g, f, p;
152
+ var n, r, l, h, d, c, m, f, g, p;
153
153
  console.log("[Widget] Port message received:", s.data);
154
154
  const { type: o, ...i } = s.data || {};
155
155
  switch (o) {
@@ -163,10 +163,10 @@ class v {
163
163
  (c = (d = this.events).onSessionEnd) == null || c.call(d);
164
164
  break;
165
165
  case a.MESSAGE:
166
- (g = (m = this.events).onMessage) == null || g.call(m, i.role, i.content);
166
+ (f = (m = this.events).onMessage) == null || f.call(m, i.role, i.content);
167
167
  break;
168
168
  case a.ERROR:
169
- (p = (f = this.events).onError) == null || p.call(f, i.code, i.message);
169
+ (p = (g = this.events).onError) == null || p.call(g, i.code, i.message);
170
170
  break;
171
171
  }
172
172
  }, this.iframe.contentWindow.postMessage(
@@ -190,6 +190,7 @@ class v {
190
190
  }
191
191
  export {
192
192
  v as LookalikeWidget,
193
- v as Widget
193
+ v as Widget,
194
+ v as default
194
195
  };
195
196
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- (function(a,r){typeof exports=="object"&&typeof module<"u"?r(exports):typeof define=="function"&&define.amd?define(["exports"],r):(a=typeof globalThis<"u"?globalThis:a||self,r(a.LookalikeWidget={}))})(this,function(a){"use strict";const r="https://your-app-name.up.railway.app",i={WIDGET_READY:"lookalike-widget-ready",WIDGET_RESIZE:"lookalike-widget-resize",SESSION_START:"lookalike-session-start",SESSION_END:"lookalike-session-end",MESSAGE:"lookalike-message",ERROR:"lookalike-error",INIT_CHANNEL:"lookalike-init-channel",COMMAND:"lookalike-command"},E={EXPAND:"expand",COLLAPSE:"collapse"};class x{constructor(e){this.events={},this.iframe=null,this.container=null,this.port=null,this.expanded=!1,this.mounted=!1,this.messageHandler=null,this.config={handle:e.handle,variant:e.variant??"floating",anchor:e.anchor??"bottom-right",collapsible:e.collapsible??!1,modes:e.modes??["text","audio","video"],baseUrl:e.baseUrl??r,theme:e.theme}}on(e,t){return this.events[e]=t,this}off(e){return delete this.events[e],this}mount(e){if(this.mounted){console.warn("LookalikeWidget: Already mounted");return}if(typeof e=="string"){const t=document.querySelector(e);if(!t)throw new Error(`LookalikeWidget: Container "${e}" not found`);this.container=t}else this.container=e;this.iframe=document.createElement("iframe"),this.iframe.src=this.buildIframeUrl(),this.iframe.style.cssText=this.getIframeStyles(),this.iframe.setAttribute("allow","camera; microphone; autoplay"),this.iframe.setAttribute("allowfullscreen",""),this.iframe.onload=()=>{console.log("[Widget] Iframe loaded successfully")},this.iframe.onerror=t=>{console.error("[Widget] Iframe error:",t)},this.messageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.messageHandler),console.log("[Widget] Message listener added"),this.container.appendChild(this.iframe),this.mounted=!0,console.log("[Widget] Iframe mounted, URL:",this.iframe.src)}expand(){this.sendCommand(E.EXPAND)}collapse(){this.sendCommand(E.COLLAPSE)}destroy(){this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.port&&(this.port.close(),this.port=null),this.iframe&&this.container&&(this.container.removeChild(this.iframe),this.iframe=null),this.container=null,this.mounted=!1,this.expanded=!1}isExpanded(){return this.expanded}buildIframeUrl(){const e=new URL(`/${this.config.handle}/chat`,this.config.baseUrl);if(e.searchParams.set("embed",""),e.searchParams.set("variant",this.config.variant),this.config.variant==="floating"&&e.searchParams.set("anchor",this.config.anchor),this.config.variant==="inline"&&this.config.collapsible&&e.searchParams.set("collapsible",""),e.searchParams.set("modes",this.config.modes.join(",")),this.config.theme){const t=[];this.config.theme.primaryColor&&t.push(`primary:${this.config.theme.primaryColor}`),this.config.theme.accentColor&&t.push(`accent:${this.config.theme.accentColor}`),this.config.theme.borderRadius&&t.push(`radius:${this.config.theme.borderRadius}`),t.length>0&&e.searchParams.set("theme",t.join(","))}return e.toString()}getIframeStyles(){if(this.config.variant==="floating"){const e=this.config.anchor;return`
1
+ (function(a,r){typeof exports=="object"&&typeof module<"u"?r(exports):typeof define=="function"&&define.amd?define(["exports"],r):(a=typeof globalThis<"u"?globalThis:a||self,r(a.LookalikeWidget={}))})(this,function(a){"use strict";const r="https://your-app-name.up.railway.app",i={WIDGET_READY:"lookalike-widget-ready",WIDGET_RESIZE:"lookalike-widget-resize",SESSION_START:"lookalike-session-start",SESSION_END:"lookalike-session-end",MESSAGE:"lookalike-message",ERROR:"lookalike-error",INIT_CHANNEL:"lookalike-init-channel",COMMAND:"lookalike-command"},v={EXPAND:"expand",COLLAPSE:"collapse"};class E{constructor(e){this.events={},this.iframe=null,this.container=null,this.port=null,this.expanded=!1,this.mounted=!1,this.messageHandler=null,this.config={handle:e.handle,variant:e.variant??"floating",anchor:e.anchor??"bottom-right",collapsible:e.collapsible??!1,modes:e.modes??["text","audio","video"],baseUrl:e.baseUrl??r,theme:e.theme}}on(e,t){return this.events[e]=t,this}off(e){return delete this.events[e],this}mount(e){if(this.mounted){console.warn("LookalikeWidget: Already mounted");return}if(typeof e=="string"){const t=document.querySelector(e);if(!t)throw new Error(`LookalikeWidget: Container "${e}" not found`);this.container=t}else this.container=e;this.iframe=document.createElement("iframe"),this.iframe.src=this.buildIframeUrl(),this.iframe.style.cssText=this.getIframeStyles(),this.iframe.setAttribute("allow","camera; microphone; autoplay"),this.iframe.setAttribute("allowfullscreen",""),this.iframe.onload=()=>{console.log("[Widget] Iframe loaded successfully")},this.iframe.onerror=t=>{console.error("[Widget] Iframe error:",t)},this.messageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.messageHandler),console.log("[Widget] Message listener added"),this.container.appendChild(this.iframe),this.mounted=!0,console.log("[Widget] Iframe mounted, URL:",this.iframe.src)}expand(){this.sendCommand(v.EXPAND)}collapse(){this.sendCommand(v.COLLAPSE)}destroy(){this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.port&&(this.port.close(),this.port=null),this.iframe&&this.container&&(this.container.removeChild(this.iframe),this.iframe=null),this.container=null,this.mounted=!1,this.expanded=!1}isExpanded(){return this.expanded}buildIframeUrl(){const e=new URL(`/${this.config.handle}/chat`,this.config.baseUrl);if(e.searchParams.set("embed",""),e.searchParams.set("variant",this.config.variant),this.config.variant==="floating"&&e.searchParams.set("anchor",this.config.anchor),this.config.variant==="inline"&&this.config.collapsible&&e.searchParams.set("collapsible",""),e.searchParams.set("modes",this.config.modes.join(",")),this.config.theme){const t=[];this.config.theme.primaryColor&&t.push(`primary:${this.config.theme.primaryColor}`),this.config.theme.accentColor&&t.push(`accent:${this.config.theme.accentColor}`),this.config.theme.borderRadius&&t.push(`radius:${this.config.theme.borderRadius}`),t.length>0&&e.searchParams.set("theme",t.join(","))}return e.toString()}getIframeStyles(){if(this.config.variant==="floating"){const e=this.config.anchor;return`
2
2
  position: fixed;
3
3
  ${{"bottom-right":"bottom: 20px; right: 20px;","bottom-left":"bottom: 20px; left: 20px;","top-right":"top: 20px; right: 20px;","top-left":"top: 20px; left: 20px;"}[e]}
4
4
  width: 380px;
@@ -14,5 +14,5 @@
14
14
  min-height: 400px;
15
15
  border: none;
16
16
  border-radius: 16px;
17
- `.replace(/\s+/g," ").trim()}handleMessage(e){var n,o,l,h,d,c,m,f,g,p,u,S,v;if(console.log("[Widget] Received message:",e.data,"from:",e.source===((n=this.iframe)==null?void 0:n.contentWindow)?"iframe":"unknown"),this.iframe&&e.source!==this.iframe.contentWindow){console.log("[Widget] Ignoring message - not from iframe");return}const{type:t,...s}=e.data||{};switch(t){case i.WIDGET_READY:console.log("[Widget] WIDGET_READY event received!"),this.initMessageChannel(),(l=(o=this.events).onReady)==null||l.call(o);break;case i.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:s.collapsed,expanded:!s.collapsed}),this.expanded=!s.collapsed,this.updateIframeSize(s.collapsed),(d=(h=this.events).onResize)==null||d.call(h,s.collapsed);break;case i.SESSION_START:(m=(c=this.events).onSessionStart)==null||m.call(c,s.mode);break;case i.SESSION_END:(g=(f=this.events).onSessionEnd)==null||g.call(f);break;case i.MESSAGE:(u=(p=this.events).onMessage)==null||u.call(p,s.role,s.content);break;case i.ERROR:(v=(S=this.events).onError)==null||v.call(S,s.code,s.message);break}}initMessageChannel(){var t;if(!((t=this.iframe)!=null&&t.contentWindow))return;const e=new MessageChannel;this.port=e.port1,this.port.onmessage=s=>{var l,h,d,c,m,f,g,p,u,S;console.log("[Widget] Port message received:",s.data);const{type:n,...o}=s.data||{};switch(n){case i.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:o.collapsed,expanded:!o.collapsed}),this.expanded=!o.collapsed,this.updateIframeSize(o.collapsed),(h=(l=this.events).onResize)==null||h.call(l,o.collapsed);break;case i.SESSION_START:(c=(d=this.events).onSessionStart)==null||c.call(d,o.mode);break;case i.SESSION_END:(f=(m=this.events).onSessionEnd)==null||f.call(m);break;case i.MESSAGE:(p=(g=this.events).onMessage)==null||p.call(g,o.role,o.content);break;case i.ERROR:(S=(u=this.events).onError)==null||S.call(u,o.code,o.message);break}},this.iframe.contentWindow.postMessage({type:i.INIT_CHANNEL},"*",[e.port2])}sendCommand(e,t){var n;const s={type:i.COMMAND,action:e,payload:t};this.port?this.port.postMessage(s):(n=this.iframe)!=null&&n.contentWindow&&this.iframe.contentWindow.postMessage(s,"*")}updateIframeSize(e){if(console.log("[Widget] updateIframeSize called:",{collapsed:e,variant:this.config.variant,hasIframe:!!this.iframe}),!this.iframe||this.config.variant!=="floating"){console.log("[Widget] updateIframeSize skipped - no iframe or not floating variant");return}e?(console.log("[Widget] Setting collapsed size: 380x72"),this.iframe.style.width="380px",this.iframe.style.height="72px",this.iframe.style.maxHeight="72px"):(console.log("[Widget] Setting expanded size: 380x520"),this.iframe.style.width="380px",this.iframe.style.height="520px",this.iframe.style.maxHeight="calc(100vh - 40px)")}}a.LookalikeWidget=x,a.Widget=x,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
17
+ `.replace(/\s+/g," ").trim()}handleMessage(e){var n,o,l,h,d,c,m,f,g,p,u,S,x;if(console.log("[Widget] Received message:",e.data,"from:",e.source===((n=this.iframe)==null?void 0:n.contentWindow)?"iframe":"unknown"),this.iframe&&e.source!==this.iframe.contentWindow){console.log("[Widget] Ignoring message - not from iframe");return}const{type:t,...s}=e.data||{};switch(t){case i.WIDGET_READY:console.log("[Widget] WIDGET_READY event received!"),this.initMessageChannel(),(l=(o=this.events).onReady)==null||l.call(o);break;case i.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:s.collapsed,expanded:!s.collapsed}),this.expanded=!s.collapsed,this.updateIframeSize(s.collapsed),(d=(h=this.events).onResize)==null||d.call(h,s.collapsed);break;case i.SESSION_START:(m=(c=this.events).onSessionStart)==null||m.call(c,s.mode);break;case i.SESSION_END:(g=(f=this.events).onSessionEnd)==null||g.call(f);break;case i.MESSAGE:(u=(p=this.events).onMessage)==null||u.call(p,s.role,s.content);break;case i.ERROR:(x=(S=this.events).onError)==null||x.call(S,s.code,s.message);break}}initMessageChannel(){var t;if(!((t=this.iframe)!=null&&t.contentWindow))return;const e=new MessageChannel;this.port=e.port1,this.port.onmessage=s=>{var l,h,d,c,m,f,g,p,u,S;console.log("[Widget] Port message received:",s.data);const{type:n,...o}=s.data||{};switch(n){case i.WIDGET_RESIZE:console.log("[Widget] Received resize event:",{collapsed:o.collapsed,expanded:!o.collapsed}),this.expanded=!o.collapsed,this.updateIframeSize(o.collapsed),(h=(l=this.events).onResize)==null||h.call(l,o.collapsed);break;case i.SESSION_START:(c=(d=this.events).onSessionStart)==null||c.call(d,o.mode);break;case i.SESSION_END:(f=(m=this.events).onSessionEnd)==null||f.call(m);break;case i.MESSAGE:(p=(g=this.events).onMessage)==null||p.call(g,o.role,o.content);break;case i.ERROR:(S=(u=this.events).onError)==null||S.call(u,o.code,o.message);break}},this.iframe.contentWindow.postMessage({type:i.INIT_CHANNEL},"*",[e.port2])}sendCommand(e,t){var n;const s={type:i.COMMAND,action:e,payload:t};this.port?this.port.postMessage(s):(n=this.iframe)!=null&&n.contentWindow&&this.iframe.contentWindow.postMessage(s,"*")}updateIframeSize(e){if(console.log("[Widget] updateIframeSize called:",{collapsed:e,variant:this.config.variant,hasIframe:!!this.iframe}),!this.iframe||this.config.variant!=="floating"){console.log("[Widget] updateIframeSize skipped - no iframe or not floating variant");return}e?(console.log("[Widget] Setting collapsed size: 380x72"),this.iframe.style.width="380px",this.iframe.style.height="72px",this.iframe.style.maxHeight="72px"):(console.log("[Widget] Setting expanded size: 380x520"),this.iframe.style.width="380px",this.iframe.style.height="520px",this.iframe.style.maxHeight="calc(100vh - 40px)")}}a.LookalikeWidget=E,a.Widget=E,a.default=E,Object.defineProperties(a,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
18
18
  //# sourceMappingURL=widget.umd.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lookalike/widget",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "Embed Lookalike conversational AI widgets in your website with Wix integration support",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -62,4 +62,4 @@
62
62
  "access": "public",
63
63
  "registry": "https://registry.npmjs.org/"
64
64
  }
65
- }
65
+ }