@opencx/widget-react-headless 4.0.2 → 4.0.3

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,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react"),E=require("@opencx/widget-core"),F=require("swr"),W=require("uuid"),P="4.0.0";class U{constructor(t){this.components=[];const{components:n}=t;if(n&&n.forEach(o=>this.register(o)),this.components.length===0)throw new Error("No components registered");if(!this.get("fallback"))throw new Error("No fallback component registered")}register(t){const n=this.components.findIndex(o=>o.key===t.key);return n!==-1?this.components[n]=t:this.components.push(t),this}get(t){const n=this.components.find(o=>o.key.toUpperCase()===t.toUpperCase());return n||null}getComponent(t){var n;return(n=this.get(t))==null?void 0:n.component}}const b=i.createContext(null);function M({options:e,children:t,components:n,storage:o,loadingComponent:u}){const c=i.useRef(null),d=i.useRef(!1),[l,C]=i.useState(null),p=i.useMemo(()=>new U({components:n}),[n]);return i.useEffect(()=>{d.current||(d.current=!0,E.WidgetCtx.initialize({config:e,storage:o}).then(C))},[]),l?i.createElement(b.Provider,{value:{widgetCtx:l,config:e,components:n,componentStore:p,version:P,contentIframeRef:c}},t):u||null}function g(){const e=i.useContext(b);if(!e)throw new Error("useWidget must be used within a WidgetProvider");return e}function w(){const{config:e}=g();return e}function m(e){return i.useSyncExternalStore(e.subscribe,e.get,e.get)}function R(){const{widgetCtx:e}=g();return{contactState:m(e.contactCtx.state),createUnverifiedContact:e.contactCtx.createUnverifiedContact}}const A=()=>{const[e,t]=i.useState("ltr");return i.useEffect(()=>{const n=()=>{typeof document>"u"||t(window.getComputedStyle(document.body).direction)};n();const o=new MutationObserver(n);return o.observe(document.documentElement,{attributes:!0,attributeFilter:["dir"]}),o.observe(document.body,{attributes:!0,attributeFilter:["dir"]}),window.addEventListener("languagechange",n),()=>{o.disconnect(),window.removeEventListener("languagechange",n)}},[]),e};function y(){const{widgetCtx:e}=g();return{messagesState:m(e.messageCtx.state),sendMessage:e.messageCtx.sendMessage}}function x(){const{widgetCtx:e}=g(),{oneOpenSessionAllowed:t}=w(),n=m(e.sessionCtx.sessionState),o=m(e.sessionCtx.sessionsState),{openSessions:u,closedSessions:c}=i.useMemo(()=>({openSessions:o.data.filter(l=>l.isOpened===!0),closedSessions:o.data.filter(l=>l.isOpened===!1)}),[o.data]),d=i.useMemo(()=>t?u.length===0:!0,[t,u.length]);return{sessionState:n,sessionsState:o,loadMoreSessions:e.sessionCtx.loadMoreSessions,resolveSession:e.sessionCtx.resolveSession,createStateCheckpoint:e.sessionCtx.createStateCheckpoint,openSessions:u,closedSessions:c,canCreateNewSession:d}}function O(){var d;const{sessionState:e}=x(),{messagesState:t}=y(),n=((d=e.session)==null?void 0:d.assignee.kind)==="ai",o=t.messages.length>0?t.messages[t.messages.length-1]:null,u=(o==null?void 0:o.type)==="FROM_USER";return{isAwaitingBotReply:(n||e.isCreatingSession)&&(t.isSendingMessage||u)}}function T(){const{widgetCtx:e}=g();return F([e.config.token],e.api.widgetPrelude,{revalidateOnFocus:!1})}function k(){const{widgetCtx:e}=g();return{routerState:m(e.routerCtx.state),toSessionsScreen:e.routerCtx.toSessionsScreen,toChatScreen:e.routerCtx.toChatScreen}}const f=new Map;function D(){const[e,t]=i.useState([]),{widgetCtx:{api:n}}=g();function o(s){const r=s.map(a=>({file:a,id:W.v4(),status:"pending",progress:0}));t(a=>[...a,...r]),r.forEach(d)}function u(s,r){t(a=>a.map(S=>S.id===s?{...S,...r}:S))}function c(s){t(r=>r.filter(a=>a.id!==s))}const d=async s=>{const r=new AbortController;f.set(s.id,r);try{t(S=>S.map(h=>h.id===s.id?{...h,status:"uploading",progress:0}:h));const a=await n.uploadFile({file:s.file,abortSignal:r.signal,onProgress:S=>{u(s.id,{progress:S})}});u(s.id,{status:"success",fileUrl:a.fileUrl,progress:100})}catch(a){r.signal.aborted||u(s.id,{status:"error",error:a instanceof Error?a.message:"Upload failed",progress:0})}finally{f.delete(s.id)}},l=s=>{const r=f.get(s);r&&(r.abort(),f.delete(s)),c(s)},C=i.useMemo(()=>e.filter(s=>s.status==="success"&&s.fileUrl),[e]);function p(){f.forEach(s=>s.abort()),f.clear(),t([])}return i.useEffect(()=>()=>{f.forEach(s=>s.abort()),f.clear()},[]),{allFiles:e,appendFiles:o,handleCancelUpload:l,successFiles:C,emptyTheFiles:p,getFileById:s=>e.find(r=>r.id===s),getUploadProgress:s=>{var r;return((r=e.find(a=>a.id===s))==null?void 0:r.progress)??0},getUploadStatus:s=>{var r;return(r=e.find(a=>a.id===s))==null?void 0:r.status},hasErrors:e.some(s=>s.status==="error"),isUploading:e.some(s=>s.status==="uploading")}}const v=i.createContext(null);function N({children:e}){const t=w(),[n,o]=i.useState(()=>t.inline?!0:t.isOpen??!1);return i.useEffect(()=>{o(u=>t.isOpen??u)},[t.isOpen]),i.useEffect(()=>{const u=t.openAfterNSeconds;if(typeof u!="number"||isNaN(u))return;const c=setTimeout(()=>o(!0),u*1e3);return()=>clearTimeout(c)},[t.openAfterNSeconds]),i.createElement(v.Provider,{value:{isOpen:n,setIsOpen:o}},e)}function B(){const e=i.useContext(v);if(!e)throw new Error("useWidgetTrigger must be used within a WidgetTriggerProvider");return e}function L(){var l,C;const{widgetCtx:e}=g(),{modesComponents:t}=w(),{sessionState:n}=x(),o=e.modes,u=(l=n.session)==null?void 0:l.modeId,c=o.find(p=>p.id===u),d=(C=t==null?void 0:t.find(p=>{var s,r;return[(c==null?void 0:c.id)||"",((s=c==null?void 0:c.name)==null?void 0:s.toLowerCase())||"",((r=c==null?void 0:c.slug)==null?void 0:r.toLowerCase())||""].includes(p.key.toLowerCase())}))==null?void 0:C.component;return{modes:o,modesComponents:t,activeModeId:u,activeMode:c,Component:d}}exports.WidgetProvider=M;exports.WidgetTriggerProvider=N;exports.useConfig=w;exports.useContact=R;exports.useDocumentDir=A;exports.useIsAwaitingBotReply=O;exports.useMessages=y;exports.useModes=L;exports.usePreludeData=T;exports.usePrimitiveState=m;exports.useSessions=x;exports.useUploadFiles=D;exports.useWidget=g;exports.useWidgetRouter=k;exports.useWidgetTrigger=B;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react"),E=require("@opencx/widget-core"),F=require("swr"),W=require("uuid"),P="4.0.2";class U{constructor(t){this.components=[];const{components:n}=t;if(n&&n.forEach(o=>this.register(o)),this.components.length===0)throw new Error("No components registered");if(!this.get("fallback"))throw new Error("No fallback component registered")}register(t){const n=this.components.findIndex(o=>o.key===t.key);return n!==-1?this.components[n]=t:this.components.push(t),this}get(t){const n=this.components.find(o=>o.key.toUpperCase()===t.toUpperCase());return n||null}getComponent(t){var n;return(n=this.get(t))==null?void 0:n.component}}const b=i.createContext(null);function M({options:e,children:t,components:n,storage:o,loadingComponent:u}){const c=i.useRef(null),d=i.useRef(!1),[l,C]=i.useState(null),p=i.useMemo(()=>new U({components:n}),[n]);return i.useEffect(()=>{d.current||(d.current=!0,E.WidgetCtx.initialize({config:e,storage:o}).then(C))},[]),l?i.createElement(b.Provider,{value:{widgetCtx:l,config:e,components:n,componentStore:p,version:P,contentIframeRef:c}},t):u||null}function g(){const e=i.useContext(b);if(!e)throw new Error("useWidget must be used within a WidgetProvider");return e}function w(){const{config:e}=g();return e}function m(e){return i.useSyncExternalStore(e.subscribe,e.get,e.get)}function R(){const{widgetCtx:e}=g();return{contactState:m(e.contactCtx.state),createUnverifiedContact:e.contactCtx.createUnverifiedContact}}function A(){const[e,t]=i.useState("ltr");return i.useEffect(()=>{const n=()=>{typeof document>"u"||t(window.getComputedStyle((window.top||window).document.body).direction)};n();const o=new MutationObserver(n);return o.observe(document.documentElement,{attributes:!0,attributeFilter:["dir"]}),o.observe(document.body,{attributes:!0,attributeFilter:["dir"]}),window.addEventListener("languagechange",n),()=>{o.disconnect(),window.removeEventListener("languagechange",n)}},[]),{dir:e}}function y(){const{widgetCtx:e}=g();return{messagesState:m(e.messageCtx.state),sendMessage:e.messageCtx.sendMessage}}function x(){const{widgetCtx:e}=g(),{oneOpenSessionAllowed:t}=w(),n=m(e.sessionCtx.sessionState),o=m(e.sessionCtx.sessionsState),{openSessions:u,closedSessions:c}=i.useMemo(()=>({openSessions:o.data.filter(l=>l.isOpened===!0),closedSessions:o.data.filter(l=>l.isOpened===!1)}),[o.data]),d=i.useMemo(()=>t?u.length===0:!0,[t,u.length]);return{sessionState:n,sessionsState:o,loadMoreSessions:e.sessionCtx.loadMoreSessions,resolveSession:e.sessionCtx.resolveSession,createStateCheckpoint:e.sessionCtx.createStateCheckpoint,openSessions:u,closedSessions:c,canCreateNewSession:d}}function O(){var d;const{sessionState:e}=x(),{messagesState:t}=y(),n=((d=e.session)==null?void 0:d.assignee.kind)==="ai",o=t.messages.length>0?t.messages[t.messages.length-1]:null,u=(o==null?void 0:o.type)==="FROM_USER";return{isAwaitingBotReply:(n||e.isCreatingSession)&&(t.isSendingMessage||u)}}function T(){const{widgetCtx:e}=g();return F([e.config.token],e.api.widgetPrelude,{revalidateOnFocus:!1})}function k(){const{widgetCtx:e}=g();return{routerState:m(e.routerCtx.state),toSessionsScreen:e.routerCtx.toSessionsScreen,toChatScreen:e.routerCtx.toChatScreen}}const f=new Map;function D(){const[e,t]=i.useState([]),{widgetCtx:{api:n}}=g();function o(s){const r=s.map(a=>({file:a,id:W.v4(),status:"pending",progress:0}));t(a=>[...a,...r]),r.forEach(d)}function u(s,r){t(a=>a.map(S=>S.id===s?{...S,...r}:S))}function c(s){t(r=>r.filter(a=>a.id!==s))}const d=async s=>{const r=new AbortController;f.set(s.id,r);try{t(S=>S.map(h=>h.id===s.id?{...h,status:"uploading",progress:0}:h));const a=await n.uploadFile({file:s.file,abortSignal:r.signal,onProgress:S=>{u(s.id,{progress:S})}});u(s.id,{status:"success",fileUrl:a.fileUrl,progress:100})}catch(a){r.signal.aborted||u(s.id,{status:"error",error:a instanceof Error?a.message:"Upload failed",progress:0})}finally{f.delete(s.id)}},l=s=>{const r=f.get(s);r&&(r.abort(),f.delete(s)),c(s)},C=i.useMemo(()=>e.filter(s=>s.status==="success"&&s.fileUrl),[e]);function p(){f.forEach(s=>s.abort()),f.clear(),t([])}return i.useEffect(()=>()=>{f.forEach(s=>s.abort()),f.clear()},[]),{allFiles:e,appendFiles:o,handleCancelUpload:l,successFiles:C,emptyTheFiles:p,getFileById:s=>e.find(r=>r.id===s),getUploadProgress:s=>{var r;return((r=e.find(a=>a.id===s))==null?void 0:r.progress)??0},getUploadStatus:s=>{var r;return(r=e.find(a=>a.id===s))==null?void 0:r.status},hasErrors:e.some(s=>s.status==="error"),isUploading:e.some(s=>s.status==="uploading")}}const v=i.createContext(null);function N({children:e}){const t=w(),[n,o]=i.useState(()=>t.inline?!0:t.isOpen??!1);return i.useEffect(()=>{o(u=>t.isOpen??u)},[t.isOpen]),i.useEffect(()=>{const u=t.openAfterNSeconds;if(typeof u!="number"||isNaN(u))return;const c=setTimeout(()=>o(!0),u*1e3);return()=>clearTimeout(c)},[t.openAfterNSeconds]),i.createElement(v.Provider,{value:{isOpen:n,setIsOpen:o}},e)}function B(){const e=i.useContext(v);if(!e)throw new Error("useWidgetTrigger must be used within a WidgetTriggerProvider");return e}function L(){var l,C;const{widgetCtx:e}=g(),{modesComponents:t}=w(),{sessionState:n}=x(),o=e.modes,u=(l=n.session)==null?void 0:l.modeId,c=o.find(p=>p.id===u),d=(C=t==null?void 0:t.find(p=>{var s,r;return[(c==null?void 0:c.id)||"",((s=c==null?void 0:c.name)==null?void 0:s.toLowerCase())||"",((r=c==null?void 0:c.slug)==null?void 0:r.toLowerCase())||""].includes(p.key.toLowerCase())}))==null?void 0:C.component;return{modes:o,modesComponents:t,activeModeId:u,activeMode:c,Component:d}}exports.WidgetProvider=M;exports.WidgetTriggerProvider=N;exports.useConfig=w;exports.useContact=R;exports.useDocumentDir=A;exports.useIsAwaitingBotReply=O;exports.useMessages=y;exports.useModes=L;exports.usePreludeData=T;exports.usePrimitiveState=m;exports.useSessions=x;exports.useUploadFiles=D;exports.useWidget=g;exports.useWidgetRouter=k;exports.useWidgetTrigger=B;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/ComponentRegistry.ts","../src/WidgetProvider.tsx","../src/hooks/useConfig.ts","../src/hooks/usePrimitiveState.ts","../src/hooks/useContact.ts","../src/hooks/useDocumentDir.ts","../src/hooks/useMessages.ts","../src/hooks/useSessions.ts","../src/hooks/useIsAwaitingBotReply.ts","../src/hooks/usePreludeData.ts","../src/hooks/useWidgetRouter.ts","../src/hooks/useUploadFiles.ts","../src/hooks/useWidgetTrigger.tsx","../src/hooks/useModes.ts"],"sourcesContent":["import type { WidgetComponentKey } from '@opencx/widget-core';\nimport type { WidgetComponentType } from './types/components';\n\nexport class ComponentRegistry {\n components: WidgetComponentType[] = [];\n\n constructor(opts: { components?: WidgetComponentType[] }) {\n const { components } = opts;\n\n if (components) {\n components.forEach((c) => this.register(c));\n }\n\n if (this.components.length === 0) {\n throw new Error('No components registered');\n }\n if (!this.get('fallback')) {\n throw new Error('No fallback component registered');\n }\n }\n\n // TODO test that this registers or replaces the component\n register(component: WidgetComponentType) {\n // Replace the key if it already exists\n const index = this.components.findIndex((c) => c.key === component.key);\n if (index !== -1) {\n this.components[index] = component;\n } else {\n this.components.push(component);\n }\n return this;\n }\n\n private get(key: WidgetComponentKey) {\n const c = this.components.find(\n (c) => c.key.toUpperCase() === key.toUpperCase(),\n );\n if (c) return c;\n return null;\n }\n\n public getComponent(key: string) {\n return this.get(key)?.component;\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { version } from '../package.json';\nimport { type ExternalStorage, type WidgetConfig, WidgetCtx } from '@opencx/widget-core';\nimport { ComponentRegistry } from './ComponentRegistry';\nimport type { WidgetComponentType } from './types/components';\n\ninterface WidgetProviderValue {\n widgetCtx: WidgetCtx;\n config: WidgetConfig;\n components?: WidgetComponentType[];\n componentStore: ComponentRegistry;\n version: string;\n contentIframeRef?: React.MutableRefObject<HTMLIFrameElement | null>;\n}\n\nconst context = createContext<WidgetProviderValue | null>(null);\n\nexport function WidgetProvider({\n options: config,\n children,\n components,\n storage,\n loadingComponent,\n}: {\n options: WidgetConfig;\n children: React.ReactNode;\n components?: WidgetComponentType[];\n storage?: ExternalStorage;\n /**\n * Custom loading component while the widget is initializing\n * Not to be confused with the `loading` custom component which renders when the bot's reply is pending\n */\n loadingComponent?: React.ReactNode;\n}) {\n const contentIframeRef = useRef<HTMLIFrameElement | null>(null);\n\n const didInitialize = useRef(false);\n const [widgetCtx, setWidgetCtx] = useState<WidgetCtx | null>(null);\n\n const componentStore = useMemo(\n () =>\n new ComponentRegistry({\n components: components,\n }),\n [components],\n );\n\n useEffect(() => {\n if (didInitialize.current) return;\n didInitialize.current = true;\n\n WidgetCtx.initialize({ config, storage }).then(setWidgetCtx);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n if (!widgetCtx) {\n return loadingComponent || null;\n }\n\n return (\n <context.Provider\n value={{\n widgetCtx,\n config,\n components,\n componentStore,\n version,\n contentIframeRef,\n }}\n >\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidget() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useWidget must be used within a WidgetProvider');\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\n\nexport function useConfig() {\n const { config } = useWidget();\n\n return config;\n}\n","import { useSyncExternalStore } from 'react';\nimport type { PrimitiveState } from '@opencx/widget-core';\n\nexport function usePrimitiveState<T>(p: PrimitiveState<T>) {\n return useSyncExternalStore(p.subscribe, p.get, p.get);\n}\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useContact() {\n const { widgetCtx } = useWidget();\n const contactState = usePrimitiveState(widgetCtx.contactCtx.state);\n\n return {\n contactState,\n createUnverifiedContact: widgetCtx.contactCtx.createUnverifiedContact,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { StringOrLiteral } from '@opencx/widget-core';\n\nconst useDocumentDir = () => {\n const [dir, setDir] = useState<StringOrLiteral<'ltr' | 'rtl'>>('ltr');\n\n useEffect(() => {\n const updateDir = () => {\n if (typeof document === 'undefined') return;\n setDir(window.getComputedStyle(document.body).direction);\n };\n\n // Set initial direction\n updateDir();\n\n // Watch for direction changes on both document and documentElement\n const observer = new MutationObserver(updateDir);\n\n // Observe both document and documentElement\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n // Add event listener for dynamic changes\n window.addEventListener('languagechange', updateDir);\n\n return () => {\n observer.disconnect();\n window.removeEventListener('languagechange', updateDir);\n };\n }, []);\n\n return dir;\n};\n\nexport { useDocumentDir };\n","import { usePrimitiveState } from './usePrimitiveState';\nimport { useWidget } from '../WidgetProvider';\n\nexport function useMessages() {\n const { widgetCtx } = useWidget();\n const messagesState = usePrimitiveState(widgetCtx.messageCtx.state);\n\n return { messagesState, sendMessage: widgetCtx.messageCtx.sendMessage };\n}\n","import { useMemo } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\nimport { useConfig } from './useConfig';\n\nexport function useSessions() {\n const { widgetCtx } = useWidget();\n const { oneOpenSessionAllowed } = useConfig();\n const sessionState = usePrimitiveState(widgetCtx.sessionCtx.sessionState);\n const sessionsState = usePrimitiveState(widgetCtx.sessionCtx.sessionsState);\n\n const { openSessions, closedSessions } = useMemo(() => {\n return {\n openSessions: sessionsState.data.filter((s) => s.isOpened === true),\n closedSessions: sessionsState.data.filter((s) => s.isOpened === false),\n };\n }, [sessionsState.data]);\n\n const canCreateNewSession = useMemo(() => {\n if (oneOpenSessionAllowed) {\n return openSessions.length === 0;\n }\n return true;\n }, [oneOpenSessionAllowed, openSessions.length]);\n\n return {\n sessionState,\n sessionsState,\n loadMoreSessions: widgetCtx.sessionCtx.loadMoreSessions,\n resolveSession: widgetCtx.sessionCtx.resolveSession,\n createStateCheckpoint: widgetCtx.sessionCtx.createStateCheckpoint,\n openSessions,\n closedSessions,\n canCreateNewSession,\n };\n}\n","import { useMessages } from './useMessages';\nimport { useSessions } from './useSessions';\n\nexport function useIsAwaitingBotReply() {\n const { sessionState } = useSessions();\n const { messagesState } = useMessages();\n\n const isSessionAssignedToAI = sessionState.session?.assignee.kind === 'ai';\n // This check is useful in cases where the user might navigate in and out of a chat, and `isSendingMessage` is reset back to its default value\n const lastMessage =\n messagesState.messages.length > 0\n ? messagesState.messages[messagesState.messages.length - 1]\n : null;\n const isLastMessageAUserMessage = lastMessage?.type === 'FROM_USER';\n\n const isAwaitingBotReply =\n (isSessionAssignedToAI || sessionState.isCreatingSession) &&\n (messagesState.isSendingMessage || isLastMessageAUserMessage);\n\n return { isAwaitingBotReply };\n}\n","import useSWR from 'swr';\nimport { useWidget } from '../WidgetProvider';\n\nfunction usePreludeData() {\n const { widgetCtx } = useWidget();\n\n // TODO remove swr dependency\n return useSWR([widgetCtx.config.token], widgetCtx.api.widgetPrelude, {\n revalidateOnFocus: false,\n });\n}\n\nexport { usePreludeData };\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useWidgetRouter() {\n const { widgetCtx } = useWidget();\n\n const routerState = usePrimitiveState(widgetCtx.routerCtx.state);\n\n return {\n routerState,\n toSessionsScreen: widgetCtx.routerCtx.toSessionsScreen,\n toChatScreen: widgetCtx.routerCtx.toChatScreen,\n };\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { v4 } from 'uuid';\n\nconst uploadAbortControllers: Map<string, AbortController> = new Map();\n\ninterface FileWithProgress {\n status: 'pending' | 'uploading' | 'success' | 'error';\n id: string;\n file: File;\n fileUrl?: string;\n progress: number;\n error?: string;\n}\n\nfunction useUploadFiles() {\n const [files, setFiles] = useState<FileWithProgress[]>([]);\n const {\n widgetCtx: { api },\n } = useWidget();\n function appendFiles(files: File[]) {\n const newFiles = files.map((file) => ({\n file,\n id: v4(),\n status: 'pending' as const,\n progress: 0,\n }));\n\n setFiles((prev) => [...prev, ...newFiles]);\n newFiles.forEach(uploadFile);\n }\n\n function updateFileById(id: string, update: Partial<FileWithProgress>) {\n setFiles((prev) =>\n prev.map((f) => (f.id === id ? { ...f, ...update } : f)),\n );\n }\n\n function removeFileById(id: string) {\n setFiles((prev) => prev.filter((f) => f.id !== id));\n }\n\n const uploadFile = async (fileItem: FileWithProgress) => {\n const controller = new AbortController();\n uploadAbortControllers.set(fileItem.id, controller);\n\n try {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === fileItem.id ? { ...f, status: 'uploading', progress: 0 } : f,\n ),\n );\n\n const response = await api.uploadFile({\n file: fileItem.file,\n abortSignal: controller.signal,\n onProgress: (percentage) => {\n updateFileById(fileItem.id, { progress: percentage });\n },\n });\n\n updateFileById(fileItem.id, {\n status: 'success',\n fileUrl: response.fileUrl,\n progress: 100,\n });\n } catch (error) {\n if (!controller.signal.aborted) {\n updateFileById(fileItem.id, {\n status: 'error',\n error: error instanceof Error ? error.message : 'Upload failed',\n progress: 0,\n });\n }\n } finally {\n uploadAbortControllers.delete(fileItem.id);\n }\n };\n\n const handleCancelUpload = (fileId: string) => {\n const controller = uploadAbortControllers.get(fileId);\n if (controller) {\n controller.abort();\n uploadAbortControllers.delete(fileId);\n }\n removeFileById(fileId);\n };\n\n const successFiles = useMemo(() => {\n return files.filter((f) => f.status === 'success' && f.fileUrl);\n }, [files]);\n\n function emptyTheFiles() {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n setFiles([]);\n }\n\n useEffect(() => {\n return () => {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n };\n }, []);\n\n return {\n allFiles: files,\n appendFiles,\n handleCancelUpload,\n successFiles,\n emptyTheFiles,\n getFileById: (id: string) => files.find((f) => f.id === id),\n getUploadProgress: (id: string) =>\n files.find((f) => f.id === id)?.progress ?? 0,\n getUploadStatus: (id: string) => files.find((f) => f.id === id)?.status,\n hasErrors: files.some((f) => f.status === 'error'),\n isUploading: files.some((f) => f.status === 'uploading'),\n };\n}\n\nexport { useUploadFiles, type FileWithProgress };\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n} from 'react';\nimport { useConfig } from './useConfig';\n\ntype WidgetTriggerCtx = {\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n};\n\nconst context = createContext<WidgetTriggerCtx | null>(null);\n\nexport function WidgetTriggerProvider({ children }: { children: ReactNode }) {\n const config = useConfig();\n const [isOpen, setIsOpen] = useState(() => {\n if (config.inline) return true;\n return config.isOpen ?? false;\n });\n\n useEffect(() => {\n setIsOpen((prev) => config.isOpen ?? prev);\n }, [config.isOpen]);\n\n useEffect(() => {\n const openAfterNSeconds = config.openAfterNSeconds;\n if (typeof openAfterNSeconds !== 'number' || isNaN(openAfterNSeconds))\n return;\n\n const timeout = setTimeout(() => setIsOpen(true), openAfterNSeconds * 1000);\n\n return () => clearTimeout(timeout);\n }, [config.openAfterNSeconds]);\n\n return (\n <context.Provider value={{ isOpen, setIsOpen }}>\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidgetTrigger() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error(\n 'useWidgetTrigger must be used within a WidgetTriggerProvider',\n );\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\nimport { useConfig } from './useConfig';\nimport { useSessions } from './useSessions';\n\nexport function useModes() {\n const { widgetCtx } = useWidget();\n const { modesComponents } = useConfig();\n const { sessionState } = useSessions();\n\n const modes = widgetCtx.modes;\n const activeModeId = sessionState.session?.modeId;\n const activeMode = modes.find((mode) => mode.id === activeModeId);\n\n const Component = modesComponents?.find((modeComponent) =>\n [\n activeMode?.id || '',\n activeMode?.name?.toLowerCase() || '',\n activeMode?.slug?.toLowerCase() || '',\n ].includes(modeComponent.key.toLowerCase()),\n )?.component;\n\n return {\n modes,\n modesComponents,\n activeModeId,\n activeMode,\n Component,\n };\n}\n"],"names":["ComponentRegistry","opts","components","c","component","index","key","_a","context","createContext","WidgetProvider","config","children","storage","loadingComponent","contentIframeRef","useRef","didInitialize","widgetCtx","setWidgetCtx","useState","componentStore","useMemo","useEffect","WidgetCtx","React","version","useWidget","ctx","useContext","useConfig","usePrimitiveState","p","useSyncExternalStore","useContact","useDocumentDir","dir","setDir","updateDir","observer","useMessages","useSessions","oneOpenSessionAllowed","sessionState","sessionsState","openSessions","closedSessions","s","canCreateNewSession","useIsAwaitingBotReply","messagesState","isSessionAssignedToAI","lastMessage","isLastMessageAUserMessage","usePreludeData","useSWR","useWidgetRouter","uploadAbortControllers","useUploadFiles","files","setFiles","api","appendFiles","newFiles","file","v4","prev","uploadFile","updateFileById","id","update","f","removeFileById","fileItem","controller","response","percentage","error","handleCancelUpload","fileId","successFiles","emptyTheFiles","WidgetTriggerProvider","isOpen","setIsOpen","openAfterNSeconds","timeout","useWidgetTrigger","useModes","modesComponents","modes","activeModeId","activeMode","mode","Component","_b","modeComponent"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/ComponentRegistry.ts","../src/WidgetProvider.tsx","../src/hooks/useConfig.ts","../src/hooks/usePrimitiveState.ts","../src/hooks/useContact.ts","../src/hooks/useDocumentDir.ts","../src/hooks/useMessages.ts","../src/hooks/useSessions.ts","../src/hooks/useIsAwaitingBotReply.ts","../src/hooks/usePreludeData.ts","../src/hooks/useWidgetRouter.ts","../src/hooks/useUploadFiles.ts","../src/hooks/useWidgetTrigger.tsx","../src/hooks/useModes.ts"],"sourcesContent":["import type { WidgetComponentKey } from '@opencx/widget-core';\nimport type { WidgetComponentType } from './types/components';\n\nexport class ComponentRegistry {\n components: WidgetComponentType[] = [];\n\n constructor(opts: { components?: WidgetComponentType[] }) {\n const { components } = opts;\n\n if (components) {\n components.forEach((c) => this.register(c));\n }\n\n if (this.components.length === 0) {\n throw new Error('No components registered');\n }\n if (!this.get('fallback')) {\n throw new Error('No fallback component registered');\n }\n }\n\n // TODO test that this registers or replaces the component\n register(component: WidgetComponentType) {\n // Replace the key if it already exists\n const index = this.components.findIndex((c) => c.key === component.key);\n if (index !== -1) {\n this.components[index] = component;\n } else {\n this.components.push(component);\n }\n return this;\n }\n\n private get(key: WidgetComponentKey) {\n const c = this.components.find(\n (c) => c.key.toUpperCase() === key.toUpperCase(),\n );\n if (c) return c;\n return null;\n }\n\n public getComponent(key: string) {\n return this.get(key)?.component;\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { version } from '../package.json';\nimport { type ExternalStorage, type WidgetConfig, WidgetCtx } from '@opencx/widget-core';\nimport { ComponentRegistry } from './ComponentRegistry';\nimport type { WidgetComponentType } from './types/components';\n\ninterface WidgetProviderValue {\n widgetCtx: WidgetCtx;\n config: WidgetConfig;\n components?: WidgetComponentType[];\n componentStore: ComponentRegistry;\n version: string;\n contentIframeRef?: React.MutableRefObject<HTMLIFrameElement | null>;\n}\n\nconst context = createContext<WidgetProviderValue | null>(null);\n\nexport function WidgetProvider({\n options: config,\n children,\n components,\n storage,\n loadingComponent,\n}: {\n options: WidgetConfig;\n children: React.ReactNode;\n components?: WidgetComponentType[];\n storage?: ExternalStorage;\n /**\n * Custom loading component while the widget is initializing\n * Not to be confused with the `loading` custom component which renders when the bot's reply is pending\n */\n loadingComponent?: React.ReactNode;\n}) {\n const contentIframeRef = useRef<HTMLIFrameElement | null>(null);\n\n const didInitialize = useRef(false);\n const [widgetCtx, setWidgetCtx] = useState<WidgetCtx | null>(null);\n\n const componentStore = useMemo(\n () =>\n new ComponentRegistry({\n components: components,\n }),\n [components],\n );\n\n useEffect(() => {\n if (didInitialize.current) return;\n didInitialize.current = true;\n\n WidgetCtx.initialize({ config, storage }).then(setWidgetCtx);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n if (!widgetCtx) {\n return loadingComponent || null;\n }\n\n return (\n <context.Provider\n value={{\n widgetCtx,\n config,\n components,\n componentStore,\n version,\n contentIframeRef,\n }}\n >\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidget() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useWidget must be used within a WidgetProvider');\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\n\nexport function useConfig() {\n const { config } = useWidget();\n\n return config;\n}\n","import { useSyncExternalStore } from 'react';\nimport type { PrimitiveState } from '@opencx/widget-core';\n\nexport function usePrimitiveState<T>(p: PrimitiveState<T>) {\n return useSyncExternalStore(p.subscribe, p.get, p.get);\n}\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useContact() {\n const { widgetCtx } = useWidget();\n const contactState = usePrimitiveState(widgetCtx.contactCtx.state);\n\n return {\n contactState,\n createUnverifiedContact: widgetCtx.contactCtx.createUnverifiedContact,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { StringOrLiteral } from '@opencx/widget-core';\n\nexport function useDocumentDir() {\n const [dir, setDir] = useState<StringOrLiteral<'ltr' | 'rtl'>>('ltr');\n\n useEffect(() => {\n const updateDir = () => {\n if (typeof document === 'undefined') return;\n setDir(\n window.getComputedStyle((window.top || window).document.body).direction,\n );\n };\n\n // Set initial direction\n updateDir();\n\n // Watch for direction changes on both document and documentElement\n const observer = new MutationObserver(updateDir);\n\n // Observe both document and documentElement\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n // Add event listener for dynamic changes\n window.addEventListener('languagechange', updateDir);\n\n return () => {\n observer.disconnect();\n window.removeEventListener('languagechange', updateDir);\n };\n }, []);\n\n return { dir };\n}\n","import { usePrimitiveState } from './usePrimitiveState';\nimport { useWidget } from '../WidgetProvider';\n\nexport function useMessages() {\n const { widgetCtx } = useWidget();\n const messagesState = usePrimitiveState(widgetCtx.messageCtx.state);\n\n return { messagesState, sendMessage: widgetCtx.messageCtx.sendMessage };\n}\n","import { useMemo } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\nimport { useConfig } from './useConfig';\n\nexport function useSessions() {\n const { widgetCtx } = useWidget();\n const { oneOpenSessionAllowed } = useConfig();\n const sessionState = usePrimitiveState(widgetCtx.sessionCtx.sessionState);\n const sessionsState = usePrimitiveState(widgetCtx.sessionCtx.sessionsState);\n\n const { openSessions, closedSessions } = useMemo(() => {\n return {\n openSessions: sessionsState.data.filter((s) => s.isOpened === true),\n closedSessions: sessionsState.data.filter((s) => s.isOpened === false),\n };\n }, [sessionsState.data]);\n\n const canCreateNewSession = useMemo(() => {\n if (oneOpenSessionAllowed) {\n return openSessions.length === 0;\n }\n return true;\n }, [oneOpenSessionAllowed, openSessions.length]);\n\n return {\n sessionState,\n sessionsState,\n loadMoreSessions: widgetCtx.sessionCtx.loadMoreSessions,\n resolveSession: widgetCtx.sessionCtx.resolveSession,\n createStateCheckpoint: widgetCtx.sessionCtx.createStateCheckpoint,\n openSessions,\n closedSessions,\n canCreateNewSession,\n };\n}\n","import { useMessages } from './useMessages';\nimport { useSessions } from './useSessions';\n\nexport function useIsAwaitingBotReply() {\n const { sessionState } = useSessions();\n const { messagesState } = useMessages();\n\n const isSessionAssignedToAI = sessionState.session?.assignee.kind === 'ai';\n // This check is useful in cases where the user might navigate in and out of a chat, and `isSendingMessage` is reset back to its default value\n const lastMessage =\n messagesState.messages.length > 0\n ? messagesState.messages[messagesState.messages.length - 1]\n : null;\n const isLastMessageAUserMessage = lastMessage?.type === 'FROM_USER';\n\n const isAwaitingBotReply =\n (isSessionAssignedToAI || sessionState.isCreatingSession) &&\n (messagesState.isSendingMessage || isLastMessageAUserMessage);\n\n return { isAwaitingBotReply };\n}\n","import useSWR from 'swr';\nimport { useWidget } from '../WidgetProvider';\n\nfunction usePreludeData() {\n const { widgetCtx } = useWidget();\n\n // TODO remove swr dependency\n return useSWR([widgetCtx.config.token], widgetCtx.api.widgetPrelude, {\n revalidateOnFocus: false,\n });\n}\n\nexport { usePreludeData };\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useWidgetRouter() {\n const { widgetCtx } = useWidget();\n\n const routerState = usePrimitiveState(widgetCtx.routerCtx.state);\n\n return {\n routerState,\n toSessionsScreen: widgetCtx.routerCtx.toSessionsScreen,\n toChatScreen: widgetCtx.routerCtx.toChatScreen,\n };\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { v4 } from 'uuid';\n\nconst uploadAbortControllers: Map<string, AbortController> = new Map();\n\ninterface FileWithProgress {\n status: 'pending' | 'uploading' | 'success' | 'error';\n id: string;\n file: File;\n fileUrl?: string;\n progress: number;\n error?: string;\n}\n\nfunction useUploadFiles() {\n const [files, setFiles] = useState<FileWithProgress[]>([]);\n const {\n widgetCtx: { api },\n } = useWidget();\n function appendFiles(files: File[]) {\n const newFiles = files.map((file) => ({\n file,\n id: v4(),\n status: 'pending' as const,\n progress: 0,\n }));\n\n setFiles((prev) => [...prev, ...newFiles]);\n newFiles.forEach(uploadFile);\n }\n\n function updateFileById(id: string, update: Partial<FileWithProgress>) {\n setFiles((prev) =>\n prev.map((f) => (f.id === id ? { ...f, ...update } : f)),\n );\n }\n\n function removeFileById(id: string) {\n setFiles((prev) => prev.filter((f) => f.id !== id));\n }\n\n const uploadFile = async (fileItem: FileWithProgress) => {\n const controller = new AbortController();\n uploadAbortControllers.set(fileItem.id, controller);\n\n try {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === fileItem.id ? { ...f, status: 'uploading', progress: 0 } : f,\n ),\n );\n\n const response = await api.uploadFile({\n file: fileItem.file,\n abortSignal: controller.signal,\n onProgress: (percentage) => {\n updateFileById(fileItem.id, { progress: percentage });\n },\n });\n\n updateFileById(fileItem.id, {\n status: 'success',\n fileUrl: response.fileUrl,\n progress: 100,\n });\n } catch (error) {\n if (!controller.signal.aborted) {\n updateFileById(fileItem.id, {\n status: 'error',\n error: error instanceof Error ? error.message : 'Upload failed',\n progress: 0,\n });\n }\n } finally {\n uploadAbortControllers.delete(fileItem.id);\n }\n };\n\n const handleCancelUpload = (fileId: string) => {\n const controller = uploadAbortControllers.get(fileId);\n if (controller) {\n controller.abort();\n uploadAbortControllers.delete(fileId);\n }\n removeFileById(fileId);\n };\n\n const successFiles = useMemo(() => {\n return files.filter((f) => f.status === 'success' && f.fileUrl);\n }, [files]);\n\n function emptyTheFiles() {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n setFiles([]);\n }\n\n useEffect(() => {\n return () => {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n };\n }, []);\n\n return {\n allFiles: files,\n appendFiles,\n handleCancelUpload,\n successFiles,\n emptyTheFiles,\n getFileById: (id: string) => files.find((f) => f.id === id),\n getUploadProgress: (id: string) =>\n files.find((f) => f.id === id)?.progress ?? 0,\n getUploadStatus: (id: string) => files.find((f) => f.id === id)?.status,\n hasErrors: files.some((f) => f.status === 'error'),\n isUploading: files.some((f) => f.status === 'uploading'),\n };\n}\n\nexport { useUploadFiles, type FileWithProgress };\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n} from 'react';\nimport { useConfig } from './useConfig';\n\ntype WidgetTriggerCtx = {\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n};\n\nconst context = createContext<WidgetTriggerCtx | null>(null);\n\nexport function WidgetTriggerProvider({ children }: { children: ReactNode }) {\n const config = useConfig();\n const [isOpen, setIsOpen] = useState(() => {\n if (config.inline) return true;\n return config.isOpen ?? false;\n });\n\n useEffect(() => {\n setIsOpen((prev) => config.isOpen ?? prev);\n }, [config.isOpen]);\n\n useEffect(() => {\n const openAfterNSeconds = config.openAfterNSeconds;\n if (typeof openAfterNSeconds !== 'number' || isNaN(openAfterNSeconds))\n return;\n\n const timeout = setTimeout(() => setIsOpen(true), openAfterNSeconds * 1000);\n\n return () => clearTimeout(timeout);\n }, [config.openAfterNSeconds]);\n\n return (\n <context.Provider value={{ isOpen, setIsOpen }}>\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidgetTrigger() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error(\n 'useWidgetTrigger must be used within a WidgetTriggerProvider',\n );\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\nimport { useConfig } from './useConfig';\nimport { useSessions } from './useSessions';\n\nexport function useModes() {\n const { widgetCtx } = useWidget();\n const { modesComponents } = useConfig();\n const { sessionState } = useSessions();\n\n const modes = widgetCtx.modes;\n const activeModeId = sessionState.session?.modeId;\n const activeMode = modes.find((mode) => mode.id === activeModeId);\n\n const Component = modesComponents?.find((modeComponent) =>\n [\n activeMode?.id || '',\n activeMode?.name?.toLowerCase() || '',\n activeMode?.slug?.toLowerCase() || '',\n ].includes(modeComponent.key.toLowerCase()),\n )?.component;\n\n return {\n modes,\n modesComponents,\n activeModeId,\n activeMode,\n Component,\n };\n}\n"],"names":["ComponentRegistry","opts","components","c","component","index","key","_a","context","createContext","WidgetProvider","config","children","storage","loadingComponent","contentIframeRef","useRef","didInitialize","widgetCtx","setWidgetCtx","useState","componentStore","useMemo","useEffect","WidgetCtx","React","version","useWidget","ctx","useContext","useConfig","usePrimitiveState","p","useSyncExternalStore","useContact","useDocumentDir","dir","setDir","updateDir","observer","useMessages","useSessions","oneOpenSessionAllowed","sessionState","sessionsState","openSessions","closedSessions","s","canCreateNewSession","useIsAwaitingBotReply","messagesState","isSessionAssignedToAI","lastMessage","isLastMessageAUserMessage","usePreludeData","useSWR","useWidgetRouter","uploadAbortControllers","useUploadFiles","files","setFiles","api","appendFiles","newFiles","file","v4","prev","uploadFile","updateFileById","id","update","f","removeFileById","fileItem","controller","response","percentage","error","handleCancelUpload","fileId","successFiles","emptyTheFiles","WidgetTriggerProvider","isOpen","setIsOpen","openAfterNSeconds","timeout","useWidgetTrigger","useModes","modesComponents","modes","activeModeId","activeMode","mode","Component","_b","modeComponent"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import v, { createContext as E, useRef as y, useState as h, useMemo as w, useEff
2
2
  import { WidgetCtx as P } from "@opencx/widget-core";
3
3
  import R from "swr";
4
4
  import { v4 as k } from "uuid";
5
- const M = "4.0.0";
5
+ const M = "4.0.2";
6
6
  class N {
7
7
  constructor(t) {
8
8
  this.components = [];
@@ -79,11 +79,13 @@ function _() {
79
79
  createUnverifiedContact: e.contactCtx.createUnverifiedContact
80
80
  };
81
81
  }
82
- const $ = () => {
82
+ function $() {
83
83
  const [e, t] = h("ltr");
84
84
  return S(() => {
85
85
  const n = () => {
86
- typeof document > "u" || t(window.getComputedStyle(document.body).direction);
86
+ typeof document > "u" || t(
87
+ window.getComputedStyle((window.top || window).document.body).direction
88
+ );
87
89
  };
88
90
  n();
89
91
  const o = new MutationObserver(n);
@@ -96,8 +98,8 @@ const $ = () => {
96
98
  }), window.addEventListener("languagechange", n), () => {
97
99
  o.disconnect(), window.removeEventListener("languagechange", n);
98
100
  };
99
- }, []), e;
100
- };
101
+ }, []), { dir: e };
102
+ }
101
103
  function T() {
102
104
  const { widgetCtx: e } = g();
103
105
  return { messagesState: C(e.messageCtx.state), sendMessage: e.messageCtx.sendMessage };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/ComponentRegistry.ts","../src/WidgetProvider.tsx","../src/hooks/useConfig.ts","../src/hooks/usePrimitiveState.ts","../src/hooks/useContact.ts","../src/hooks/useDocumentDir.ts","../src/hooks/useMessages.ts","../src/hooks/useSessions.ts","../src/hooks/useIsAwaitingBotReply.ts","../src/hooks/usePreludeData.ts","../src/hooks/useWidgetRouter.ts","../src/hooks/useUploadFiles.ts","../src/hooks/useWidgetTrigger.tsx","../src/hooks/useModes.ts"],"sourcesContent":["import type { WidgetComponentKey } from '@opencx/widget-core';\nimport type { WidgetComponentType } from './types/components';\n\nexport class ComponentRegistry {\n components: WidgetComponentType[] = [];\n\n constructor(opts: { components?: WidgetComponentType[] }) {\n const { components } = opts;\n\n if (components) {\n components.forEach((c) => this.register(c));\n }\n\n if (this.components.length === 0) {\n throw new Error('No components registered');\n }\n if (!this.get('fallback')) {\n throw new Error('No fallback component registered');\n }\n }\n\n // TODO test that this registers or replaces the component\n register(component: WidgetComponentType) {\n // Replace the key if it already exists\n const index = this.components.findIndex((c) => c.key === component.key);\n if (index !== -1) {\n this.components[index] = component;\n } else {\n this.components.push(component);\n }\n return this;\n }\n\n private get(key: WidgetComponentKey) {\n const c = this.components.find(\n (c) => c.key.toUpperCase() === key.toUpperCase(),\n );\n if (c) return c;\n return null;\n }\n\n public getComponent(key: string) {\n return this.get(key)?.component;\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { version } from '../package.json';\nimport { type ExternalStorage, type WidgetConfig, WidgetCtx } from '@opencx/widget-core';\nimport { ComponentRegistry } from './ComponentRegistry';\nimport type { WidgetComponentType } from './types/components';\n\ninterface WidgetProviderValue {\n widgetCtx: WidgetCtx;\n config: WidgetConfig;\n components?: WidgetComponentType[];\n componentStore: ComponentRegistry;\n version: string;\n contentIframeRef?: React.MutableRefObject<HTMLIFrameElement | null>;\n}\n\nconst context = createContext<WidgetProviderValue | null>(null);\n\nexport function WidgetProvider({\n options: config,\n children,\n components,\n storage,\n loadingComponent,\n}: {\n options: WidgetConfig;\n children: React.ReactNode;\n components?: WidgetComponentType[];\n storage?: ExternalStorage;\n /**\n * Custom loading component while the widget is initializing\n * Not to be confused with the `loading` custom component which renders when the bot's reply is pending\n */\n loadingComponent?: React.ReactNode;\n}) {\n const contentIframeRef = useRef<HTMLIFrameElement | null>(null);\n\n const didInitialize = useRef(false);\n const [widgetCtx, setWidgetCtx] = useState<WidgetCtx | null>(null);\n\n const componentStore = useMemo(\n () =>\n new ComponentRegistry({\n components: components,\n }),\n [components],\n );\n\n useEffect(() => {\n if (didInitialize.current) return;\n didInitialize.current = true;\n\n WidgetCtx.initialize({ config, storage }).then(setWidgetCtx);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n if (!widgetCtx) {\n return loadingComponent || null;\n }\n\n return (\n <context.Provider\n value={{\n widgetCtx,\n config,\n components,\n componentStore,\n version,\n contentIframeRef,\n }}\n >\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidget() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useWidget must be used within a WidgetProvider');\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\n\nexport function useConfig() {\n const { config } = useWidget();\n\n return config;\n}\n","import { useSyncExternalStore } from 'react';\nimport type { PrimitiveState } from '@opencx/widget-core';\n\nexport function usePrimitiveState<T>(p: PrimitiveState<T>) {\n return useSyncExternalStore(p.subscribe, p.get, p.get);\n}\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useContact() {\n const { widgetCtx } = useWidget();\n const contactState = usePrimitiveState(widgetCtx.contactCtx.state);\n\n return {\n contactState,\n createUnverifiedContact: widgetCtx.contactCtx.createUnverifiedContact,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { StringOrLiteral } from '@opencx/widget-core';\n\nconst useDocumentDir = () => {\n const [dir, setDir] = useState<StringOrLiteral<'ltr' | 'rtl'>>('ltr');\n\n useEffect(() => {\n const updateDir = () => {\n if (typeof document === 'undefined') return;\n setDir(window.getComputedStyle(document.body).direction);\n };\n\n // Set initial direction\n updateDir();\n\n // Watch for direction changes on both document and documentElement\n const observer = new MutationObserver(updateDir);\n\n // Observe both document and documentElement\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n // Add event listener for dynamic changes\n window.addEventListener('languagechange', updateDir);\n\n return () => {\n observer.disconnect();\n window.removeEventListener('languagechange', updateDir);\n };\n }, []);\n\n return dir;\n};\n\nexport { useDocumentDir };\n","import { usePrimitiveState } from './usePrimitiveState';\nimport { useWidget } from '../WidgetProvider';\n\nexport function useMessages() {\n const { widgetCtx } = useWidget();\n const messagesState = usePrimitiveState(widgetCtx.messageCtx.state);\n\n return { messagesState, sendMessage: widgetCtx.messageCtx.sendMessage };\n}\n","import { useMemo } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\nimport { useConfig } from './useConfig';\n\nexport function useSessions() {\n const { widgetCtx } = useWidget();\n const { oneOpenSessionAllowed } = useConfig();\n const sessionState = usePrimitiveState(widgetCtx.sessionCtx.sessionState);\n const sessionsState = usePrimitiveState(widgetCtx.sessionCtx.sessionsState);\n\n const { openSessions, closedSessions } = useMemo(() => {\n return {\n openSessions: sessionsState.data.filter((s) => s.isOpened === true),\n closedSessions: sessionsState.data.filter((s) => s.isOpened === false),\n };\n }, [sessionsState.data]);\n\n const canCreateNewSession = useMemo(() => {\n if (oneOpenSessionAllowed) {\n return openSessions.length === 0;\n }\n return true;\n }, [oneOpenSessionAllowed, openSessions.length]);\n\n return {\n sessionState,\n sessionsState,\n loadMoreSessions: widgetCtx.sessionCtx.loadMoreSessions,\n resolveSession: widgetCtx.sessionCtx.resolveSession,\n createStateCheckpoint: widgetCtx.sessionCtx.createStateCheckpoint,\n openSessions,\n closedSessions,\n canCreateNewSession,\n };\n}\n","import { useMessages } from './useMessages';\nimport { useSessions } from './useSessions';\n\nexport function useIsAwaitingBotReply() {\n const { sessionState } = useSessions();\n const { messagesState } = useMessages();\n\n const isSessionAssignedToAI = sessionState.session?.assignee.kind === 'ai';\n // This check is useful in cases where the user might navigate in and out of a chat, and `isSendingMessage` is reset back to its default value\n const lastMessage =\n messagesState.messages.length > 0\n ? messagesState.messages[messagesState.messages.length - 1]\n : null;\n const isLastMessageAUserMessage = lastMessage?.type === 'FROM_USER';\n\n const isAwaitingBotReply =\n (isSessionAssignedToAI || sessionState.isCreatingSession) &&\n (messagesState.isSendingMessage || isLastMessageAUserMessage);\n\n return { isAwaitingBotReply };\n}\n","import useSWR from 'swr';\nimport { useWidget } from '../WidgetProvider';\n\nfunction usePreludeData() {\n const { widgetCtx } = useWidget();\n\n // TODO remove swr dependency\n return useSWR([widgetCtx.config.token], widgetCtx.api.widgetPrelude, {\n revalidateOnFocus: false,\n });\n}\n\nexport { usePreludeData };\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useWidgetRouter() {\n const { widgetCtx } = useWidget();\n\n const routerState = usePrimitiveState(widgetCtx.routerCtx.state);\n\n return {\n routerState,\n toSessionsScreen: widgetCtx.routerCtx.toSessionsScreen,\n toChatScreen: widgetCtx.routerCtx.toChatScreen,\n };\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { v4 } from 'uuid';\n\nconst uploadAbortControllers: Map<string, AbortController> = new Map();\n\ninterface FileWithProgress {\n status: 'pending' | 'uploading' | 'success' | 'error';\n id: string;\n file: File;\n fileUrl?: string;\n progress: number;\n error?: string;\n}\n\nfunction useUploadFiles() {\n const [files, setFiles] = useState<FileWithProgress[]>([]);\n const {\n widgetCtx: { api },\n } = useWidget();\n function appendFiles(files: File[]) {\n const newFiles = files.map((file) => ({\n file,\n id: v4(),\n status: 'pending' as const,\n progress: 0,\n }));\n\n setFiles((prev) => [...prev, ...newFiles]);\n newFiles.forEach(uploadFile);\n }\n\n function updateFileById(id: string, update: Partial<FileWithProgress>) {\n setFiles((prev) =>\n prev.map((f) => (f.id === id ? { ...f, ...update } : f)),\n );\n }\n\n function removeFileById(id: string) {\n setFiles((prev) => prev.filter((f) => f.id !== id));\n }\n\n const uploadFile = async (fileItem: FileWithProgress) => {\n const controller = new AbortController();\n uploadAbortControllers.set(fileItem.id, controller);\n\n try {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === fileItem.id ? { ...f, status: 'uploading', progress: 0 } : f,\n ),\n );\n\n const response = await api.uploadFile({\n file: fileItem.file,\n abortSignal: controller.signal,\n onProgress: (percentage) => {\n updateFileById(fileItem.id, { progress: percentage });\n },\n });\n\n updateFileById(fileItem.id, {\n status: 'success',\n fileUrl: response.fileUrl,\n progress: 100,\n });\n } catch (error) {\n if (!controller.signal.aborted) {\n updateFileById(fileItem.id, {\n status: 'error',\n error: error instanceof Error ? error.message : 'Upload failed',\n progress: 0,\n });\n }\n } finally {\n uploadAbortControllers.delete(fileItem.id);\n }\n };\n\n const handleCancelUpload = (fileId: string) => {\n const controller = uploadAbortControllers.get(fileId);\n if (controller) {\n controller.abort();\n uploadAbortControllers.delete(fileId);\n }\n removeFileById(fileId);\n };\n\n const successFiles = useMemo(() => {\n return files.filter((f) => f.status === 'success' && f.fileUrl);\n }, [files]);\n\n function emptyTheFiles() {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n setFiles([]);\n }\n\n useEffect(() => {\n return () => {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n };\n }, []);\n\n return {\n allFiles: files,\n appendFiles,\n handleCancelUpload,\n successFiles,\n emptyTheFiles,\n getFileById: (id: string) => files.find((f) => f.id === id),\n getUploadProgress: (id: string) =>\n files.find((f) => f.id === id)?.progress ?? 0,\n getUploadStatus: (id: string) => files.find((f) => f.id === id)?.status,\n hasErrors: files.some((f) => f.status === 'error'),\n isUploading: files.some((f) => f.status === 'uploading'),\n };\n}\n\nexport { useUploadFiles, type FileWithProgress };\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n} from 'react';\nimport { useConfig } from './useConfig';\n\ntype WidgetTriggerCtx = {\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n};\n\nconst context = createContext<WidgetTriggerCtx | null>(null);\n\nexport function WidgetTriggerProvider({ children }: { children: ReactNode }) {\n const config = useConfig();\n const [isOpen, setIsOpen] = useState(() => {\n if (config.inline) return true;\n return config.isOpen ?? false;\n });\n\n useEffect(() => {\n setIsOpen((prev) => config.isOpen ?? prev);\n }, [config.isOpen]);\n\n useEffect(() => {\n const openAfterNSeconds = config.openAfterNSeconds;\n if (typeof openAfterNSeconds !== 'number' || isNaN(openAfterNSeconds))\n return;\n\n const timeout = setTimeout(() => setIsOpen(true), openAfterNSeconds * 1000);\n\n return () => clearTimeout(timeout);\n }, [config.openAfterNSeconds]);\n\n return (\n <context.Provider value={{ isOpen, setIsOpen }}>\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidgetTrigger() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error(\n 'useWidgetTrigger must be used within a WidgetTriggerProvider',\n );\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\nimport { useConfig } from './useConfig';\nimport { useSessions } from './useSessions';\n\nexport function useModes() {\n const { widgetCtx } = useWidget();\n const { modesComponents } = useConfig();\n const { sessionState } = useSessions();\n\n const modes = widgetCtx.modes;\n const activeModeId = sessionState.session?.modeId;\n const activeMode = modes.find((mode) => mode.id === activeModeId);\n\n const Component = modesComponents?.find((modeComponent) =>\n [\n activeMode?.id || '',\n activeMode?.name?.toLowerCase() || '',\n activeMode?.slug?.toLowerCase() || '',\n ].includes(modeComponent.key.toLowerCase()),\n )?.component;\n\n return {\n modes,\n modesComponents,\n activeModeId,\n activeMode,\n Component,\n };\n}\n"],"names":["ComponentRegistry","opts","components","c","component","index","key","_a","context","createContext","WidgetProvider","config","children","storage","loadingComponent","contentIframeRef","useRef","didInitialize","widgetCtx","setWidgetCtx","useState","componentStore","useMemo","useEffect","WidgetCtx","React","version","useWidget","ctx","useContext","useConfig","usePrimitiveState","p","useSyncExternalStore","useContact","useDocumentDir","dir","setDir","updateDir","observer","useMessages","useSessions","oneOpenSessionAllowed","sessionState","sessionsState","openSessions","closedSessions","s","canCreateNewSession","useIsAwaitingBotReply","messagesState","isSessionAssignedToAI","lastMessage","isLastMessageAUserMessage","usePreludeData","useSWR","useWidgetRouter","uploadAbortControllers","useUploadFiles","files","setFiles","api","appendFiles","newFiles","file","v4","prev","uploadFile","updateFileById","id","update","removeFileById","f","fileItem","controller","response","percentage","error","handleCancelUpload","fileId","successFiles","emptyTheFiles","WidgetTriggerProvider","isOpen","setIsOpen","openAfterNSeconds","timeout","useWidgetTrigger","useModes","modesComponents","modes","activeModeId","activeMode","mode","Component","_b","modeComponent"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/ComponentRegistry.ts","../src/WidgetProvider.tsx","../src/hooks/useConfig.ts","../src/hooks/usePrimitiveState.ts","../src/hooks/useContact.ts","../src/hooks/useDocumentDir.ts","../src/hooks/useMessages.ts","../src/hooks/useSessions.ts","../src/hooks/useIsAwaitingBotReply.ts","../src/hooks/usePreludeData.ts","../src/hooks/useWidgetRouter.ts","../src/hooks/useUploadFiles.ts","../src/hooks/useWidgetTrigger.tsx","../src/hooks/useModes.ts"],"sourcesContent":["import type { WidgetComponentKey } from '@opencx/widget-core';\nimport type { WidgetComponentType } from './types/components';\n\nexport class ComponentRegistry {\n components: WidgetComponentType[] = [];\n\n constructor(opts: { components?: WidgetComponentType[] }) {\n const { components } = opts;\n\n if (components) {\n components.forEach((c) => this.register(c));\n }\n\n if (this.components.length === 0) {\n throw new Error('No components registered');\n }\n if (!this.get('fallback')) {\n throw new Error('No fallback component registered');\n }\n }\n\n // TODO test that this registers or replaces the component\n register(component: WidgetComponentType) {\n // Replace the key if it already exists\n const index = this.components.findIndex((c) => c.key === component.key);\n if (index !== -1) {\n this.components[index] = component;\n } else {\n this.components.push(component);\n }\n return this;\n }\n\n private get(key: WidgetComponentKey) {\n const c = this.components.find(\n (c) => c.key.toUpperCase() === key.toUpperCase(),\n );\n if (c) return c;\n return null;\n }\n\n public getComponent(key: string) {\n return this.get(key)?.component;\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { version } from '../package.json';\nimport { type ExternalStorage, type WidgetConfig, WidgetCtx } from '@opencx/widget-core';\nimport { ComponentRegistry } from './ComponentRegistry';\nimport type { WidgetComponentType } from './types/components';\n\ninterface WidgetProviderValue {\n widgetCtx: WidgetCtx;\n config: WidgetConfig;\n components?: WidgetComponentType[];\n componentStore: ComponentRegistry;\n version: string;\n contentIframeRef?: React.MutableRefObject<HTMLIFrameElement | null>;\n}\n\nconst context = createContext<WidgetProviderValue | null>(null);\n\nexport function WidgetProvider({\n options: config,\n children,\n components,\n storage,\n loadingComponent,\n}: {\n options: WidgetConfig;\n children: React.ReactNode;\n components?: WidgetComponentType[];\n storage?: ExternalStorage;\n /**\n * Custom loading component while the widget is initializing\n * Not to be confused with the `loading` custom component which renders when the bot's reply is pending\n */\n loadingComponent?: React.ReactNode;\n}) {\n const contentIframeRef = useRef<HTMLIFrameElement | null>(null);\n\n const didInitialize = useRef(false);\n const [widgetCtx, setWidgetCtx] = useState<WidgetCtx | null>(null);\n\n const componentStore = useMemo(\n () =>\n new ComponentRegistry({\n components: components,\n }),\n [components],\n );\n\n useEffect(() => {\n if (didInitialize.current) return;\n didInitialize.current = true;\n\n WidgetCtx.initialize({ config, storage }).then(setWidgetCtx);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n if (!widgetCtx) {\n return loadingComponent || null;\n }\n\n return (\n <context.Provider\n value={{\n widgetCtx,\n config,\n components,\n componentStore,\n version,\n contentIframeRef,\n }}\n >\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidget() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useWidget must be used within a WidgetProvider');\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\n\nexport function useConfig() {\n const { config } = useWidget();\n\n return config;\n}\n","import { useSyncExternalStore } from 'react';\nimport type { PrimitiveState } from '@opencx/widget-core';\n\nexport function usePrimitiveState<T>(p: PrimitiveState<T>) {\n return useSyncExternalStore(p.subscribe, p.get, p.get);\n}\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useContact() {\n const { widgetCtx } = useWidget();\n const contactState = usePrimitiveState(widgetCtx.contactCtx.state);\n\n return {\n contactState,\n createUnverifiedContact: widgetCtx.contactCtx.createUnverifiedContact,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { StringOrLiteral } from '@opencx/widget-core';\n\nexport function useDocumentDir() {\n const [dir, setDir] = useState<StringOrLiteral<'ltr' | 'rtl'>>('ltr');\n\n useEffect(() => {\n const updateDir = () => {\n if (typeof document === 'undefined') return;\n setDir(\n window.getComputedStyle((window.top || window).document.body).direction,\n );\n };\n\n // Set initial direction\n updateDir();\n\n // Watch for direction changes on both document and documentElement\n const observer = new MutationObserver(updateDir);\n\n // Observe both document and documentElement\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n observer.observe(document.body, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n\n // Add event listener for dynamic changes\n window.addEventListener('languagechange', updateDir);\n\n return () => {\n observer.disconnect();\n window.removeEventListener('languagechange', updateDir);\n };\n }, []);\n\n return { dir };\n}\n","import { usePrimitiveState } from './usePrimitiveState';\nimport { useWidget } from '../WidgetProvider';\n\nexport function useMessages() {\n const { widgetCtx } = useWidget();\n const messagesState = usePrimitiveState(widgetCtx.messageCtx.state);\n\n return { messagesState, sendMessage: widgetCtx.messageCtx.sendMessage };\n}\n","import { useMemo } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\nimport { useConfig } from './useConfig';\n\nexport function useSessions() {\n const { widgetCtx } = useWidget();\n const { oneOpenSessionAllowed } = useConfig();\n const sessionState = usePrimitiveState(widgetCtx.sessionCtx.sessionState);\n const sessionsState = usePrimitiveState(widgetCtx.sessionCtx.sessionsState);\n\n const { openSessions, closedSessions } = useMemo(() => {\n return {\n openSessions: sessionsState.data.filter((s) => s.isOpened === true),\n closedSessions: sessionsState.data.filter((s) => s.isOpened === false),\n };\n }, [sessionsState.data]);\n\n const canCreateNewSession = useMemo(() => {\n if (oneOpenSessionAllowed) {\n return openSessions.length === 0;\n }\n return true;\n }, [oneOpenSessionAllowed, openSessions.length]);\n\n return {\n sessionState,\n sessionsState,\n loadMoreSessions: widgetCtx.sessionCtx.loadMoreSessions,\n resolveSession: widgetCtx.sessionCtx.resolveSession,\n createStateCheckpoint: widgetCtx.sessionCtx.createStateCheckpoint,\n openSessions,\n closedSessions,\n canCreateNewSession,\n };\n}\n","import { useMessages } from './useMessages';\nimport { useSessions } from './useSessions';\n\nexport function useIsAwaitingBotReply() {\n const { sessionState } = useSessions();\n const { messagesState } = useMessages();\n\n const isSessionAssignedToAI = sessionState.session?.assignee.kind === 'ai';\n // This check is useful in cases where the user might navigate in and out of a chat, and `isSendingMessage` is reset back to its default value\n const lastMessage =\n messagesState.messages.length > 0\n ? messagesState.messages[messagesState.messages.length - 1]\n : null;\n const isLastMessageAUserMessage = lastMessage?.type === 'FROM_USER';\n\n const isAwaitingBotReply =\n (isSessionAssignedToAI || sessionState.isCreatingSession) &&\n (messagesState.isSendingMessage || isLastMessageAUserMessage);\n\n return { isAwaitingBotReply };\n}\n","import useSWR from 'swr';\nimport { useWidget } from '../WidgetProvider';\n\nfunction usePreludeData() {\n const { widgetCtx } = useWidget();\n\n // TODO remove swr dependency\n return useSWR([widgetCtx.config.token], widgetCtx.api.widgetPrelude, {\n revalidateOnFocus: false,\n });\n}\n\nexport { usePreludeData };\n","import { useWidget } from '../WidgetProvider';\nimport { usePrimitiveState } from './usePrimitiveState';\n\nexport function useWidgetRouter() {\n const { widgetCtx } = useWidget();\n\n const routerState = usePrimitiveState(widgetCtx.routerCtx.state);\n\n return {\n routerState,\n toSessionsScreen: widgetCtx.routerCtx.toSessionsScreen,\n toChatScreen: widgetCtx.routerCtx.toChatScreen,\n };\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport { useWidget } from '../WidgetProvider';\nimport { v4 } from 'uuid';\n\nconst uploadAbortControllers: Map<string, AbortController> = new Map();\n\ninterface FileWithProgress {\n status: 'pending' | 'uploading' | 'success' | 'error';\n id: string;\n file: File;\n fileUrl?: string;\n progress: number;\n error?: string;\n}\n\nfunction useUploadFiles() {\n const [files, setFiles] = useState<FileWithProgress[]>([]);\n const {\n widgetCtx: { api },\n } = useWidget();\n function appendFiles(files: File[]) {\n const newFiles = files.map((file) => ({\n file,\n id: v4(),\n status: 'pending' as const,\n progress: 0,\n }));\n\n setFiles((prev) => [...prev, ...newFiles]);\n newFiles.forEach(uploadFile);\n }\n\n function updateFileById(id: string, update: Partial<FileWithProgress>) {\n setFiles((prev) =>\n prev.map((f) => (f.id === id ? { ...f, ...update } : f)),\n );\n }\n\n function removeFileById(id: string) {\n setFiles((prev) => prev.filter((f) => f.id !== id));\n }\n\n const uploadFile = async (fileItem: FileWithProgress) => {\n const controller = new AbortController();\n uploadAbortControllers.set(fileItem.id, controller);\n\n try {\n setFiles((prev) =>\n prev.map((f) =>\n f.id === fileItem.id ? { ...f, status: 'uploading', progress: 0 } : f,\n ),\n );\n\n const response = await api.uploadFile({\n file: fileItem.file,\n abortSignal: controller.signal,\n onProgress: (percentage) => {\n updateFileById(fileItem.id, { progress: percentage });\n },\n });\n\n updateFileById(fileItem.id, {\n status: 'success',\n fileUrl: response.fileUrl,\n progress: 100,\n });\n } catch (error) {\n if (!controller.signal.aborted) {\n updateFileById(fileItem.id, {\n status: 'error',\n error: error instanceof Error ? error.message : 'Upload failed',\n progress: 0,\n });\n }\n } finally {\n uploadAbortControllers.delete(fileItem.id);\n }\n };\n\n const handleCancelUpload = (fileId: string) => {\n const controller = uploadAbortControllers.get(fileId);\n if (controller) {\n controller.abort();\n uploadAbortControllers.delete(fileId);\n }\n removeFileById(fileId);\n };\n\n const successFiles = useMemo(() => {\n return files.filter((f) => f.status === 'success' && f.fileUrl);\n }, [files]);\n\n function emptyTheFiles() {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n setFiles([]);\n }\n\n useEffect(() => {\n return () => {\n uploadAbortControllers.forEach((controller) => controller.abort());\n uploadAbortControllers.clear();\n };\n }, []);\n\n return {\n allFiles: files,\n appendFiles,\n handleCancelUpload,\n successFiles,\n emptyTheFiles,\n getFileById: (id: string) => files.find((f) => f.id === id),\n getUploadProgress: (id: string) =>\n files.find((f) => f.id === id)?.progress ?? 0,\n getUploadStatus: (id: string) => files.find((f) => f.id === id)?.status,\n hasErrors: files.some((f) => f.status === 'error'),\n isUploading: files.some((f) => f.status === 'uploading'),\n };\n}\n\nexport { useUploadFiles, type FileWithProgress };\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n} from 'react';\nimport { useConfig } from './useConfig';\n\ntype WidgetTriggerCtx = {\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n};\n\nconst context = createContext<WidgetTriggerCtx | null>(null);\n\nexport function WidgetTriggerProvider({ children }: { children: ReactNode }) {\n const config = useConfig();\n const [isOpen, setIsOpen] = useState(() => {\n if (config.inline) return true;\n return config.isOpen ?? false;\n });\n\n useEffect(() => {\n setIsOpen((prev) => config.isOpen ?? prev);\n }, [config.isOpen]);\n\n useEffect(() => {\n const openAfterNSeconds = config.openAfterNSeconds;\n if (typeof openAfterNSeconds !== 'number' || isNaN(openAfterNSeconds))\n return;\n\n const timeout = setTimeout(() => setIsOpen(true), openAfterNSeconds * 1000);\n\n return () => clearTimeout(timeout);\n }, [config.openAfterNSeconds]);\n\n return (\n <context.Provider value={{ isOpen, setIsOpen }}>\n {children}\n </context.Provider>\n );\n}\n\nexport function useWidgetTrigger() {\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error(\n 'useWidgetTrigger must be used within a WidgetTriggerProvider',\n );\n }\n return ctx;\n}\n","import { useWidget } from '../WidgetProvider';\nimport { useConfig } from './useConfig';\nimport { useSessions } from './useSessions';\n\nexport function useModes() {\n const { widgetCtx } = useWidget();\n const { modesComponents } = useConfig();\n const { sessionState } = useSessions();\n\n const modes = widgetCtx.modes;\n const activeModeId = sessionState.session?.modeId;\n const activeMode = modes.find((mode) => mode.id === activeModeId);\n\n const Component = modesComponents?.find((modeComponent) =>\n [\n activeMode?.id || '',\n activeMode?.name?.toLowerCase() || '',\n activeMode?.slug?.toLowerCase() || '',\n ].includes(modeComponent.key.toLowerCase()),\n )?.component;\n\n return {\n modes,\n modesComponents,\n activeModeId,\n activeMode,\n Component,\n };\n}\n"],"names":["ComponentRegistry","opts","components","c","component","index","key","_a","context","createContext","WidgetProvider","config","children","storage","loadingComponent","contentIframeRef","useRef","didInitialize","widgetCtx","setWidgetCtx","useState","componentStore","useMemo","useEffect","WidgetCtx","React","version","useWidget","ctx","useContext","useConfig","usePrimitiveState","p","useSyncExternalStore","useContact","useDocumentDir","dir","setDir","updateDir","observer","useMessages","useSessions","oneOpenSessionAllowed","sessionState","sessionsState","openSessions","closedSessions","s","canCreateNewSession","useIsAwaitingBotReply","messagesState","isSessionAssignedToAI","lastMessage","isLastMessageAUserMessage","usePreludeData","useSWR","useWidgetRouter","uploadAbortControllers","useUploadFiles","files","setFiles","api","appendFiles","newFiles","file","v4","prev","uploadFile","updateFileById","id","update","removeFileById","f","fileItem","controller","response","percentage","error","handleCancelUpload","fileId","successFiles","emptyTheFiles","WidgetTriggerProvider","isOpen","setIsOpen","openAfterNSeconds","timeout","useWidgetTrigger","useModes","modesComponents","modes","activeModeId","activeMode","mode","Component","_b","modeComponent"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  import { StringOrLiteral } from '@opencx/widget-core';
2
- declare const useDocumentDir: () => StringOrLiteral<"ltr" | "rtl">;
3
- export { useDocumentDir };
2
+ export declare function useDocumentDir(): {
3
+ dir: StringOrLiteral<"ltr" | "rtl">;
4
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@opencx/widget-react-headless",
3
3
  "private": false,
4
- "version": "4.0.2",
4
+ "version": "4.0.3",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "swr": "^2.2.5",
22
22
  "uuid": "^11.0.4",
23
- "@opencx/widget-core": "4.0.2"
23
+ "@opencx/widget-core": "4.0.3"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@types/react": ">=18 <20",
@@ -29,8 +29,8 @@
29
29
  "react-dom": ">=18 <20"
30
30
  },
31
31
  "devDependencies": {
32
- "@opencx/eslint-config": "0.0.0",
33
- "@opencx/tsconfig": "0.0.0"
32
+ "@opencx/tsconfig": "0.0.0",
33
+ "@opencx/eslint-config": "0.0.0"
34
34
  },
35
35
  "scripts": {
36
36
  "clean": "rm -rf node_modules dist .turbo",