@channlize/react 0.1.0 → 0.3.0
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/CHANGELOG.md +55 -0
- package/README.md +99 -25
- package/dist/index.d.mts +236 -42
- package/dist/index.d.ts +236 -42
- package/dist/index.js +2252 -657
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2278 -662
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -16
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/context/ChannlizeContext.tsx","../src/hooks/useContactForm.ts","../src/hooks/useChatSession.ts","../src/components/Form.tsx","../src/components/ContactForm.tsx","../src/components/SupportChat.tsx","../src/components/ChannlizeChat.tsx"],"sourcesContent":["/**\n * @channlize/react\n * React SDK for Channlize platform\n */\n\n// Context and Provider\nexport { ChannlizeProvider, useChannlize } from './context/ChannlizeContext';\n\n// Hooks\nexport { useContactForm } from './hooks/useContactForm';\nexport { useChatSession } from './hooks/useChatSession';\n\n// Components\nexport { ContactForm } from './components/ContactForm';\nexport { SupportChat } from './components/SupportChat';\nexport { ChannlizeChat } from './components/ChannlizeChat'; // All-in-one component\n\n// Re-export types from core package\nexport type {\n ChannlizeConfig,\n ContactFormData,\n ChatMessage,\n ChatSession,\n FileAttachment,\n CreateContactResponse,\n CreateChatSessionResponse,\n SendMessageResponse,\n ChannlizeError,\n ValidationError,\n AuthenticationError,\n RateLimitError,\n} from '@channlize/core';\n","import { createContext, useContext, ReactNode } from 'react';\nimport { ChannlizeClient, ChannlizeConfig } from '@channlize/core';\n\ninterface ChannlizeContextValue {\n client: ChannlizeClient;\n config: ChannlizeConfig;\n}\n\nconst ChannlizeContext = createContext<ChannlizeContextValue | null>(null);\n\nexport interface ChannlizeProviderProps {\n config: ChannlizeConfig;\n children: ReactNode;\n}\n\n/**\n * Provider component that makes Channlize client available to all child components\n */\nexport function ChannlizeProvider({ config, children }: ChannlizeProviderProps) {\n const client = new ChannlizeClient(config);\n\n return (\n <ChannlizeContext.Provider value={{ client, config }}>\n {children}\n </ChannlizeContext.Provider>\n );\n}\n\n/**\n * Hook to access the Channlize client and configuration\n */\nexport function useChannlize(): ChannlizeContextValue {\n const context = useContext(ChannlizeContext);\n \n if (!context) {\n throw new Error('useChannlize must be used within a ChannlizeProvider');\n }\n \n return context;\n}\n","import { useState, useCallback } from 'react';\nimport { useChannlize } from '../context/ChannlizeContext';\nimport type { ContactFormData, CreateContactResponse, ChannlizeError } from '@channlize/core';\n\nexport interface UseContactFormOptions {\n onSuccess?: (response: CreateContactResponse) => void;\n onError?: (error: ChannlizeError) => void;\n}\n\nexport interface UseContactFormReturn {\n submit: (data: ContactFormData) => Promise<void>;\n isSubmitting: boolean;\n isSuccess: boolean;\n error: ChannlizeError | null;\n reset: () => void;\n}\n\n/**\n * Hook for handling contact form submissions\n */\nexport function useContactForm(options: UseContactFormOptions = {}): UseContactFormReturn {\n const { client } = useChannlize();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isSuccess, setIsSuccess] = useState(false);\n const [error, setError] = useState<ChannlizeError | null>(null);\n\n const submit = useCallback(\n async (data: ContactFormData) => {\n setIsSubmitting(true);\n setError(null);\n setIsSuccess(false);\n\n try {\n const response = await client.submitContactForm(data);\n setIsSuccess(true);\n options.onSuccess?.(response);\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n } finally {\n setIsSubmitting(false);\n }\n },\n [client, options]\n );\n\n const reset = useCallback(() => {\n setIsSubmitting(false);\n setIsSuccess(false);\n setError(null);\n }, []);\n\n return {\n submit,\n isSubmitting,\n isSuccess,\n error,\n reset,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useChannlize } from '../context/ChannlizeContext';\nimport type {\n ChatSession,\n ChatMessage,\n CreateChatSessionResponse,\n ChannlizeError,\n} from '@channlize/core';\n\nexport interface UseChatSessionOptions {\n autoConnect?: boolean;\n metadata?: Record<string, unknown>;\n onMessage?: (message: ChatMessage) => void;\n onError?: (error: ChannlizeError) => void;\n sessionId?: string; // Optional: Resume existing session\n persistSession?: boolean; // Whether to persist session in localStorage\n storageKey?: string; // Custom localStorage key\n}\n\nexport interface UseChatSessionReturn {\n session: ChatSession | null;\n messages: ChatMessage[];\n isConnecting: boolean;\n isConnected: boolean;\n error: ChannlizeError | null;\n sendMessage: (content: string, attachments?: File[]) => Promise<void>;\n startSession: () => Promise<void>;\n endSession: () => Promise<void>;\n}\n\n/**\n * Hook for managing chat sessions with real-time messaging\n */\nexport function useChatSession(options: UseChatSessionOptions = {}): UseChatSessionReturn {\n const { client, config } = useChannlize();\n const [session, setSession] = useState<ChatSession | null>(null);\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [isConnecting, setIsConnecting] = useState(false);\n const [isConnected, setIsConnected] = useState(false);\n const [error, setError] = useState<ChannlizeError | null>(null);\n \n const eventSourceRef = useRef<EventSource | null>(null);\n const sessionRef = useRef<ChatSession | null>(null);\n const isInitializedRef = useRef(false);\n const baseUrl = config.baseUrl || 'https://api.channlize.com';\n \n const storageKey = options.storageKey || `channlize_session_${config.apiKey}`;\n const persistSession = options.persistSession ?? true; // Default to true\n\n // Update ref when session changes\n useEffect(() => {\n sessionRef.current = session;\n }, [session]);\n\n // LocalStorage helpers\n const saveSessionToStorage = useCallback((sessionId: string) => {\n if (persistSession && typeof window !== 'undefined') {\n try {\n localStorage.setItem(storageKey, sessionId);\n } catch (err) {\n console.warn('Failed to save session to localStorage:', err);\n }\n }\n }, [persistSession, storageKey]);\n\n const getSessionFromStorage = useCallback((): string | null => {\n if (persistSession && typeof window !== 'undefined') {\n try {\n return localStorage.getItem(storageKey);\n } catch (err) {\n console.warn('Failed to get session from localStorage:', err);\n }\n }\n return null;\n }, [persistSession, storageKey]);\n\n const clearSessionFromStorage = useCallback(() => {\n if (persistSession && typeof window !== 'undefined') {\n try {\n localStorage.removeItem(storageKey);\n } catch (err) {\n console.warn('Failed to clear session from localStorage:', err);\n }\n }\n }, [persistSession, storageKey]);\n\n const connectToSSE = useCallback((sseEndpoint: string) => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close();\n }\n\n // Construct full URL for SSE endpoint\n const fullUrl = sseEndpoint.startsWith('http') \n ? sseEndpoint \n : `${baseUrl}${sseEndpoint}`;\n \n const eventSource = new EventSource(fullUrl);\n eventSourceRef.current = eventSource;\n\n eventSource.onopen = () => {\n setIsConnected(true);\n setError(null);\n };\n\n // Listen for 'connected' event\n eventSource.addEventListener('connected', (event) => {\n console.log('SSE connected:', event.data);\n });\n\n // Listen for 'message' event (custom event type from backend)\n eventSource.addEventListener('message', (event: MessageEvent) => {\n try {\n console.log('SSE message:', event.data);\n const message = JSON.parse(event.data);\n \n // Backend sends message object directly in event.data\n const chatMessage: ChatMessage = {\n ...message,\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n \n // Add message only if it doesn't already exist (avoid duplicates from optimistic updates)\n setMessages(prev => {\n const exists = prev.some(m => m.id === chatMessage.id);\n return exists ? prev : [...prev, chatMessage];\n });\n options.onMessage?.(chatMessage);\n } catch (err) {\n console.warn('Failed to parse SSE message:', err, event.data);\n }\n });\n\n // Also handle default onmessage for backwards compatibility\n eventSource.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data);\n \n // Handle wrapped format: {type: 'message', message: {...}}\n if (data.type === 'message' && data.message) {\n const message: ChatMessage = {\n ...data.message,\n timestamp: data.message.timestamp ? new Date(data.message.timestamp) : new Date(),\n };\n \n setMessages(prev => {\n const exists = prev.some(m => m.id === message.id);\n return exists ? prev : [...prev, message];\n });\n options.onMessage?.(message);\n }\n } catch (err) {\n console.warn('Failed to parse default SSE message:', err);\n }\n };\n\n eventSource.onerror = () => {\n setIsConnected(false);\n eventSource.close();\n eventSourceRef.current = null;\n const error = new Error('Connection lost') as ChannlizeError;\n setError(error);\n options.onError?.(error);\n };\n }, [baseUrl, options.onError, options.onMessage]);\n\n const startSession = useCallback(async () => {\n if (isConnecting || session) return;\n\n setIsConnecting(true);\n setError(null);\n\n try {\n // Check for existing session ID (from options or localStorage)\n const existingSessionId = options.sessionId || getSessionFromStorage();\n \n if (existingSessionId) {\n // Try to resume existing session\n try {\n console.log('📦 Resuming session from storage:', existingSessionId);\n const existingSession = await client.getChatSession(existingSessionId);\n const existingMessages = await client.getChatMessages(existingSessionId);\n \n setSession(existingSession);\n \n // Normalize message timestamps\n const normalizedMessages = existingMessages.map(msg => ({\n ...msg,\n timestamp: msg.timestamp ? new Date(msg.timestamp) : new Date()\n }));\n setMessages(normalizedMessages);\n \n // Reconnect to SSE\n const sseEndpoint = `/v1/chat/sessions/${existingSessionId}/events`;\n connectToSSE(sseEndpoint);\n \n console.log('✅ Session resumed successfully');\n return;\n } catch (err) {\n console.warn('⚠️ Failed to resume session, creating new one:', err);\n // Clear invalid session from storage\n clearSessionFromStorage();\n }\n }\n \n // Create new session\n console.log('🆕 Creating new chat session');\n const response: CreateChatSessionResponse = await client.createChatSession(options.metadata);\n \n setSession(response.session);\n \n // Save session ID to localStorage\n saveSessionToStorage(response.session.id);\n \n // Normalize message timestamps to ensure they're valid Date objects\n const normalizedMessages = (response.session.messages || []).map(msg => ({\n ...msg,\n timestamp: msg.timestamp ? new Date(msg.timestamp) : new Date()\n }));\n setMessages(normalizedMessages);\n \n if (response.sseEndpoint) {\n connectToSSE(response.sseEndpoint);\n }\n \n console.log('✅ New session created:', response.session.id);\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n } finally {\n setIsConnecting(false);\n }\n }, [client, connectToSSE, options.metadata, options.onError, options.sessionId, getSessionFromStorage, saveSessionToStorage, clearSessionFromStorage, isConnecting, session]);\n\n const sendMessage = useCallback(\n async (content: string, attachments?: File[]) => {\n if (!sessionRef.current) {\n throw new Error('No active chat session');\n }\n\n try {\n const response = await client.sendMessage(\n sessionRef.current.id,\n content,\n attachments\n );\n \n // Only add if not already present (SSE might have already added it)\n setMessages(prev => {\n const exists = prev.some(m => m.id === response.message.id);\n if (exists) return prev;\n \n const message = {\n ...response.message,\n timestamp: response.message.timestamp \n ? new Date(response.message.timestamp)\n : new Date()\n };\n return [...prev, message];\n });\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n throw error;\n }\n },\n [client, options.onError]\n );\n\n const endSession = useCallback(async () => {\n if (!sessionRef.current) return;\n\n try {\n await client.closeChatSession(sessionRef.current.id);\n \n if (eventSourceRef.current) {\n eventSourceRef.current.close();\n eventSourceRef.current = null;\n }\n \n // Clear session from localStorage\n clearSessionFromStorage();\n \n setSession(null);\n setMessages([]);\n setIsConnected(false);\n \n console.log('✅ Session ended and cleared from storage');\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n }\n }, [client, options.onError, clearSessionFromStorage]);\n\n // Auto-connect when autoConnect becomes true\n useEffect(() => {\n if (options.autoConnect && !session && !isConnecting && !isInitializedRef.current) {\n isInitializedRef.current = true;\n startSession();\n }\n \n return () => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close();\n }\n };\n }, [options.autoConnect, session, isConnecting, startSession]);\n\n return {\n session,\n messages,\n isConnecting,\n isConnected,\n error,\n sendMessage,\n startSession,\n endSession,\n };\n}\n","import { useState, FormEvent } from 'react';\nimport { useContactForm } from '../hooks/useContactForm';\nimport type { ContactFormData } from '@channlize/core';\n\nexport interface FormProps {\n /** Custom fields to include in the form */\n customFields?: Array<{\n name: string;\n label: string;\n type: 'text' | 'email' | 'textarea' | 'select';\n required?: boolean;\n options?: string[]; // For select fields\n }>;\n /** Callback when form is successfully submitted */\n onSuccess?: () => void;\n /** Callback when form submission fails */\n onError?: (error: Error) => void;\n /** Custom CSS classes */\n className?: string;\n /** Custom styles for form elements */\n styles?: {\n form?: React.CSSProperties;\n field?: React.CSSProperties;\n label?: React.CSSProperties;\n input?: React.CSSProperties;\n textarea?: React.CSSProperties;\n button?: React.CSSProperties;\n error?: React.CSSProperties;\n success?: React.CSSProperties;\n };\n /** Button text */\n submitText?: string;\n /** Success message */\n successMessage?: string;\n}\n\n/**\n * Form component that submits inquiries to Channlize\n */\nexport function Form({\n customFields = [],\n onSuccess,\n onError,\n className = '',\n styles = {},\n submitText = 'Send Message',\n successMessage = 'Thank you! Your message has been sent.',\n}: FormProps) {\n const [formData, setFormData] = useState<Partial<ContactFormData>>({\n name: '',\n email: '',\n subject: '',\n message: '',\n customFields: {},\n });\n\n const { submit, isSubmitting, isSuccess, error, reset } = useContactForm({\n onSuccess: () => {\n setFormData({\n name: '',\n email: '',\n subject: '',\n message: '',\n customFields: {},\n });\n onSuccess?.();\n },\n onError,\n });\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n \n if (!formData.name || !formData.email || !formData.message) {\n return;\n }\n\n await submit(formData as ContactFormData);\n };\n\n const handleInputChange = (field: keyof ContactFormData, value: string) => {\n setFormData(prev => ({ ...prev, [field]: value }));\n };\n\n const handleCustomFieldChange = (fieldName: string, value: string) => {\n setFormData(prev => ({\n ...prev,\n customFields: {\n ...prev.customFields,\n [fieldName]: value,\n },\n }));\n };\n\n if (isSuccess) {\n return (\n <div className={`channlize-form-success ${className}`} style={styles.success}>\n <p>{successMessage}</p>\n <button\n type=\"button\"\n onClick={reset}\n style={styles.button}\n >\n Send Another Message\n </button>\n </div>\n );\n }\n\n return (\n <form\n className={`channlize-form ${className}`}\n style={styles.form}\n onSubmit={handleSubmit}\n >\n <div className=\"channlize-field\" style={styles.field}>\n <label htmlFor=\"channlize-name\" style={styles.label}>\n Name *\n </label>\n <input\n id=\"channlize-name\"\n type=\"text\"\n value={formData.name || ''}\n onChange={e => handleInputChange('name', e.target.value)}\n required\n style={styles.input}\n />\n </div>\n\n <div className=\"channlize-field\" style={styles.field}>\n <label htmlFor=\"channlize-email\" style={styles.label}>\n Email *\n </label>\n <input\n id=\"channlize-email\"\n type=\"email\"\n value={formData.email || ''}\n onChange={e => handleInputChange('email', e.target.value)}\n required\n style={styles.input}\n />\n </div>\n\n <div className=\"channlize-field\" style={styles.field}>\n <label htmlFor=\"channlize-subject\" style={styles.label}>\n Subject\n </label>\n <input\n id=\"channlize-subject\"\n type=\"text\"\n value={formData.subject || ''}\n onChange={e => handleInputChange('subject', e.target.value)}\n style={styles.input}\n />\n </div>\n\n {customFields.map(field => (\n <div key={field.name} className=\"channlize-field\" style={styles.field}>\n <label htmlFor={`channlize-${field.name}`} style={styles.label}>\n {field.label} {field.required && '*'}\n </label>\n \n {field.type === 'select' ? (\n <select\n id={`channlize-${field.name}`}\n value={formData.customFields?.[field.name] as string || ''}\n onChange={e => handleCustomFieldChange(field.name, e.target.value)}\n required={field.required}\n style={styles.input}\n >\n <option value=\"\">Select...</option>\n {field.options?.map(option => (\n <option key={option} value={option}>\n {option}\n </option>\n ))}\n </select>\n ) : field.type === 'textarea' ? (\n <textarea\n id={`channlize-${field.name}`}\n value={formData.customFields?.[field.name] as string || ''}\n onChange={e => handleCustomFieldChange(field.name, e.target.value)}\n required={field.required}\n style={styles.textarea}\n />\n ) : (\n <input\n id={`channlize-${field.name}`}\n type={field.type}\n value={formData.customFields?.[field.name] as string || ''}\n onChange={e => handleCustomFieldChange(field.name, e.target.value)}\n required={field.required}\n style={styles.input}\n />\n )}\n </div>\n ))}\n\n <div className=\"channlize-field\" style={styles.field}>\n <label htmlFor=\"channlize-message\" style={styles.label}>\n Message *\n </label>\n <textarea\n id=\"channlize-message\"\n value={formData.message || ''}\n onChange={e => handleInputChange('message', e.target.value)}\n required\n rows={4}\n style={styles.textarea}\n />\n </div>\n\n {error && (\n <div className=\"channlize-error\" style={styles.error}>\n {error.message}\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={isSubmitting}\n style={styles.button}\n >\n {isSubmitting ? 'Sending...' : submitText}\n </button>\n </form>\n );\n}\n\n\n","import { Form, FormProps } from './Form';\n\n/**\n * ContactForm component - Alias for Form component\n * Provides a form for collecting contact information and messages\n */\nexport function ContactForm(props: FormProps) {\n return <Form {...props} />;\n}\n\n// Re-export FormProps as ContactFormProps for convenience\nexport type ContactFormProps = FormProps;\n\n","import { useState, useEffect, useRef, FormEvent } from 'react';\nimport { useChatSession, UseChatSessionOptions } from '../hooks/useChatSession';\nimport type { ChatMessage } from '@channlize/core';\n\nexport interface SupportChatProps extends UseChatSessionOptions {\n /** Custom CSS classes */\n className?: string;\n /** Custom styles for chat elements */\n styles?: {\n container?: React.CSSProperties;\n header?: React.CSSProperties;\n messagesContainer?: React.CSSProperties;\n message?: React.CSSProperties;\n userMessage?: React.CSSProperties;\n agentMessage?: React.CSSProperties;\n inputContainer?: React.CSSProperties;\n input?: React.CSSProperties;\n button?: React.CSSProperties;\n error?: React.CSSProperties;\n timestamp?: React.CSSProperties;\n };\n /** Placeholder text for message input */\n placeholder?: string;\n /** Header title */\n title?: string;\n /** Button text */\n sendButtonText?: string;\n /** Show timestamps on messages */\n showTimestamps?: boolean;\n /** Allow file attachments */\n allowAttachments?: boolean;\n}\n\n/**\n * SupportChat component - Real-time chat interface\n * Provides a complete chat UI with message history and real-time updates\n */\nexport function SupportChat({\n autoConnect = true,\n metadata,\n onMessage,\n onError,\n sessionId,\n persistSession,\n storageKey,\n className = '',\n styles = {},\n placeholder = 'Type your message...',\n title = 'Support Chat',\n sendButtonText = 'Send',\n showTimestamps = true,\n allowAttachments = false,\n}: SupportChatProps) {\n const [messageInput, setMessageInput] = useState('');\n const [attachments, setAttachments] = useState<File[]>([]);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n const {\n session,\n messages,\n isConnecting,\n isConnected,\n error,\n sendMessage,\n startSession,\n endSession,\n } = useChatSession({\n autoConnect,\n metadata,\n onMessage,\n onError,\n sessionId,\n persistSession,\n storageKey,\n });\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages]);\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n \n if (!messageInput.trim() && attachments.length === 0) return;\n\n try {\n await sendMessage(messageInput, attachments.length > 0 ? attachments : undefined);\n setMessageInput('');\n setAttachments([]);\n } catch (err) {\n console.error('Failed to send message:', err);\n }\n };\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files) {\n setAttachments(Array.from(e.target.files));\n }\n };\n\n const formatTimestamp = (date: Date) => {\n // Check if date is valid\n if (!date || isNaN(date.getTime())) {\n return '';\n }\n \n try {\n return new Intl.DateTimeFormat('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(date);\n } catch (error) {\n console.warn('Failed to format timestamp:', error);\n return '';\n }\n };\n\n if (!session && !isConnecting) {\n return (\n <div className={`channlize-chat-container ${className}`} style={styles.container}>\n <div className=\"channlize-chat-header\" style={styles.header}>\n <h3>{title}</h3>\n </div>\n <div className=\"channlize-chat-start\">\n <button onClick={startSession} style={styles.button}>\n Start Chat\n </button>\n </div>\n {error && (\n <div className=\"channlize-error\" style={styles.error}>\n {error.message}\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className={`channlize-chat-container ${className}`} style={styles.container}>\n <div className=\"channlize-chat-header\" style={styles.header}>\n <h3>{title}</h3>\n <div className=\"channlize-chat-status\" style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>\n {isConnecting && (\n <>\n <span style={{ \n display: 'inline-block',\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: '#f59e0b',\n }} />\n <span>Connecting...</span>\n </>\n )}\n {isConnected && (\n <>\n <span style={{ \n display: 'inline-block',\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: '#10b981',\n }} />\n <span>Connected</span>\n </>\n )}\n {!isConnected && !isConnecting && (\n <>\n <span style={{ \n display: 'inline-block',\n width: '8px',\n height: '8px',\n borderRadius: '50%',\n backgroundColor: '#ef4444',\n }} />\n <span>Disconnected</span>\n </>\n )}\n </div>\n {session && (\n <button\n onClick={endSession}\n style={{ ...styles.button, fontSize: '0.875rem' }}\n type=\"button\"\n >\n End Chat\n </button>\n )}\n </div>\n\n <div className=\"channlize-messages\" style={styles.messagesContainer}>\n {messages.length === 0 && (\n <div style={{ textAlign: 'center', padding: '2rem', color: '#666' }}>\n No messages yet. Start the conversation!\n </div>\n )}\n \n {messages.map((message: ChatMessage, index: number) => (\n <div\n key={message.id || index}\n className={`channlize-message ${\n message.author === 'user' ? 'channlize-message-user' : 'channlize-message-agent'\n }`}\n style={{\n ...styles.message,\n ...(message.author === 'user' ? styles.userMessage : styles.agentMessage),\n }}\n >\n <div className=\"channlize-message-content\">\n {message.content}\n </div>\n {showTimestamps && (\n <div className=\"channlize-message-timestamp\" style={styles.timestamp}>\n {formatTimestamp(message.timestamp)}\n </div>\n )}\n </div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n {error && (\n <div className=\"channlize-error\" style={styles.error}>\n {error.message}\n </div>\n )}\n\n <form\n className=\"channlize-chat-input-container\"\n style={styles.inputContainer}\n onSubmit={handleSubmit}\n >\n {allowAttachments && (\n <div>\n <input\n type=\"file\"\n multiple\n onChange={handleFileChange}\n style={{ fontSize: '0.875rem' }}\n />\n {attachments.length > 0 && (\n <div style={{ fontSize: '0.75rem', marginTop: '0.25rem' }}>\n {attachments.length} file(s) selected\n </div>\n )}\n </div>\n )}\n \n <div style={{ display: 'flex', gap: '0.5rem' }}>\n <input\n type=\"text\"\n value={messageInput}\n onChange={e => setMessageInput(e.target.value)}\n placeholder={placeholder}\n disabled={!session || isConnecting}\n style={{ ...styles.input, flex: 1 }}\n />\n <button\n type=\"submit\"\n disabled={!session || isConnecting || (!messageInput.trim() && attachments.length === 0)}\n style={styles.button}\n >\n {sendButtonText}\n </button>\n </div>\n </form>\n </div>\n );\n}\n\n","import { useState, useEffect, ReactNode } from 'react';\nimport { ChannlizeProvider } from '../context/ChannlizeContext';\nimport { SupportChat } from './SupportChat';\nimport type { ChannlizeConfig } from '@channlize/core';\nimport type { SupportChatProps } from './SupportChat';\n\nexport interface ChannlizeChatProps {\n /** Channlize configuration */\n config: ChannlizeConfig;\n \n /** Position of the floating button */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n \n /** Offset from edges in pixels */\n offset?: { x?: number; y?: number };\n \n /** Custom button element (overrides default button) */\n buttonElement?: ReactNode;\n \n /** Custom button icon (only used if buttonElement is not provided) */\n buttonIcon?: ReactNode;\n \n /** Button size in pixels */\n buttonSize?: number;\n \n /** Button colors */\n buttonColors?: {\n background?: string;\n hover?: string;\n text?: string;\n };\n \n /** Chat window props (passed to SupportChat) */\n chatProps?: Omit<SupportChatProps, 'autoConnect'>;\n \n /** Whether to start closed or open */\n defaultOpen?: boolean;\n \n /** Whether to show badge with unread count */\n showBadge?: boolean;\n \n /** Unread count (for badge) */\n unreadCount?: number;\n \n /** Custom z-index */\n zIndex?: number;\n \n /** Whether to show on mobile */\n showOnMobile?: boolean;\n \n /** Callback when chat opens */\n onOpen?: () => void;\n \n /** Callback when chat closes */\n onClose?: () => void;\n \n /** Whether to enable animations */\n enableAnimations?: boolean;\n \n /** Custom class for button container */\n buttonClassName?: string;\n \n /** Custom class for chat container */\n chatClassName?: string;\n}\n\n/**\n * ChannlizeChat - All-in-one floating chat widget with provider\n * \n * Drop this component anywhere in your React app for instant live chat support.\n * Includes the provider, floating button, and chat window.\n * \n * @example\n * ```tsx\n * <ChannlizeChat\n * config={{\n * apiKey: \"your-widget-key\",\n * projectId: \"your-project-id\",\n * }}\n * position=\"bottom-right\"\n * chatProps={{\n * title: \"Customer Support\",\n * placeholder: \"How can we help?\"\n * }}\n * />\n * ```\n */\nexport function ChannlizeChat({\n config,\n position = 'bottom-right',\n offset = { x: 24, y: 24 },\n buttonElement,\n buttonIcon,\n buttonSize = 56,\n buttonColors = {\n background: '#3b82f6',\n hover: '#2563eb',\n text: '#ffffff',\n },\n chatProps = {},\n defaultOpen = false,\n showBadge = false,\n unreadCount = 0,\n zIndex = 1000,\n showOnMobile = true,\n onOpen,\n onClose,\n enableAnimations = true,\n buttonClassName = '',\n chatClassName = '',\n}: ChannlizeChatProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n const [isMounted, setIsMounted] = useState(false);\n const [isDarkMode, setIsDarkMode] = useState(false);\n\n // Only render on client to avoid hydration mismatch\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n // Detect dark mode preference\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n setIsDarkMode(mediaQuery.matches);\n\n const handler = (e: MediaQueryListEvent) => setIsDarkMode(e.matches);\n mediaQuery.addEventListener('change', handler);\n return () => mediaQuery.removeEventListener('change', handler);\n }, []);\n\n // Don't render on server to avoid hydration issues\n if (!isMounted) {\n return null;\n }\n\n const handleToggle = () => {\n const newState = !isOpen;\n setIsOpen(newState);\n \n if (newState) {\n onOpen?.();\n // Start session when chat is opened\n // The session will be started by the SupportChat component with autoConnect based on isOpen\n } else {\n onClose?.();\n }\n };\n\n // Calculate position styles\n const positionStyles: React.CSSProperties = {\n position: 'fixed',\n zIndex,\n ...(position.includes('bottom') ? { bottom: `${offset.y}px` } : { top: `${offset.y}px` }),\n ...(position.includes('right') ? { right: `${offset.x}px` } : { left: `${offset.x}px` }),\n };\n\n const buttonStyle: React.CSSProperties = {\n width: `${buttonSize}px`,\n height: `${buttonSize}px`,\n borderRadius: '50%',\n backgroundColor: buttonColors.background,\n color: buttonColors.text,\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',\n transition: enableAnimations ? 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)' : 'none',\n transform: enableAnimations && isOpen ? 'scale(0.9)' : 'scale(1)',\n };\n\n const chatContainerStyle: React.CSSProperties = {\n ...positionStyles,\n opacity: isOpen ? 1 : 0,\n visibility: isOpen ? 'visible' : 'hidden',\n transform: enableAnimations \n ? isOpen ? 'scale(1) translateY(0)' : 'scale(0.95) translateY(10px)'\n : 'none',\n transition: enableAnimations \n ? 'opacity 0.2s, transform 0.2s, visibility 0.2s'\n : 'none',\n };\n\n const defaultIcon = (\n <svg\n width={buttonSize * 0.5}\n height={buttonSize * 0.5}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n {isOpen ? (\n <>\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </>\n ) : (\n <>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n <path d=\"M8 10h.01\" />\n <path d=\"M12 10h.01\" />\n <path d=\"M16 10h.01\" />\n </>\n )}\n </svg>\n );\n\n return (\n <ChannlizeProvider config={config}>\n {/* Floating Button */}\n {!isOpen && (\n <div\n style={{\n ...positionStyles,\n display: !showOnMobile && typeof window !== 'undefined' && window.innerWidth < 768 ? 'none' : 'block',\n }}\n className={buttonClassName}\n >\n {buttonElement ? (\n <div onClick={handleToggle} style={{ cursor: 'pointer' }}>\n {buttonElement}\n </div>\n ) : (\n <button\n onClick={handleToggle}\n style={buttonStyle}\n onMouseEnter={(e) => {\n if (enableAnimations) {\n e.currentTarget.style.backgroundColor = buttonColors.hover || buttonColors.background || '#2563eb';\n e.currentTarget.style.transform = 'scale(1.05)';\n }\n }}\n onMouseLeave={(e) => {\n if (enableAnimations) {\n e.currentTarget.style.backgroundColor = buttonColors.background || '#3b82f6';\n e.currentTarget.style.transform = 'scale(1)';\n }\n }}\n aria-label={isOpen ? 'Close chat' : 'Open chat'}\n >\n {buttonIcon || defaultIcon}\n {showBadge && unreadCount > 0 && (\n <span\n style={{\n position: 'absolute',\n top: '-4px',\n right: '-4px',\n backgroundColor: '#ef4444',\n color: 'white',\n borderRadius: '10px',\n padding: '2px 6px',\n fontSize: '12px',\n fontWeight: '600',\n minWidth: '20px',\n textAlign: 'center',\n boxShadow: '0 2px 4px rgba(0,0,0,0.2)',\n }}\n >\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n )}\n </button>\n )}\n </div>\n )}\n\n {/* Chat Window */}\n <div\n style={chatContainerStyle}\n className={chatClassName}\n >\n <SupportChat\n autoConnect={isOpen}\n persistSession={true}\n title=\"Support Chat\"\n placeholder=\"Type your message...\"\n showTimestamps={true}\n {...chatProps}\n styles={{\n container: {\n width: '384px',\n height: '600px',\n maxHeight: 'calc(100vh - 120px)',\n borderRadius: '16px',\n overflow: 'hidden',\n boxShadow: isDarkMode \n ? '0 20px 25px -5px rgb(0 0 0 / 0.4), 0 8px 10px -6px rgb(0 0 0 / 0.5)'\n : '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',\n backgroundColor: isDarkMode ? '#1f2937' : '#ffffff',\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n ...chatProps.styles?.container,\n },\n header: {\n background: 'linear-gradient(135deg, #3b82f6 0%, #9333ea 100%)',\n padding: '20px',\n borderRadius: '16px 16px 0 0',\n color: 'white',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n ...chatProps.styles?.header,\n },\n messagesContainer: {\n flex: 1,\n overflowY: 'auto',\n padding: '20px',\n backgroundColor: isDarkMode ? '#111827' : '#f9fafb',\n ...chatProps.styles?.messagesContainer,\n },\n inputContainer: {\n padding: '16px',\n backgroundColor: isDarkMode ? '#1f2937' : 'white',\n borderTop: `1px solid ${isDarkMode ? '#374151' : '#e5e7eb'}`,\n ...chatProps.styles?.inputContainer,\n },\n input: {\n ...chatProps.styles?.input,\n borderRadius: '12px',\n padding: '12px 16px',\n fontSize: '14px',\n border: `1px solid ${isDarkMode ? '#374151' : '#d1d5db'}`,\n outline: 'none',\n backgroundColor: isDarkMode ? '#374151' : '#ffffff',\n color: isDarkMode ? '#f9fafb' : '#111827',\n fontWeight: '400',\n },\n button: {\n backgroundColor: '#3b82f6',\n color: 'white',\n borderRadius: '12px',\n padding: '12px 24px',\n fontSize: '14px',\n fontWeight: '500',\n border: 'none',\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n ...chatProps.styles?.button,\n },\n userMessage: {\n backgroundColor: '#3b82f6',\n color: 'white',\n padding: '10px 14px',\n borderRadius: '12px 12px 4px 12px',\n marginBottom: '8px',\n marginLeft: 'auto',\n maxWidth: '80%',\n width: 'fit-content',\n ...chatProps.styles?.userMessage,\n },\n agentMessage: {\n backgroundColor: isDarkMode ? '#374151' : 'white',\n color: isDarkMode ? '#f9fafb' : '#1f2937',\n padding: '10px 14px',\n borderRadius: '12px 12px 12px 4px',\n marginBottom: '8px',\n marginRight: 'auto',\n maxWidth: '80%',\n width: 'fit-content',\n boxShadow: isDarkMode \n ? '0 1px 2px 0 rgb(0 0 0 / 0.3)'\n : '0 1px 2px 0 rgb(0 0 0 / 0.05)',\n ...chatProps.styles?.agentMessage,\n },\n timestamp: {\n fontSize: '11px',\n opacity: 0.7,\n marginTop: '4px',\n color: isDarkMode ? '#d1d5db' : 'inherit',\n ...chatProps.styles?.timestamp,\n },\n error: {\n backgroundColor: isDarkMode ? '#7f1d1d' : '#fee2e2',\n color: isDarkMode ? '#fca5a5' : '#991b1b',\n padding: '12px',\n margin: '8px 16px',\n borderRadius: '8px',\n fontSize: '14px',\n ...chatProps.styles?.error,\n },\n }}\n />\n \n {/* Close Button Overlay */}\n <button\n onClick={handleToggle}\n style={{\n position: 'absolute',\n top: '16px',\n right: '16px',\n width: '32px',\n height: '32px',\n borderRadius: '50%',\n backgroundColor: 'rgba(255, 255, 255, 0.2)',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'white',\n transition: 'background-color 0.2s',\n zIndex: 10,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.3)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.2)';\n }}\n aria-label=\"Close chat\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </ChannlizeProvider>\n );\n}\n\n"],"mappings":"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","names":["import_react","error","import_react","error","normalizedMessages","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","error","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context/ChannlizeContext.tsx","../src/hooks/useContactForm.ts","../src/hooks/useChatSession.ts","../src/hooks/useChannlizeAnalytics.ts","../src/components/Form.tsx","../src/components/chat/icons.tsx","../src/components/chat/utils.ts","../src/components/form/styles.ts","../src/components/ContactForm.tsx","../src/components/SupportChat.tsx","../src/components/chat/internal.tsx","../src/components/chat/styles.ts","../src/components/ChannlizeChat.tsx"],"sourcesContent":["/**\n * @channlize/react\n * React SDK for Channlize platform\n */\n\n// Context and Provider\nexport { ChannlizeProvider, useChannlize } from './context/ChannlizeContext';\n\n// Hooks\nexport { useContactForm } from './hooks/useContactForm';\nexport { useChatSession } from './hooks/useChatSession';\nexport { useChannlizeAnalytics } from './hooks/useChannlizeAnalytics';\n\n// Components\nexport {\n ContactForm,\n defaultContactFormLabels,\n} from './components/ContactForm';\nexport type {\n ContactFormProps,\n ContactFieldMode,\n ContactFormCustomField,\n ContactFormLabels,\n ContactFormTheme,\n ContactFormTopic,\n ContactFormValues,\n} from './components/ContactForm';\nexport { SupportChat } from './components/SupportChat';\nexport { ChannlizeChat } from './components/ChannlizeChat'; // All-in-one component\nexport { defaultSupportChatLabels } from './components/SupportChat';\nexport type {\n SupportChatProps,\n SupportChatLabels,\n ChatTheme,\n} from './components/SupportChat';\nexport type { ChannlizeChatProps } from './components/ChannlizeChat';\nexport type {\n UseChatSessionOptions,\n UseChatSessionReturn,\n} from './hooks/useChatSession';\n\n// Re-export types from core package\nexport type {\n ChannlizeConfig,\n ContactFormData,\n ChatMessage,\n ChatSession,\n FileAttachment,\n CreateContactResponse,\n CreateChatSessionResponse,\n SendMessageResponse,\n ChannlizeError,\n ValidationError,\n AuthenticationError,\n RateLimitError,\n TrackEventOptions,\n EventSeverity,\n} from '@channlize/core';\n","import { createContext, useContext, ReactNode } from 'react';\nimport { ChannlizeClient, ChannlizeConfig } from '@channlize/core';\n\ninterface ChannlizeContextValue {\n client: ChannlizeClient;\n config: ChannlizeConfig;\n}\n\nconst ChannlizeContext = createContext<ChannlizeContextValue | null>(null);\n\nexport interface ChannlizeProviderProps {\n config: ChannlizeConfig;\n children: ReactNode;\n}\n\n/**\n * Provider component that makes Channlize client available to all child components\n */\nexport function ChannlizeProvider({\n config,\n children,\n}: ChannlizeProviderProps) {\n const client = new ChannlizeClient(config);\n\n return (\n <ChannlizeContext.Provider value={{ client, config }}>\n {children}\n </ChannlizeContext.Provider>\n );\n}\n\n/**\n * Hook to access the Channlize client and configuration\n */\nexport function useChannlize(): ChannlizeContextValue {\n const context = useContext(ChannlizeContext);\n\n if (!context) {\n throw new Error('useChannlize must be used within a ChannlizeProvider');\n }\n\n return context;\n}\n","import { useState, useCallback } from 'react';\nimport { useChannlize } from '../context/ChannlizeContext';\nimport type {\n ContactFormData,\n CreateContactResponse,\n ChannlizeError,\n} from '@channlize/core';\n\nexport interface UseContactFormOptions {\n onSuccess?: (response: CreateContactResponse) => void;\n onError?: (error: ChannlizeError) => void;\n}\n\nexport interface UseContactFormReturn {\n submit: (data: ContactFormData) => Promise<void>;\n isSubmitting: boolean;\n isSuccess: boolean;\n error: ChannlizeError | null;\n reset: () => void;\n}\n\n/**\n * Hook for handling contact form submissions\n */\nexport function useContactForm(\n options: UseContactFormOptions = {}\n): UseContactFormReturn {\n const { client } = useChannlize();\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isSuccess, setIsSuccess] = useState(false);\n const [error, setError] = useState<ChannlizeError | null>(null);\n\n const submit = useCallback(\n async (data: ContactFormData) => {\n setIsSubmitting(true);\n setError(null);\n setIsSuccess(false);\n\n try {\n const response = await client.submitContactForm(data);\n setIsSuccess(true);\n options.onSuccess?.(response);\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n } finally {\n setIsSubmitting(false);\n }\n },\n [client, options]\n );\n\n const reset = useCallback(() => {\n setIsSubmitting(false);\n setIsSuccess(false);\n setError(null);\n }, []);\n\n return {\n submit,\n isSubmitting,\n isSuccess,\n error,\n reset,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useChannlize } from '../context/ChannlizeContext';\nimport type {\n ChatSession,\n ChatMessage,\n CreateChatSessionResponse,\n ChannlizeError,\n} from '@channlize/core';\n\nexport interface UseChatSessionOptions {\n autoConnect?: boolean;\n metadata?: Record<string, unknown>;\n onMessage?: (message: ChatMessage) => void;\n onError?: (error: ChannlizeError) => void;\n sessionId?: string; // Optional: Resume existing session\n persistSession?: boolean; // Whether to persist session in localStorage\n storageKey?: string; // Custom localStorage key\n}\n\nexport interface UseChatSessionReturn {\n session: ChatSession | null;\n messages: ChatMessage[];\n isConnecting: boolean;\n isConnected: boolean;\n error: ChannlizeError | null;\n sendMessage: (content: string, attachments?: File[]) => Promise<void>;\n startSession: () => Promise<void>;\n endSession: () => Promise<void>;\n /**\n * Reopen the real-time stream for the current session after it failed\n * (`error.code === 'SSE_ERROR'`). Routine reconnects are automatic.\n */\n reconnect: () => void;\n}\n\n/**\n * Hook for managing chat sessions with real-time messaging\n */\nexport function useChatSession(\n options: UseChatSessionOptions = {}\n): UseChatSessionReturn {\n const { client, config } = useChannlize();\n const [session, setSession] = useState<ChatSession | null>(null);\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [isConnecting, setIsConnecting] = useState(false);\n const [isConnected, setIsConnected] = useState(false);\n const [error, setError] = useState<ChannlizeError | null>(null);\n\n const eventSourceRef = useRef<EventSource | null>(null);\n const sessionRef = useRef<ChatSession | null>(null);\n const isInitializedRef = useRef(false);\n const baseUrl = config.baseUrl || 'https://api.channlize.com';\n\n const storageKey = options.storageKey || `channlize_session_${config.apiKey}`;\n const persistSession = options.persistSession ?? true; // Default to true\n\n // Update ref when session changes\n useEffect(() => {\n sessionRef.current = session;\n }, [session]);\n\n // LocalStorage helpers\n const saveSessionToStorage = useCallback(\n (sessionId: string) => {\n if (persistSession && typeof window !== 'undefined') {\n try {\n localStorage.setItem(storageKey, sessionId);\n } catch (err) {\n console.warn('Failed to save session to localStorage:', err);\n }\n }\n },\n [persistSession, storageKey]\n );\n\n const getSessionFromStorage = useCallback((): string | null => {\n if (persistSession && typeof window !== 'undefined') {\n try {\n return localStorage.getItem(storageKey);\n } catch (err) {\n console.warn('Failed to get session from localStorage:', err);\n }\n }\n return null;\n }, [persistSession, storageKey]);\n\n const clearSessionFromStorage = useCallback(() => {\n if (persistSession && typeof window !== 'undefined') {\n try {\n localStorage.removeItem(storageKey);\n } catch (err) {\n console.warn('Failed to clear session from localStorage:', err);\n }\n }\n }, [persistSession, storageKey]);\n\n const connectToSSE = useCallback(\n (sseEndpoint: string) => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close();\n }\n\n // Construct full URL for SSE endpoint\n const fullUrl = sseEndpoint.startsWith('http')\n ? sseEndpoint\n : `${baseUrl}${sseEndpoint}`;\n\n console.log('[Channlize SSE] Connecting to:', fullUrl);\n\n const eventSource = new EventSource(fullUrl);\n eventSourceRef.current = eventSource;\n\n eventSource.onopen = () => {\n console.log('[Channlize SSE] Connection opened');\n setIsConnected(true);\n setError(null);\n };\n\n // Listen for 'connected' event\n eventSource.addEventListener('connected', event => {\n console.log('SSE connected:', event.data);\n });\n\n // Listen for 'message' event (custom event type from backend)\n eventSource.addEventListener('message', (event: MessageEvent) => {\n try {\n console.log('SSE message:', event.data);\n const message = JSON.parse(event.data);\n\n // Backend sends message object directly in event.data\n const chatMessage: ChatMessage = {\n ...message,\n timestamp: message.timestamp\n ? new Date(message.timestamp)\n : new Date(),\n };\n\n // Add message only if it doesn't already exist (avoid duplicates from optimistic updates)\n setMessages(prev => {\n const exists = prev.some(m => m.id === chatMessage.id);\n return exists ? prev : [...prev, chatMessage];\n });\n options.onMessage?.(chatMessage);\n } catch (err) {\n console.warn('Failed to parse SSE message:', err, event.data);\n }\n });\n\n // Also handle default onmessage for backwards compatibility\n eventSource.onmessage = event => {\n try {\n const data = JSON.parse(event.data);\n\n // Handle wrapped format: {type: 'message', message: {...}}\n if (data.type === 'message' && data.message) {\n const message: ChatMessage = {\n ...data.message,\n timestamp: data.message.timestamp\n ? new Date(data.message.timestamp)\n : new Date(),\n };\n\n setMessages(prev => {\n const exists = prev.some(m => m.id === message.id);\n return exists ? prev : [...prev, message];\n });\n options.onMessage?.(message);\n }\n } catch (err) {\n console.warn('Failed to parse default SSE message:', err);\n }\n };\n\n eventSource.onerror = event => {\n // The server ends each stream after ~50s (serverless time limit).\n // The browser then reconnects on its own and resumes from the last\n // message id, so only a CLOSED source is a real failure.\n if (eventSource.readyState === EventSource.CONNECTING) {\n setIsConnected(false);\n return;\n }\n\n console.error('[Channlize SSE] Connection error', {\n readyState: eventSource.readyState,\n url: fullUrl,\n event,\n });\n\n // ReadyState: 0 = CONNECTING, 1 = OPEN, 2 = CLOSED\n const stateMessage =\n eventSource.readyState === 0\n ? 'Failed to connect (CONNECTING)'\n : eventSource.readyState === 1\n ? 'Connection error while OPEN'\n : 'Connection closed';\n\n setIsConnected(false);\n eventSource.close();\n eventSourceRef.current = null;\n const error = new Error(`SSE ${stateMessage}`) as ChannlizeError;\n error.code = 'SSE_ERROR';\n setError(error);\n options.onError?.(error);\n };\n },\n [baseUrl, options.onError, options.onMessage]\n );\n\n const startSession = useCallback(async () => {\n if (isConnecting || session) return;\n\n setIsConnecting(true);\n setError(null);\n\n try {\n // Check for existing session ID (from options or localStorage)\n const existingSessionId = options.sessionId || getSessionFromStorage();\n\n if (existingSessionId) {\n // Try to resume existing session\n try {\n console.log('📦 Resuming session from storage:', existingSessionId);\n const existingSession =\n await client.getChatSession(existingSessionId);\n const existingMessages =\n await client.getChatMessages(existingSessionId);\n\n sessionRef.current = existingSession;\n setSession(existingSession);\n\n // Normalize message timestamps\n const normalizedMessages = existingMessages.map(\n (msg: ChatMessage) => ({\n ...msg,\n timestamp: msg.timestamp ? new Date(msg.timestamp) : new Date(),\n })\n );\n setMessages(normalizedMessages);\n\n // Reconnect to SSE\n const sseEndpoint = `/v1/chat/sessions/${existingSessionId}/events`;\n connectToSSE(sseEndpoint);\n\n console.log('✅ Session resumed successfully');\n return;\n } catch (err) {\n console.warn('⚠️ Failed to resume session, creating new one:', err);\n // Clear invalid session from storage\n clearSessionFromStorage();\n }\n }\n\n // Create new session\n console.log('🆕 Creating new chat session');\n const response: CreateChatSessionResponse =\n await client.createChatSession(options.metadata);\n\n sessionRef.current = response.session;\n setSession(response.session);\n\n // Save session ID to localStorage\n saveSessionToStorage(response.session.id);\n\n // Normalize message timestamps to ensure they're valid Date objects\n const normalizedMessages = (response.session.messages || []).map(\n (msg: ChatMessage) => ({\n ...msg,\n timestamp: msg.timestamp ? new Date(msg.timestamp) : new Date(),\n })\n );\n setMessages(normalizedMessages);\n\n if (response.sseEndpoint) {\n connectToSSE(response.sseEndpoint);\n }\n\n console.log('✅ New session created:', response.session.id);\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n } finally {\n setIsConnecting(false);\n }\n }, [\n client,\n connectToSSE,\n options.metadata,\n options.onError,\n options.sessionId,\n getSessionFromStorage,\n saveSessionToStorage,\n clearSessionFromStorage,\n isConnecting,\n session,\n ]);\n\n const sendMessage = useCallback(\n async (content: string, attachments?: File[]) => {\n if (!sessionRef.current) {\n throw new Error('No active chat session');\n }\n\n try {\n const response = await client.sendMessage(\n sessionRef.current.id,\n content,\n attachments\n );\n\n // Only add if not already present (SSE might have already added it)\n setMessages(prev => {\n const exists = prev.some(m => m.id === response.message.id);\n if (exists) return prev;\n\n const message = {\n ...response.message,\n timestamp: response.message.timestamp\n ? new Date(response.message.timestamp)\n : new Date(),\n };\n return [...prev, message];\n });\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n throw error;\n }\n },\n [client, options.onError]\n );\n\n const endSession = useCallback(async () => {\n if (!sessionRef.current) return;\n\n try {\n await client.closeChatSession(sessionRef.current.id);\n\n if (eventSourceRef.current) {\n eventSourceRef.current.close();\n eventSourceRef.current = null;\n }\n\n // Clear session from localStorage\n clearSessionFromStorage();\n\n sessionRef.current = null;\n setSession(null);\n setMessages([]);\n setIsConnected(false);\n\n console.log('✅ Session ended and cleared from storage');\n } catch (err) {\n const error = err as ChannlizeError;\n setError(error);\n options.onError?.(error);\n }\n }, [client, options.onError, clearSessionFromStorage]);\n\n const reconnect = useCallback(() => {\n const current = sessionRef.current;\n if (!current) return;\n // Skip if a stream is already open or reconnecting on its own.\n if (\n eventSourceRef.current &&\n eventSourceRef.current.readyState !== EventSource.CLOSED\n ) {\n return;\n }\n setError(null);\n connectToSSE(`/v1/chat/sessions/${current.id}/events`);\n }, [connectToSSE]);\n\n // Auto-connect when autoConnect becomes true\n useEffect(() => {\n if (\n options.autoConnect &&\n !session &&\n !isConnecting &&\n !isInitializedRef.current\n ) {\n isInitializedRef.current = true;\n startSession();\n }\n }, [options.autoConnect, session, isConnecting, startSession]);\n\n // Close the stream on unmount only. A cleanup on the effect above would run\n // whenever `session` or `isConnecting` changes, which happens right after\n // the stream opens, and close it for good.\n useEffect(() => {\n return () => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close();\n eventSourceRef.current = null;\n }\n };\n }, []);\n\n return {\n session,\n messages,\n isConnecting,\n isConnected,\n error,\n sendMessage,\n startSession,\n endSession,\n reconnect,\n };\n}\n","import { useCallback } from 'react';\nimport { useChannlize } from '../context/ChannlizeContext';\nimport type { TrackEventOptions } from '@channlize/core';\n\n/**\n * Returns a stable `track` function bound to the provider client for log\n * tracking (browser / widget key; shown under Log tracking in the\n * dashboard). To post a Slack message when something happens, use Events\n * (`notify` from `@channlize/core`) on your server instead.\n */\nexport function useChannlizeAnalytics() {\n const { client } = useChannlize();\n\n const track = useCallback(\n (name: string, options?: TrackEventOptions) =>\n client.trackEvent(name, options),\n [client]\n );\n\n return { track };\n}\n","import {\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FocusEvent,\n type FormEvent,\n type ReactNode,\n} from 'react';\nimport { useContactForm } from '../hooks/useContactForm';\nimport type { ContactFormData, CreateContactResponse } from '@channlize/core';\nimport { AlertIcon, CheckIcon } from './chat/icons';\nimport { readableTextColor } from './chat/utils';\nimport { FORM_CSS } from './form/styles';\n\n/** `auto` and `system` both follow `prefers-color-scheme`. */\nexport type ContactFormTheme = 'auto' | 'system' | 'light' | 'dark';\n\n/** Whether a built-in field is shown, and whether it must be filled in. */\nexport type ContactFieldMode = 'required' | 'optional' | 'hidden';\n\nexport interface ContactFormTopic {\n /** Identifies the option, e.g. for `defaultValues.topic` from a URL */\n value: string;\n /**\n * Shown in the select, sent as `customFields.topic`, and used as the\n * subject when that is blank. Defaults to `value`.\n */\n label?: string;\n}\n\n/** The built-in fields' values (also what `defaultValues` takes). */\nexport interface ContactFormValues {\n name: string;\n email: string;\n company: string;\n subject: string;\n topic: string;\n message: string;\n}\n\nexport interface ContactFormCustomField {\n name: string;\n label: string;\n type: 'text' | 'email' | 'textarea' | 'select';\n required?: boolean;\n options?: string[]; // For select fields\n placeholder?: string;\n}\n\n/** Every user-facing string in the form, for copy changes or translation. */\nexport interface ContactFormLabels {\n name: string;\n email: string;\n company: string;\n subject: string;\n topic: string;\n message: string;\n namePlaceholder: string;\n emailPlaceholder: string;\n companyPlaceholder: string;\n subjectPlaceholder: string;\n topicPlaceholder: string;\n messagePlaceholder: string;\n optional: string;\n submit: string;\n submitting: string;\n successTitle: string;\n successMessage: string;\n sendAnother: string;\n /** Shown under a required field left empty */\n errorRequired: string;\n /** Shown under a required select left on the placeholder */\n errorSelect: string;\n errorEmail: string;\n /** `{min}` is replaced with the minimum length */\n errorTooShort: string;\n /** `{max}` is replaced with the maximum length */\n errorTooLong: string;\n /** Announced when a submit is blocked by invalid fields */\n errorSummary: string;\n /** Shown when sending fails */\n errorGeneric: string;\n /** Shown when the API rate limit is hit */\n errorRateLimit: string;\n /** Small print under the submit button; '' hides it */\n footnote: string;\n}\n\nexport const defaultContactFormLabels: ContactFormLabels = {\n name: 'Name',\n email: 'Email',\n company: 'Company',\n subject: 'Subject',\n topic: 'Topic',\n message: 'Message',\n namePlaceholder: 'Jane Doe',\n emailPlaceholder: 'you@company.com',\n companyPlaceholder: 'Acme Inc.',\n subjectPlaceholder: 'What is this about?',\n topicPlaceholder: 'Choose a topic',\n messagePlaceholder: 'How can we help?',\n optional: '(optional)',\n submit: 'Send message',\n submitting: 'Sending…',\n successTitle: 'Message sent',\n successMessage: 'Thanks for reaching out. We’ll get back to you by email.',\n sendAnother: 'Send another message',\n errorRequired: 'Please fill in this field.',\n errorSelect: 'Please choose an option.',\n errorEmail: 'Enter a valid email address, like name@example.com.',\n errorTooShort: 'Please write at least {min} characters.',\n errorTooLong: 'Please keep this under {max} characters.',\n errorSummary: 'Please fix the highlighted fields.',\n errorGeneric: 'We couldn’t send your message. Please try again.',\n errorRateLimit:\n 'Too many messages in a short time. Please wait a minute and try again.',\n footnote: '',\n};\n\nexport interface FormProps {\n /** Custom fields to include in the form (sent as `customFields`) */\n customFields?: ContactFormCustomField[];\n /** Callback when form is successfully submitted */\n onSuccess?: (response: CreateContactResponse) => void;\n /** Callback when form submission fails */\n onError?: (error: Error) => void;\n /** Custom CSS classes */\n className?: string;\n /** Custom styles for form elements (applied inline, so they win over the theme) */\n styles?: {\n form?: CSSProperties;\n field?: CSSProperties;\n label?: CSSProperties;\n input?: CSSProperties;\n textarea?: CSSProperties;\n button?: CSSProperties;\n error?: CSSProperties;\n success?: CSSProperties;\n };\n /** Button text (same as `labels.submit`) */\n submitText?: string;\n /** Success message (same as `labels.successMessage`) */\n successMessage?: string;\n\n /** Colour scheme (default `light`). `auto` / `system` follow `prefers-color-scheme`. */\n theme?: ContactFormTheme;\n /** Accent colour (button, focus ring). Hex recommended. */\n primaryColor?: string;\n /** Text colour on the accent colour. Defaults to white or near-black, whichever is readable. */\n primaryTextColor?: string;\n /** `card` (default) draws a themed surface with padding; `plain` inherits the host's. */\n variant?: 'card' | 'plain';\n /** Skip the built-in stylesheet entirely (class names stay for your own CSS) */\n unstyled?: boolean;\n /**\n * Built-in fields. Email and message are always required.\n * Defaults: name `required`, subject `optional`, company `hidden`,\n * topic `optional` when `topics` is set.\n */\n fields?: {\n name?: ContactFieldMode;\n company?: ContactFieldMode;\n subject?: ContactFieldMode;\n topic?: ContactFieldMode;\n };\n /** Options of the topic select; it is shown only when this is set */\n topics?: Array<string | ContactFormTopic>;\n /**\n * Initial values, e.g. a topic from the URL (`?topic=sales`). A topic\n * matches an option's value or label, case-insensitively.\n */\n defaultValues?: Partial<ContactFormValues>;\n /** Override any user-facing string */\n labels?: Partial<ContactFormLabels>;\n /** Minimum message length (default `10`, what the Channlize API accepts) */\n minMessageLength?: number;\n /** Maximum message length (default `5000`) */\n maxMessageLength?: number;\n /** Add a hidden honeypot field; bots that fill it get a fake success (default `true`) */\n honeypot?: boolean;\n /** Show the built-in success state after sending (default `true`) */\n showSuccessState?: boolean;\n /** Prefix of the fields' ids (default `channlize`, e.g. `channlize-email`) */\n idPrefix?: string;\n}\n\ntype BuiltIn = keyof ContactFormValues;\ntype Errors = Record<string, string | undefined>;\n\nconst DEFAULT_PRIMARY = '#2563eb';\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst EMPTY_VALUES: ContactFormValues = {\n name: '',\n email: '',\n company: '',\n subject: '',\n topic: '',\n message: '',\n};\n\nfunction normalizeTopics(\n topics: FormProps['topics']\n): Required<ContactFormTopic>[] {\n return (topics ?? []).map(t =>\n typeof t === 'string'\n ? { value: t, label: t }\n : { value: t.value, label: t.label ?? t.value }\n );\n}\n\nfunction matchTopic(\n topics: Required<ContactFormTopic>[],\n wanted: string | undefined\n): string {\n const w = wanted?.trim().toLowerCase();\n if (!w) return '';\n const hit = topics.find(\n t => t.value.toLowerCase() === w || t.label.toLowerCase() === w\n );\n return hit ? hit.value : '';\n}\n\n/**\n * Form component that submits inquiries to Channlize\n */\nexport function Form({\n customFields = [],\n onSuccess,\n onError,\n className = '',\n styles = {},\n submitText,\n successMessage,\n theme = 'light',\n primaryColor,\n primaryTextColor,\n variant = 'card',\n unstyled = false,\n fields = {},\n topics,\n defaultValues,\n labels: labelOverrides,\n minMessageLength = 10,\n maxMessageLength = 5000,\n honeypot = true,\n showSuccessState = true,\n idPrefix = 'channlize',\n}: FormProps) {\n const labels: ContactFormLabels = {\n ...defaultContactFormLabels,\n ...labelOverrides,\n ...(submitText !== undefined && { submit: submitText }),\n ...(successMessage !== undefined && { successMessage }),\n };\n\n const topicOptions = useMemo(() => normalizeTopics(topics), [topics]);\n const modes: Record<\n 'name' | 'company' | 'subject' | 'topic',\n ContactFieldMode\n > = {\n name: fields.name ?? 'required',\n company: fields.company ?? 'hidden',\n subject: fields.subject ?? 'optional',\n topic: topicOptions.length === 0 ? 'hidden' : (fields.topic ?? 'optional'),\n };\n\n const initialValues = (): ContactFormValues => ({\n ...EMPTY_VALUES,\n ...defaultValues,\n topic: matchTopic(topicOptions, defaultValues?.topic),\n });\n\n const [values, setValues] = useState<ContactFormValues>(initialValues);\n const [custom, setCustom] = useState<Record<string, string>>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n const [showAllErrors, setShowAllErrors] = useState(false);\n const [trap, setTrap] = useState('');\n const [botSuccess, setBotSuccess] = useState(false);\n const [announcement, setAnnouncement] = useState('');\n const formRef = useRef<HTMLFormElement>(null);\n const successRef = useRef<HTMLHeadingElement>(null);\n\n // A topic from the URL usually arrives after the first render (search\n // params): apply it while the visitor hasn't picked one.\n const wantedTopic = defaultValues?.topic;\n useEffect(() => {\n const matched = matchTopic(topicOptions, wantedTopic);\n if (matched) setValues(v => (v.topic ? v : { ...v, topic: matched }));\n }, [wantedTopic, topicOptions]);\n\n const { submit, isSubmitting, isSuccess, error, reset } = useContactForm({\n onSuccess: response => {\n setValues(v => ({\n ...EMPTY_VALUES,\n name: v.name,\n email: v.email,\n company: v.company,\n }));\n setCustom({});\n setTouched({});\n setShowAllErrors(false);\n if (!showSuccessState) setAnnouncement(labels.successTitle);\n onSuccess?.(response);\n },\n onError,\n });\n\n const succeeded = (isSuccess || botSuccess) && showSuccessState;\n useEffect(() => {\n if (succeeded) successRef.current?.focus();\n }, [succeeded]);\n\n const id = (name: string) => `${idPrefix}-${name}`;\n\n const validate = (\n v: ContactFormValues,\n c: Record<string, string>\n ): Errors => {\n const errors: Errors = {};\n const need = (name: BuiltIn, mode: ContactFieldMode) => {\n if (mode === 'required' && !v[name].trim()) {\n errors[name] =\n name === 'topic' ? labels.errorSelect : labels.errorRequired;\n }\n };\n need('name', modes.name);\n need('company', modes.company);\n need('subject', modes.subject);\n need('topic', modes.topic);\n if (!v.email.trim()) errors.email = labels.errorRequired;\n else if (!EMAIL_PATTERN.test(v.email.trim()))\n errors.email = labels.errorEmail;\n const message = v.message.trim();\n if (!message) errors.message = labels.errorRequired;\n else if (message.length < minMessageLength) {\n errors.message = labels.errorTooShort.replace(\n '{min}',\n String(minMessageLength)\n );\n } else if (message.length > maxMessageLength) {\n errors.message = labels.errorTooLong.replace(\n '{max}',\n String(maxMessageLength)\n );\n }\n for (const field of customFields) {\n const value = (c[field.name] ?? '').trim();\n if (field.required && !value) {\n errors[`custom:${field.name}`] =\n field.type === 'select' ? labels.errorSelect : labels.errorRequired;\n } else if (\n field.type === 'email' &&\n value &&\n !EMAIL_PATTERN.test(value)\n ) {\n errors[`custom:${field.name}`] = labels.errorEmail;\n }\n }\n return errors;\n };\n\n const errors = validate(values, custom);\n const visibleError = (key: string) =>\n showAllErrors || touched[key] ? errors[key] : undefined;\n\n const handleBlur = (key: string) => (e: FocusEvent) => {\n // Don't flag an untouched field when focus just passes through it.\n const value = (e.target as HTMLInputElement).value;\n if (value || touched[key] || showAllErrors)\n setTouched(t => ({ ...t, [key]: true }));\n };\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n if (isSubmitting) return;\n\n if (Object.values(errors).some(Boolean)) {\n setShowAllErrors(true);\n setAnnouncement('');\n // Next tick, so the live region re-announces on repeated attempts.\n setTimeout(() => setAnnouncement(labels.errorSummary), 0);\n // Focus by id: the aria-invalid attributes aren't rendered yet.\n const order = [\n 'name',\n 'email',\n 'company',\n 'topic',\n 'subject',\n ...customFields.map(f => `custom:${f.name}`),\n 'message',\n ];\n const firstKey = order.find(key => errors[key]);\n if (firstKey) {\n const target = formRef.current?.querySelector<HTMLElement>(\n `[id=\"${id(firstKey.replace(/^custom:/, ''))}\"]`\n );\n target?.focus();\n }\n return;\n }\n\n if (honeypot && trap) {\n setBotSuccess(true);\n return;\n }\n\n const topic = topicOptions.find(t => t.value === values.topic);\n const customFieldValues: Record<string, string> = {};\n for (const field of customFields) {\n const v = (custom[field.name] ?? '').trim();\n if (v) customFieldValues[field.name] = v;\n }\n if (modes.topic !== 'hidden' && topic)\n customFieldValues.topic = topic.label;\n if (modes.company !== 'hidden' && values.company.trim()) {\n customFieldValues.company = values.company.trim();\n }\n\n const subject =\n (modes.subject !== 'hidden' && values.subject.trim()) ||\n topic?.label ||\n undefined;\n\n const data: ContactFormData = {\n name: modes.name === 'hidden' ? '' : values.name.trim(),\n email: values.email.trim(),\n subject,\n message: values.message.trim(),\n ...(Object.keys(customFieldValues).length > 0 && {\n customFields: customFieldValues,\n }),\n };\n await submit(data);\n };\n\n const handleReset = () => {\n reset();\n setBotSuccess(false);\n setTrap('');\n setAnnouncement('');\n };\n\n const accent = primaryColor || DEFAULT_PRIMARY;\n const rootStyle = {\n ...(primaryColor && { '--chz-primary': primaryColor }),\n '--chz-on-primary': primaryTextColor || readableTextColor(accent),\n } as CSSProperties;\n\n const rootProps = {\n className: `channlize-contact ${className}`.trim(),\n 'data-theme': theme === 'system' ? 'auto' : theme,\n 'data-variant': variant,\n style: rootStyle,\n };\n const stylesheet = unstyled ? null : (\n // Static, trusted CSS; dangerouslySetInnerHTML keeps `>` intact in SSR.\n <style\n data-channlize-form=\"\"\n dangerouslySetInnerHTML={{ __html: FORM_CSS }}\n />\n );\n\n if (succeeded) {\n return (\n <div {...rootProps}>\n {stylesheet}\n <div\n className=\"channlize-form-success\"\n style={styles.success}\n role=\"status\"\n >\n <span className=\"channlize-success-icon\" aria-hidden=\"true\">\n <CheckIcon size={26} />\n </span>\n <h2\n ref={successRef}\n tabIndex={-1}\n className=\"channlize-success-title\"\n >\n {labels.successTitle}\n </h2>\n <p className=\"channlize-success-text\">{labels.successMessage}</p>\n <button\n type=\"button\"\n className=\"channlize-secondary\"\n onClick={handleReset}\n >\n {labels.sendAnother}\n </button>\n </div>\n </div>\n );\n }\n\n const label = (name: string, text: string, required: boolean) => (\n <label htmlFor={id(name)} className=\"channlize-label\" style={styles.label}>\n {text}\n {!required && (\n <span className=\"channlize-optional\">{labels.optional}</span>\n )}\n </label>\n );\n\n const fieldError = (key: string, errorId: string): ReactNode => {\n const message = visibleError(key);\n if (!message) return null;\n return (\n <p id={errorId} className=\"channlize-field-error\">\n <AlertIcon size={14} />\n <span>{message}</span>\n </p>\n );\n };\n\n const a11y = (\n key: string,\n name: string,\n required: boolean,\n extraDescribedBy?: string\n ) => {\n const invalid = Boolean(visibleError(key));\n const describedBy = [invalid ? id(`${name}-error`) : null, extraDescribedBy]\n .filter(Boolean)\n .join(' ');\n return {\n id: id(name),\n 'aria-invalid': invalid || undefined,\n 'aria-required': required || undefined,\n 'aria-describedby': describedBy || undefined,\n };\n };\n\n const setValue = (name: BuiltIn) => (e: { target: { value: string } }) =>\n setValues(v => ({ ...v, [name]: e.target.value }));\n\n const textField = (\n name: 'name' | 'company' | 'subject' | 'email',\n mode: ContactFieldMode,\n inputProps: { type: string; autoComplete: string; inputMode?: 'email' }\n ) => {\n if (mode === 'hidden') return null;\n const required = mode === 'required';\n return (\n <div\n className=\"channlize-field\"\n data-invalid={Boolean(visibleError(name))}\n style={styles.field}\n >\n {label(name, labels[name], required)}\n <input\n {...a11y(name, name, required)}\n className=\"channlize-form-input\"\n name={name}\n type={inputProps.type}\n autoComplete={inputProps.autoComplete}\n inputMode={inputProps.inputMode}\n placeholder={labels[`${name}Placeholder`]}\n value={values[name]}\n onChange={setValue(name)}\n onBlur={handleBlur(name)}\n maxLength={name === 'subject' ? 200 : 254}\n style={styles.input}\n />\n {fieldError(name, id(`${name}-error`))}\n </div>\n );\n };\n\n const topicField =\n modes.topic === 'hidden' ? null : (\n <div\n className=\"channlize-field\"\n data-invalid={Boolean(visibleError('topic'))}\n style={styles.field}\n >\n {label('topic', labels.topic, modes.topic === 'required')}\n <select\n {...a11y('topic', 'topic', modes.topic === 'required')}\n className=\"channlize-form-select\"\n name=\"topic\"\n value={values.topic}\n data-empty={!values.topic}\n onChange={e => {\n setValue('topic')(e);\n setTouched(t => ({ ...t, topic: true }));\n }}\n onBlur={handleBlur('topic')}\n style={styles.input}\n >\n <option value=\"\">{labels.topicPlaceholder}</option>\n {topicOptions.map(t => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n {fieldError('topic', id('topic-error'))}\n </div>\n );\n\n const messageLength = values.message.trim().length;\n const showCounter = messageLength > maxMessageLength * 0.8;\n const counterId = id('message-count');\n\n const submitError = error\n ? error.statusCode === 429 || error.code === 'RATE_LIMIT_ERROR'\n ? labels.errorRateLimit\n : labels.errorGeneric\n : null;\n\n return (\n <div {...rootProps}>\n {stylesheet}\n <form\n ref={formRef}\n className=\"channlize-form\"\n style={styles.form}\n onSubmit={handleSubmit}\n noValidate\n aria-busy={isSubmitting || undefined}\n >\n <div className=\"channlize-form-row\">\n {textField('name', modes.name, {\n type: 'text',\n autoComplete: 'name',\n })}\n {textField('email', 'required', {\n type: 'email',\n autoComplete: 'email',\n inputMode: 'email',\n })}\n </div>\n\n {(modes.company !== 'hidden' || modes.topic !== 'hidden') && (\n <div className=\"channlize-form-row\">\n {textField('company', modes.company, {\n type: 'text',\n autoComplete: 'organization',\n })}\n {topicField}\n </div>\n )}\n\n {textField('subject', modes.subject, {\n type: 'text',\n autoComplete: 'off',\n })}\n\n {customFields.map(field => {\n const key = `custom:${field.name}`;\n const required = Boolean(field.required);\n const common = {\n ...a11y(key, field.name, required),\n name: field.name,\n value: custom[field.name] ?? '',\n onChange: (e: { target: { value: string } }) => {\n const value = e.target.value;\n setCustom(c => ({ ...c, [field.name]: value }));\n },\n onBlur: handleBlur(key),\n };\n return (\n <div\n key={field.name}\n className=\"channlize-field\"\n data-invalid={Boolean(visibleError(key))}\n style={styles.field}\n >\n {label(field.name, field.label, required)}\n {field.type === 'select' ? (\n <select\n {...common}\n className=\"channlize-form-select\"\n data-empty={!common.value}\n style={styles.input}\n >\n <option value=\"\">\n {field.placeholder ?? labels.topicPlaceholder}\n </option>\n {field.options?.map(option => (\n <option key={option} value={option}>\n {option}\n </option>\n ))}\n </select>\n ) : field.type === 'textarea' ? (\n <textarea\n {...common}\n className=\"channlize-form-textarea\"\n placeholder={field.placeholder}\n rows={3}\n style={styles.textarea}\n />\n ) : (\n <input\n {...common}\n className=\"channlize-form-input\"\n type={field.type}\n placeholder={field.placeholder}\n style={styles.input}\n />\n )}\n {fieldError(key, id(`${field.name}-error`))}\n </div>\n );\n })}\n\n <div\n className=\"channlize-field\"\n data-invalid={Boolean(visibleError('message'))}\n style={styles.field}\n >\n {label('message', labels.message, true)}\n <textarea\n {...a11y(\n 'message',\n 'message',\n true,\n showCounter ? counterId : undefined\n )}\n className=\"channlize-form-textarea\"\n name=\"message\"\n rows={5}\n placeholder={labels.messagePlaceholder}\n value={values.message}\n onChange={setValue('message')}\n onBlur={handleBlur('message')}\n style={styles.textarea}\n />\n {(visibleError('message') || showCounter) && (\n <div className=\"channlize-field-meta\">\n {fieldError('message', id('message-error'))}\n {showCounter && (\n <span\n id={counterId}\n className=\"channlize-counter\"\n data-over={messageLength > maxMessageLength}\n >\n {messageLength}/{maxMessageLength}\n </span>\n )}\n </div>\n )}\n </div>\n\n {honeypot && (\n // Bots fill every input; people never see this one. No `id`, so\n // host-page form helpers keyed on ids skip it too.\n <div className=\"channlize-honeypot\" aria-hidden=\"true\">\n <label>\n Leave this field empty\n <input\n type=\"text\"\n name=\"website\"\n tabIndex={-1}\n autoComplete=\"off\"\n value={trap}\n onChange={e => setTrap(e.target.value)}\n />\n </label>\n </div>\n )}\n\n {submitError && (\n <div className=\"channlize-error\" role=\"alert\" style={styles.error}>\n <AlertIcon size={18} />\n <span>{submitError}</span>\n </div>\n )}\n\n <div className=\"channlize-form-footer\">\n <button\n type=\"submit\"\n className=\"channlize-submit\"\n disabled={isSubmitting}\n style={styles.button}\n >\n {isSubmitting && (\n <span className=\"channlize-form-spinner\" aria-hidden=\"true\" />\n )}\n {isSubmitting ? labels.submitting : labels.submit}\n </button>\n {labels.footnote && (\n <p className=\"channlize-footnote\">{labels.footnote}</p>\n )}\n </div>\n\n <p\n className=\"channlize-visually-hidden\"\n role=\"status\"\n aria-live=\"polite\"\n >\n {announcement}\n </p>\n </form>\n </div>\n );\n}\n","import type { SVGProps } from 'react';\n\ntype IconProps = SVGProps<SVGSVGElement> & { size?: number };\n\nfunction Icon({ size = 20, children, ...props }: IconProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...props}\n >\n {children}\n </svg>\n );\n}\n\nexport const ChatIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M21 11.5a8.4 8.4 0 0 1-9 8.4 9.3 9.3 0 0 1-3.7-.8L3 21l1.9-4.9A8 8 0 0 1 3 11.5 8.6 8.6 0 0 1 12 3a8.6 8.6 0 0 1 9 8.5Z\" />\n </Icon>\n);\n\nexport const CloseIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </Icon>\n);\n\nexport const ChevronDownIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"m6 9 6 6 6-6\" />\n </Icon>\n);\n\nexport const MoreIcon = (p: IconProps) => (\n <Icon {...p}>\n <circle cx=\"5\" cy=\"12\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"12\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" fill=\"currentColor\" />\n </Icon>\n);\n\nexport const SendIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M12 19V5\" />\n <path d=\"m5 12 7-7 7 7\" />\n </Icon>\n);\n\nexport const PaperclipIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"m21.4 11.1-9.2 9.2a6 6 0 0 1-8.5-8.5l9.2-9.2a4 4 0 0 1 5.7 5.7l-9.2 9.2a2 2 0 0 1-2.8-2.8l8.5-8.5\" />\n </Icon>\n);\n\nexport const FileIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8Z\" />\n <path d=\"M14 3v5h5\" />\n </Icon>\n);\n\nexport const AlertIcon = (p: IconProps) => (\n <Icon {...p}>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 8v4\" />\n <path d=\"M12 16h.01\" />\n </Icon>\n);\n\nexport const ExitIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <path d=\"m16 17 5-5-5-5\" />\n <path d=\"M21 12H9\" />\n </Icon>\n);\n\nexport const CheckIcon = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Icon>\n);\n","import type { ChatMessage, FileAttachment } from '@channlize/core';\n\n/** Consecutive messages from one author closer than this are grouped. */\nconst GROUP_GAP_MS = 5 * 60 * 1000;\n\nexport type MessageStatus = 'sent' | 'sending' | 'failed';\n\n/** A message as the widget renders it: a server message or a local draft. */\nexport interface DisplayMessage {\n key: string;\n author: 'user' | 'agent';\n content: string;\n timestamp: Date;\n authorName?: string;\n avatarUrl?: string;\n attachments: DisplayAttachment[];\n status: MessageStatus;\n /** Local id of an optimistic message, used to retry or remove it. */\n localId?: string;\n /** The original server message (absent for optimistic messages). */\n message?: ChatMessage;\n}\n\nexport interface DisplayAttachment {\n key: string;\n name: string;\n size?: number;\n type?: string;\n /** Safe http(s)/blob URL, or undefined when the URL is not safe to link. */\n url?: string;\n}\n\nexport interface MessageGroup {\n key: string;\n author: 'user' | 'agent';\n authorName?: string;\n avatarUrl?: string;\n messages: DisplayMessage[];\n}\n\nexport interface DaySection {\n key: string;\n date: Date;\n groups: MessageGroup[];\n}\n\nexport function isValidDate(date: unknown): date is Date {\n return date instanceof Date && !isNaN(date.getTime());\n}\n\nfunction dayKey(date: Date): string {\n return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;\n}\n\n/** Split messages into day sections, each holding author groups. */\nexport function groupMessages(messages: DisplayMessage[]): DaySection[] {\n const sections: DaySection[] = [];\n let section: DaySection | undefined;\n let group: MessageGroup | undefined;\n let lastTime = 0;\n\n for (const msg of messages) {\n const time = isValidDate(msg.timestamp) ? msg.timestamp : new Date();\n const key = dayKey(time);\n\n if (!section || section.key !== key) {\n section = { key, date: time, groups: [] };\n sections.push(section);\n group = undefined;\n }\n\n const sameAuthor =\n group &&\n group.author === msg.author &&\n (msg.author === 'user' || group.authorName === msg.authorName);\n const closeInTime = time.getTime() - lastTime < GROUP_GAP_MS;\n\n if (!group || !sameAuthor || !closeInTime) {\n group = {\n key: msg.key,\n author: msg.author,\n authorName: msg.authorName,\n avatarUrl: msg.avatarUrl,\n messages: [],\n };\n section.groups.push(group);\n }\n\n group.messages.push(msg);\n lastTime = time.getTime();\n }\n\n return sections;\n}\n\nexport function formatTime(date: Date, locale?: string): string {\n if (!isValidDate(date)) return '';\n try {\n return new Intl.DateTimeFormat(locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(date);\n } catch {\n return '';\n }\n}\n\nexport function formatFullDate(date: Date, locale?: string): string {\n if (!isValidDate(date)) return '';\n try {\n return new Intl.DateTimeFormat(locale, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(date);\n } catch {\n return '';\n }\n}\n\nexport function formatDayLabel(\n date: Date,\n labels: { today: string; yesterday: string },\n locale?: string,\n now: Date = new Date()\n): string {\n if (!isValidDate(date)) return '';\n const startOfDay = (d: Date) =>\n new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n const days = Math.round((startOfDay(now) - startOfDay(date)) / 86400000);\n\n if (days === 0) return labels.today;\n if (days === 1) return labels.yesterday;\n\n try {\n if (days > 1 && days < 7) {\n return new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(date);\n }\n return new Intl.DateTimeFormat(locale, {\n month: 'short',\n day: 'numeric',\n ...(date.getFullYear() !== now.getFullYear() && { year: 'numeric' }),\n }).format(date);\n } catch {\n return date.toDateString();\n }\n}\n\nexport function formatFileSize(bytes?: number): string {\n if (typeof bytes !== 'number' || !isFinite(bytes) || bytes < 0) return '';\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Resolve a server URL (possibly relative to the API) and return it only if\n * it uses a safe scheme. Anything else (javascript:, data:, ...) is dropped.\n */\nexport function safeUrl(\n url: string | undefined | null,\n baseUrl?: string\n): string | undefined {\n if (!url || typeof url !== 'string') return undefined;\n try {\n const base =\n baseUrl ||\n (typeof window !== 'undefined' ? window.location.href : undefined);\n const parsed = new URL(url, base);\n if (['http:', 'https:', 'blob:'].includes(parsed.protocol)) {\n return parsed.href;\n }\n } catch {\n // fall through\n }\n return undefined;\n}\n\nexport function toDisplayAttachments(\n attachments: FileAttachment[] | undefined,\n baseUrl?: string\n): DisplayAttachment[] {\n if (!Array.isArray(attachments)) return [];\n return attachments.map((a, i) => ({\n key: a.id || `${a.name}-${i}`,\n name: a.name || 'Attachment',\n size: a.size,\n type: a.type,\n url: safeUrl(a.url, baseUrl),\n }));\n}\n\nexport function isImage(attachment: DisplayAttachment): boolean {\n if (attachment.type) return attachment.type.startsWith('image/');\n return /\\.(png|jpe?g|gif|webp|avif)$/i.test(attachment.name);\n}\n\nexport type TextPart =\n | { type: 'text'; value: string }\n | { type: 'link'; value: string; href: string };\n\nconst URL_PATTERN = /\\b(?:https?:\\/\\/|www\\.)[^\\s<>\"']+/gi;\nconst TRAILING_PUNCTUATION = /[.,;:!?'\"\\]}]+$/;\n\n/**\n * Split text into plain and link parts. The caller renders the parts as React\n * text nodes and anchors, so message content is never parsed as HTML.\n */\nexport function linkify(text: string): TextPart[] {\n const parts: TextPart[] = [];\n if (!text) return parts;\n\n let last = 0;\n for (const match of text.matchAll(URL_PATTERN)) {\n const start = match.index ?? 0;\n let raw = match[0];\n\n // Drop trailing punctuation, and a closing paren that has no opener.\n for (;;) {\n const trimmed = raw.replace(TRAILING_PUNCTUATION, '');\n const opens = (trimmed.match(/\\(/g) || []).length;\n const closes = (trimmed.match(/\\)/g) || []).length;\n const next =\n trimmed.endsWith(')') && closes > opens\n ? trimmed.slice(0, -1)\n : trimmed;\n if (next === raw) break;\n raw = next;\n }\n\n const href = safeUrl(\n raw.toLowerCase().startsWith('www.') ? `https://${raw}` : raw\n );\n if (!href || !/^https?:/.test(href)) continue;\n\n if (start > last) {\n parts.push({ type: 'text', value: text.slice(last, start) });\n }\n parts.push({ type: 'link', value: raw, href });\n last = start + raw.length;\n }\n\n if (last < text.length) {\n parts.push({ type: 'text', value: text.slice(last) });\n }\n return parts;\n}\n\nexport function initials(name: string | undefined): string {\n if (!name) return '?';\n const words = name.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) return '?';\n const first = words[0]?.[0] ?? '';\n const second = words.length > 1 ? (words[words.length - 1]?.[0] ?? '') : '';\n return (first + second).toUpperCase();\n}\n\nfunction parseHexColor(color: string): [number, number, number] | null {\n const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color.trim());\n let hex = m?.[1];\n if (!hex) return null;\n if (hex.length === 3) {\n hex = hex\n .split('')\n .map(c => c + c)\n .join('');\n }\n const n = parseInt(hex, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nfunction relativeLuminance([r, g, b]: [number, number, number]): number {\n const channel = (v: number) => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);\n };\n return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);\n}\n\n/**\n * Pick white or near-black text for a background colour. White is kept\n * whenever it meets WCAG AA (4.5:1); otherwise the higher-contrast option\n * wins. Non-hex colours fall back to white.\n */\nexport function readableTextColor(background: string): string {\n const rgb = parseHexColor(background);\n if (!rgb) return '#ffffff';\n const lum = relativeLuminance(rgb);\n const onWhite = 1.05 / (lum + 0.05);\n const onDark = (lum + 0.05) / (relativeLuminance([17, 24, 39]) + 0.05);\n return onWhite >= 4.5 || onWhite >= onDark ? '#ffffff' : '#111827';\n}\n","/**\n * Scoped stylesheet for the contact form.\n *\n * Same approach as the chat widget (`../chat/styles.ts`): every rule is\n * scoped under `.channlize-contact` (the chat's stylesheet also uses names\n * like `.channlize-input`, and both can be on one page), a small reset neutralises host-page\n * element styles, and inline `styles` props still win. Theme values are the\n * same `--chz-*` custom properties, so one `primaryColor` brands both.\n */\nexport const FORM_CSS = `\n.channlize-contact{\n --chz-primary:#2563eb;\n --chz-on-primary:#ffffff;\n --chz-bg:#ffffff;\n --chz-surface:#f6f7f9;\n --chz-field:#ffffff;\n --chz-text:#111827;\n --chz-muted:#5d6572;\n --chz-border:#d5d9e0;\n --chz-border-soft:#e3e6eb;\n --chz-danger:#b42318;\n --chz-danger-bg:#fdecec;\n --chz-success:#067647;\n --chz-success-bg:#e7f6ec;\n --chz-radius:10px;\n display:block;\n box-sizing:border-box;\n width:100%;\n max-width:100%;\n font-family:ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;\n font-size:14px;\n line-height:1.5;\n font-weight:400;\n letter-spacing:normal;\n text-transform:none;\n text-align:left;\n color:var(--chz-text);\n -webkit-font-smoothing:antialiased;\n -moz-osx-font-smoothing:grayscale;\n}\n.channlize-contact[data-theme=\"dark\"]{\n --chz-bg:#16181d;\n --chz-surface:#1f2228;\n --chz-field:#1b1e24;\n --chz-text:#f2f4f7;\n --chz-muted:#a7aebb;\n --chz-border:#3a404a;\n --chz-border-soft:#2f343d;\n --chz-danger:#ff9b9b;\n --chz-danger-bg:#3b1e22;\n --chz-success:#6ce9a6;\n --chz-success-bg:#12301f;\n}\n@media (prefers-color-scheme: dark){\n .channlize-contact[data-theme=\"auto\"]{\n --chz-bg:#16181d;\n --chz-surface:#1f2228;\n --chz-field:#1b1e24;\n --chz-text:#f2f4f7;\n --chz-muted:#a7aebb;\n --chz-border:#3a404a;\n --chz-border-soft:#2f343d;\n --chz-danger:#ff9b9b;\n --chz-danger-bg:#3b1e22;\n --chz-success:#6ce9a6;\n --chz-success-bg:#12301f;\n }\n}\n.channlize-contact[data-variant=\"card\"]{background:var(--chz-bg);border:1px solid var(--chz-border-soft);border-radius:16px;padding:24px;}\n@media (max-width: 480px){.channlize-contact[data-variant=\"card\"]{padding:18px;}}\n.channlize-contact *,.channlize-contact *::before,.channlize-contact *::after{box-sizing:border-box;letter-spacing:inherit;}\n.channlize-contact :where(h2,p,form,fieldset,label){margin:0;padding:0;border:0;font:inherit;color:inherit;background:none;}\n.channlize-contact :where(button,input,textarea,select){font:inherit;color:inherit;letter-spacing:inherit;text-transform:none;margin:0;}\n.channlize-contact :where(button){appearance:none;-webkit-appearance:none;background:none;border:0;padding:0;cursor:pointer;line-height:inherit;text-decoration:none;}\n.channlize-contact :where(button:disabled){cursor:default;}\n.channlize-contact :where(svg){display:block;flex-shrink:0;}\n.channlize-contact :where(:focus-visible){outline:2px solid var(--chz-primary);outline-offset:2px;}\n\n.channlize-contact .channlize-form{display:flex;flex-direction:column;gap:18px;}\n.channlize-contact .channlize-form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:18px;}\n.channlize-contact .channlize-field{display:flex;flex-direction:column;gap:6px;min-width:0;}\n.channlize-contact .channlize-label{display:flex;align-items:baseline;gap:6px;font-size:13.5px;font-weight:600;line-height:1.3;color:var(--chz-text);}\n.channlize-contact .channlize-optional{font-weight:400;color:var(--chz-muted);font-size:12.5px;}\n.channlize-contact .channlize-form-input,.channlize-contact .channlize-form-select,.channlize-contact .channlize-form-textarea{display:block;width:100%;min-width:0;padding:10px 12px;border-radius:var(--chz-radius);border:1px solid var(--chz-border);background:var(--chz-field);color:var(--chz-text);font-size:15px;line-height:1.4;box-shadow:none;outline:none;transition:border-color .15s ease,box-shadow .15s ease;}\n.channlize-contact .channlize-form-input,.channlize-contact .channlize-form-select{height:44px;}\n.channlize-contact .channlize-form-textarea{min-height:132px;resize:vertical;}\n.channlize-contact .channlize-form-input::placeholder,.channlize-contact .channlize-form-textarea::placeholder{color:var(--chz-muted);opacity:1;}\n.channlize-contact .channlize-form-input:hover,.channlize-contact .channlize-form-select:hover,.channlize-contact .channlize-form-textarea:hover{border-color:color-mix(in srgb, var(--chz-text) 30%, var(--chz-border));}\n.channlize-contact .channlize-form-input:focus,.channlize-contact .channlize-form-select:focus,.channlize-contact .channlize-form-textarea:focus{border-color:var(--chz-primary);box-shadow:0 0 0 3px rgba(37,99,235,.18);box-shadow:0 0 0 3px color-mix(in srgb, var(--chz-primary) 22%, transparent);outline:none;}\n.channlize-contact .channlize-form-select{appearance:none;-webkit-appearance:none;padding-right:38px;background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);background-position:calc(100% - 18px) 19px,calc(100% - 13px) 19px;background-size:5px 5px,5px 5px;background-repeat:no-repeat;cursor:pointer;}\n.channlize-contact .channlize-form-select[data-empty=\"true\"]{color:var(--chz-muted);}\n.channlize-contact .channlize-form-select option{color:var(--chz-text);background:var(--chz-field);}\n.channlize-contact .channlize-field[data-invalid=\"true\"] .channlize-form-input,.channlize-contact .channlize-field[data-invalid=\"true\"] .channlize-form-select,.channlize-contact .channlize-field[data-invalid=\"true\"] .channlize-form-textarea{border-color:var(--chz-danger);}\n.channlize-contact .channlize-field[data-invalid=\"true\"] .channlize-form-input:focus,.channlize-contact .channlize-field[data-invalid=\"true\"] .channlize-form-select:focus,.channlize-contact .channlize-field[data-invalid=\"true\"] .channlize-form-textarea:focus{box-shadow:0 0 0 3px color-mix(in srgb, var(--chz-danger) 22%, transparent);}\n.channlize-contact .channlize-field-error{display:flex;align-items:flex-start;gap:6px;font-size:13px;line-height:1.35;color:var(--chz-danger);}\n.channlize-contact .channlize-field-error svg{margin-top:1px;}\n.channlize-contact .channlize-field-meta{display:flex;justify-content:space-between;gap:12px;}\n.channlize-contact .channlize-counter{margin-left:auto;font-size:12px;color:var(--chz-muted);font-variant-numeric:tabular-nums;white-space:nowrap;}\n.channlize-contact .channlize-counter[data-over=\"true\"]{color:var(--chz-danger);}\n\n.channlize-contact .channlize-error{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border-radius:var(--chz-radius);background:var(--chz-danger-bg);color:var(--chz-danger);font-size:14px;line-height:1.4;}\n.channlize-contact .channlize-error svg{margin-top:1px;}\n\n.channlize-contact .channlize-form-footer{display:flex;flex-wrap:wrap;align-items:center;gap:12px 16px;}\n.channlize-contact .channlize-submit{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:10px 20px;border-radius:var(--chz-radius);background:var(--chz-primary);color:var(--chz-on-primary);font-size:15px;font-weight:600;line-height:1.2;transition:filter .15s ease,transform .15s ease,opacity .15s ease;}\n.channlize-contact .channlize-submit:hover:not(:disabled){filter:brightness(1.08);}\n.channlize-contact .channlize-submit:active:not(:disabled){transform:translateY(1px);}\n.channlize-contact .channlize-submit:disabled{opacity:.75;}\n.channlize-contact .channlize-submit:focus-visible{outline:2px solid var(--chz-primary);outline-offset:3px;}\n@media (max-width: 480px){.channlize-contact .channlize-submit{width:100%;}}\n.channlize-contact .channlize-footnote{font-size:12.5px;color:var(--chz-muted);}\n.channlize-contact .channlize-form-spinner{width:14px;height:14px;flex-shrink:0;border-radius:999px;border:2px solid currentColor;border-right-color:transparent;animation:channlize-spin .8s linear infinite;}\n\n.channlize-contact .channlize-honeypot{position:absolute !important;left:-10000px !important;top:auto !important;width:1px !important;height:1px !important;overflow:hidden !important;opacity:0 !important;pointer-events:none !important;}\n.channlize-contact .channlize-visually-hidden{position:absolute !important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}\n\n.channlize-contact .channlize-form-success{display:flex;flex-direction:column;align-items:center;text-align:center;gap:8px;padding:24px 8px;animation:channlize-fade-in .25s ease;}\n.channlize-contact .channlize-success-icon{display:inline-flex;align-items:center;justify-content:center;width:52px;height:52px;margin-bottom:6px;border-radius:999px;background:var(--chz-success-bg);color:var(--chz-success);}\n.channlize-contact .channlize-success-title{font-size:20px;font-weight:650;line-height:1.3;color:var(--chz-text);outline:none;}\n.channlize-contact .channlize-success-text{max-width:380px;font-size:15px;color:var(--chz-muted);}\n.channlize-contact .channlize-secondary{margin-top:12px;display:inline-flex;align-items:center;justify-content:center;min-height:40px;padding:8px 16px;border-radius:var(--chz-radius);border:1px solid var(--chz-border);background:var(--chz-surface);color:var(--chz-text);font-size:14px;font-weight:600;transition:background-color .15s ease;}\n.channlize-contact .channlize-secondary:hover{background:var(--chz-border-soft);}\n\n@media (max-width: 640px), (pointer: coarse){\n .channlize-contact .channlize-form-input,.channlize-contact .channlize-form-select,.channlize-contact .channlize-form-textarea{font-size:16px;}\n}\n@media (prefers-reduced-motion: reduce){\n .channlize-contact,.channlize-contact *{transition-duration:.01ms !important;animation-duration:.01ms !important;animation-iteration-count:1 !important;}\n}\n@keyframes channlize-spin{to{transform:rotate(360deg);}}\n@keyframes channlize-fade-in{from{opacity:0;}to{opacity:1;}}\n`;\n","import { Form, FormProps } from './Form';\n\n/**\n * ContactForm component\n *\n * A themed, accessible contact form that posts to Channlize (and from there\n * to your Slack). Inline validation, loading / success / error states, an\n * optional topic select and company field, and a honeypot spam guard.\n * Must be rendered inside `<ChannlizeProvider>`.\n */\nexport function ContactForm(props: FormProps) {\n return <Form {...props} />;\n}\n\n// Re-export FormProps as ContactFormProps for convenience\nexport type ContactFormProps = FormProps;\nexport type {\n ContactFieldMode,\n ContactFormCustomField,\n ContactFormLabels,\n ContactFormTheme,\n ContactFormTopic,\n ContactFormValues,\n} from './Form';\nexport { defaultContactFormLabels } from './Form';\n","import {\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FormEvent,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { useChatSession, UseChatSessionOptions } from '../hooks/useChatSession';\nimport { useChannlize } from '../context/ChannlizeContext';\nimport type { ChatMessage } from '@channlize/core';\nimport {\n Avatar,\n WidgetStyles,\n useDelayedFlag,\n useIsomorphicLayoutEffect,\n} from './chat/internal';\nimport {\n AlertIcon,\n ChevronDownIcon,\n CloseIcon,\n ExitIcon,\n FileIcon,\n MoreIcon,\n PaperclipIcon,\n SendIcon,\n} from './chat/icons';\nimport {\n formatDayLabel,\n formatFileSize,\n formatFullDate,\n formatTime,\n groupMessages,\n isImage,\n isValidDate,\n linkify,\n readableTextColor,\n toDisplayAttachments,\n type DisplayAttachment,\n type DisplayMessage,\n} from './chat/utils';\n\nexport type ChatTheme = 'auto' | 'light' | 'dark';\n\n/** Every user-facing string in the chat, for copy changes or translation. */\nexport interface SupportChatLabels {\n online: string;\n connecting: string;\n reconnecting: string;\n offline: string;\n connectionLost: string;\n startFailed: string;\n retry: string;\n today: string;\n yesterday: string;\n you: string;\n sending: string;\n failed: string;\n remove: string;\n moreOptions: string;\n minimize: string;\n endChat: string;\n endChatTitle: string;\n endChatDescription: string;\n endChatConfirm: string;\n cancel: string;\n attach: string;\n removeAttachment: string;\n messages: string;\n conversationEnded: string;\n charactersLeft: string;\n}\n\nexport const defaultSupportChatLabels: SupportChatLabels = {\n online: 'Online',\n connecting: 'Connecting…',\n reconnecting: 'Reconnecting…',\n offline: 'Offline',\n connectionLost: 'Connection lost. New replies may be delayed.',\n startFailed: 'We couldn’t start the chat.',\n retry: 'Retry',\n today: 'Today',\n yesterday: 'Yesterday',\n you: 'You',\n sending: 'Sending…',\n failed: 'Not sent',\n remove: 'Remove',\n moreOptions: 'More options',\n minimize: 'Minimize chat',\n endChat: 'End conversation',\n endChatTitle: 'End this conversation?',\n endChatDescription:\n 'The chat history will be cleared from this device. You can start a new conversation at any time.',\n endChatConfirm: 'End conversation',\n cancel: 'Cancel',\n attach: 'Attach files',\n removeAttachment: 'Remove attachment',\n messages: 'Messages',\n conversationEnded: 'Conversation ended. Send a message to start a new one.',\n charactersLeft: 'characters',\n};\n\nexport interface SupportChatProps extends UseChatSessionOptions {\n /** Custom CSS classes */\n className?: string;\n /** Custom styles for chat elements (applied inline, so they win over the theme) */\n styles?: {\n container?: React.CSSProperties;\n header?: React.CSSProperties;\n messagesContainer?: React.CSSProperties;\n message?: React.CSSProperties;\n userMessage?: React.CSSProperties;\n agentMessage?: React.CSSProperties;\n inputContainer?: React.CSSProperties;\n input?: React.CSSProperties;\n button?: React.CSSProperties;\n error?: React.CSSProperties;\n timestamp?: React.CSSProperties;\n };\n /** Placeholder text for message input */\n placeholder?: string;\n /** Header title: your team or brand name */\n title?: string;\n /** Accessible label (and tooltip) of the send button */\n sendButtonText?: string;\n /** Show timestamps on messages */\n showTimestamps?: boolean;\n /** Allow file attachments */\n allowAttachments?: boolean;\n\n /** Logo or team avatar URL, shown in the header and on the welcome screen */\n avatarUrl?: string;\n /** Custom avatar element (overrides `avatarUrl`) */\n avatar?: ReactNode;\n /** Text after \"Online\" in the header, e.g. \"Replies in a few minutes\". Set to '' to hide. */\n statusText?: string;\n /** Welcome heading shown before the first message */\n greeting?: string;\n /** Welcome text shown under the greeting */\n welcomeMessage?: string;\n /** Quick replies shown on the welcome screen; clicking one sends it */\n suggestions?: string[];\n /** Colour scheme. `auto` follows `prefers-color-scheme`. */\n theme?: ChatTheme;\n /** Accent colour (header, customer bubbles, send button). Hex recommended. */\n primaryColor?: string;\n /** Text colour on the accent colour. Defaults to white or near-black, whichever is readable. */\n primaryTextColor?: string;\n /** Locale for dates and times (defaults to the browser locale) */\n locale?: string;\n /** Maximum message length */\n maxLength?: number;\n /** Show \"End conversation\" in the header menu */\n allowEndChat?: boolean;\n /** When set, a minimize button is shown in the header and Esc calls it */\n onMinimize?: () => void;\n /** Override any user-facing string */\n labels?: Partial<SupportChatLabels>;\n}\n\ninterface PendingMessage {\n localId: string;\n content: string;\n files: File[];\n timestamp: Date;\n status: 'sending' | 'failed';\n}\n\nconst DEFAULT_PRIMARY = '#2563eb';\nconst MAX_FILES = 10;\n/** Routine SSE reconnects take ~1s; only surface longer outages. */\nconst STATUS_DELAY_MS = 3000;\nconst BANNER_DELAY_MS = 5000;\n\nlet localIdCounter = 0;\n\nfunction createPendingMessage(content: string, files: File[]): PendingMessage {\n localIdCounter += 1;\n return {\n localId: `local-${Date.now()}-${localIdCounter}`,\n content,\n files,\n timestamp: new Date(),\n status: 'sending',\n };\n}\n\n/**\n * SupportChat component - Real-time chat interface\n * Provides a complete chat UI with message history and real-time updates\n */\nexport function SupportChat({\n autoConnect = true,\n metadata,\n onMessage,\n onError,\n sessionId,\n persistSession,\n storageKey,\n className = '',\n styles = {},\n placeholder = 'Write a message…',\n title = 'Support',\n sendButtonText = 'Send message',\n showTimestamps = true,\n allowAttachments = false,\n avatarUrl,\n avatar,\n statusText = 'Replies in a few minutes',\n greeting = 'Hi there!',\n welcomeMessage = 'Ask us anything. We’re here to help.',\n suggestions,\n theme = 'auto',\n primaryColor,\n primaryTextColor,\n locale,\n maxLength = 5000,\n allowEndChat = true,\n onMinimize,\n labels: labelOverrides,\n}: SupportChatProps) {\n const labels = useMemo(\n () => ({ ...defaultSupportChatLabels, ...labelOverrides }),\n [labelOverrides]\n );\n const { config } = useChannlize();\n const baseUrl = config.baseUrl || 'https://api.channlize.com';\n\n const [text, setText] = useState('');\n const [files, setFiles] = useState<File[]>([]);\n const [pending, setPending] = useState<PendingMessage[]>([]);\n const [sendError, setSendError] = useState<unknown>(null);\n const [menuOpen, setMenuOpen] = useState(false);\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [ended, setEnded] = useState(false);\n\n const rootId = useId();\n const titleId = `${rootId}-title`;\n const menuId = `${rootId}-menu`;\n const confirmTitleId = `${rootId}-confirm-title`;\n const confirmTextId = `${rootId}-confirm-text`;\n\n const listRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const menuWrapRef = useRef<HTMLDivElement>(null);\n const moreButtonRef = useRef<HTMLButtonElement>(null);\n const cancelRef = useRef<HTMLButtonElement>(null);\n const stickToBottomRef = useRef(true);\n const startingRef = useRef<Promise<void> | null>(null);\n\n const {\n session,\n messages,\n isConnecting,\n isConnected,\n error,\n sendMessage,\n startSession,\n endSession,\n reconnect,\n } = useChatSession({\n autoConnect,\n metadata,\n onMessage,\n onError,\n sessionId,\n persistSession,\n storageKey,\n });\n\n // ----- Connection state (debounced so routine reconnects never flicker) --\n const sseFailed = error?.code === 'SSE_ERROR';\n const ownSendError = !!error && error === sendError;\n const startFailed = !session && !!error && !isConnecting && !ownSendError;\n const streamDown = !!session && !isConnected && !sseFailed;\n const showConnecting = useDelayedFlag(\n isConnecting || streamDown,\n STATUS_DELAY_MS\n );\n const showReconnectBanner = useDelayedFlag(\n streamDown && !isConnecting,\n BANNER_DELAY_MS\n );\n\n const status: 'online' | 'connecting' | 'offline' =\n sseFailed || startFailed\n ? 'offline'\n : showConnecting\n ? 'connecting'\n : 'online';\n const statusLabel =\n status === 'offline'\n ? labels.offline\n : status === 'connecting'\n ? session\n ? labels.reconnecting\n : labels.connecting\n : statusText\n ? `${labels.online} · ${statusText}`\n : labels.online;\n\n // ----- Messages ---------------------------------------------------------\n const displayMessages = useMemo<DisplayMessage[]>(() => {\n const fromServer = messages.map(\n (m: ChatMessage, i: number): DisplayMessage => ({\n key: m.id || `m-${i}`,\n author: m.author === 'user' ? 'user' : 'agent',\n content: typeof m.content === 'string' ? m.content : '',\n timestamp: isValidDate(m.timestamp)\n ? m.timestamp\n : new Date(m.timestamp as unknown as string),\n authorName:\n m.author === 'user' ? undefined : m.authorData?.name || title,\n avatarUrl: m.author === 'user' ? undefined : m.authorData?.avatarUrl,\n attachments: toDisplayAttachments(m.attachments, baseUrl),\n status: 'sent',\n message: m,\n })\n );\n const local = pending.map((p): DisplayMessage => ({\n key: p.localId,\n localId: p.localId,\n author: 'user',\n content: p.content,\n timestamp: p.timestamp,\n attachments: p.files.map((f, i) => ({\n key: `${p.localId}-${i}`,\n name: f.name,\n size: f.size,\n type: f.type,\n })),\n status: p.status,\n }));\n return [...fromServer, ...local];\n }, [messages, pending, title, baseUrl]);\n\n const sections = useMemo(\n () => groupMessages(displayMessages),\n [displayMessages]\n );\n const lastMessage = displayMessages[displayMessages.length - 1];\n\n // Keep the newest message in view, unless the user scrolled up to read.\n useIsomorphicLayoutEffect(() => {\n const el = listRef.current;\n if (!el) return;\n if (stickToBottomRef.current || lastMessage?.localId) {\n el.scrollTop = el.scrollHeight;\n }\n }, [lastMessage?.key, lastMessage?.status, displayMessages.length]);\n\n const handleScroll = () => {\n const el = listRef.current;\n if (!el) return;\n stickToBottomRef.current =\n el.scrollHeight - el.scrollTop - el.clientHeight < 80;\n };\n\n // Images change the list height after they load; stay pinned if we were.\n const handleMediaLoad = () => {\n const el = listRef.current;\n if (el && stickToBottomRef.current) el.scrollTop = el.scrollHeight;\n };\n\n // ----- Composer ---------------------------------------------------------\n useIsomorphicLayoutEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n el.style.height = 'auto';\n el.style.height = `${Math.min(el.scrollHeight, 140)}px`;\n }, [text]);\n\n const deliver = useCallback(\n async (item: PendingMessage) => {\n setPending(prev =>\n prev.map(p =>\n p.localId === item.localId ? { ...p, status: 'sending' } : p\n )\n );\n try {\n if (!session) {\n // Several quick sends before a session exists share one start.\n if (!startingRef.current) {\n startingRef.current = startSession().finally(() => {\n startingRef.current = null;\n });\n }\n await startingRef.current;\n }\n await sendMessage(\n item.content,\n item.files.length > 0 ? item.files : undefined\n );\n setPending(prev => prev.filter(p => p.localId !== item.localId));\n } catch (err) {\n setSendError(err);\n setPending(prev =>\n prev.map(p =>\n p.localId === item.localId ? { ...p, status: 'failed' } : p\n )\n );\n }\n },\n [session, startSession, sendMessage]\n );\n\n const send = (raw: string, attached: File[]) => {\n const content = raw.trim() || attached.map(f => f.name).join(', ');\n if (!content) return;\n const item = createPendingMessage(content, attached);\n stickToBottomRef.current = true;\n setEnded(false);\n setPending(prev => [...prev, item]);\n void deliver(item);\n };\n\n const canSend = (!!text.trim() || files.length > 0) && !isConnecting;\n\n const handleSubmit = (e?: FormEvent) => {\n e?.preventDefault();\n if (!canSend) return;\n send(text, files);\n setText('');\n setFiles([]);\n inputRef.current?.focus();\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key !== 'Enter' || e.shiftKey || e.altKey) return;\n // Don't send while an IME composition is being confirmed.\n if (e.nativeEvent.isComposing || e.keyCode === 229) return;\n // On touch-only devices Enter adds a newline; the send button sends.\n if (\n typeof window !== 'undefined' &&\n window.matchMedia?.('(hover: none) and (pointer: coarse)').matches\n ) {\n return;\n }\n e.preventDefault();\n handleSubmit();\n };\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const selected = e.target.files ? Array.from(e.target.files) : [];\n if (selected.length > 0) {\n setFiles(prev => [...prev, ...selected].slice(0, MAX_FILES));\n }\n e.target.value = '';\n };\n\n const retry = (localId: string) => {\n const item = pending.find(p => p.localId === localId);\n if (item) void deliver(item);\n };\n\n const removePending = (localId: string) => {\n setPending(prev => prev.filter(p => p.localId !== localId));\n };\n\n // ----- Menu & end-chat confirmation -------------------------------------\n useEffect(() => {\n if (!menuOpen) return;\n const onPointerDown = (e: PointerEvent) => {\n if (!menuWrapRef.current?.contains(e.target as Node)) {\n setMenuOpen(false);\n }\n };\n document.addEventListener('pointerdown', onPointerDown);\n return () => document.removeEventListener('pointerdown', onPointerDown);\n }, [menuOpen]);\n\n useEffect(() => {\n if (confirmOpen) cancelRef.current?.focus();\n }, [confirmOpen]);\n\n const closeConfirm = () => {\n setConfirmOpen(false);\n moreButtonRef.current?.focus();\n };\n\n const confirmEnd = async () => {\n setConfirmOpen(false);\n await endSession();\n setPending([]);\n setEnded(true);\n inputRef.current?.focus();\n };\n\n const handleRootKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== 'Escape') return;\n if (confirmOpen) {\n e.stopPropagation();\n closeConfirm();\n } else if (menuOpen) {\n e.stopPropagation();\n setMenuOpen(false);\n moreButtonRef.current?.focus();\n } else if (onMinimize) {\n e.stopPropagation();\n onMinimize();\n }\n };\n\n // ----- Banner -----------------------------------------------------------\n let banner: ReactNode = null;\n if (sseFailed || startFailed) {\n banner = (\n <div\n className=\"channlize-banner channlize-error\"\n data-tone=\"error\"\n role=\"alert\"\n style={styles.error}\n >\n <AlertIcon size={16} />\n <span className=\"channlize-banner-text\">\n {sseFailed ? labels.connectionLost : labels.startFailed}\n </span>\n <button\n type=\"button\"\n className=\"channlize-banner-action\"\n onClick={() => (sseFailed ? reconnect() : void startSession())}\n >\n {labels.retry}\n </button>\n </div>\n );\n } else if (error && !ownSendError) {\n banner = (\n <div\n className=\"channlize-banner channlize-error\"\n data-tone=\"error\"\n role=\"alert\"\n style={styles.error}\n >\n <AlertIcon size={16} />\n <span className=\"channlize-banner-text\">{error.message}</span>\n </div>\n );\n } else if (showReconnectBanner) {\n banner = (\n <div className=\"channlize-banner\" role=\"status\">\n <span className=\"channlize-spinner\" aria-hidden=\"true\" />\n <span className=\"channlize-banner-text\">{labels.reconnecting}</span>\n </div>\n );\n }\n\n // ----- Theme ------------------------------------------------------------\n const accent = primaryColor || DEFAULT_PRIMARY;\n const themeVars = {\n ...(primaryColor && { '--chz-primary': primaryColor }),\n '--chz-on-primary': primaryTextColor || readableTextColor(accent),\n } as CSSProperties;\n\n const headerAvatar = (\n <Avatar\n name={title}\n url={avatarUrl}\n node={avatar}\n className=\"channlize-header-avatar\"\n />\n );\n\n const counterVisible = text.length > maxLength * 0.8;\n\n return (\n <div\n className={`channlize-widget channlize-chat-container ${className}`}\n data-theme={theme}\n style={{ ...themeVars, ...styles.container }}\n onKeyDown={handleRootKeyDown}\n >\n <WidgetStyles ifMissing />\n\n <div className=\"channlize-chat-header\" style={styles.header}>\n {headerAvatar}\n <div className=\"channlize-header-text\">\n <h2 className=\"channlize-chat-title\" id={titleId}>\n {title}\n </h2>\n <p\n className=\"channlize-chat-status\"\n data-status={status}\n title={statusLabel}\n >\n <span className=\"channlize-status-dot\" aria-hidden=\"true\" />\n <span>{statusLabel}</span>\n </p>\n </div>\n <div className=\"channlize-header-actions\">\n {allowEndChat && session && (\n <div className=\"channlize-menu-wrap\" ref={menuWrapRef}>\n <button\n ref={moreButtonRef}\n type=\"button\"\n className=\"channlize-icon-btn\"\n aria-label={labels.moreOptions}\n title={labels.moreOptions}\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n aria-controls={menuOpen ? menuId : undefined}\n onClick={() => setMenuOpen(o => !o)}\n >\n <MoreIcon size={20} />\n </button>\n {menuOpen && (\n <div\n className=\"channlize-menu\"\n role=\"menu\"\n id={menuId}\n aria-label={labels.moreOptions}\n >\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"channlize-menu-item\"\n autoFocus\n onClick={() => {\n setMenuOpen(false);\n setConfirmOpen(true);\n }}\n >\n <ExitIcon size={16} />\n {labels.endChat}\n </button>\n </div>\n )}\n </div>\n )}\n {onMinimize && (\n <button\n type=\"button\"\n className=\"channlize-icon-btn\"\n aria-label={labels.minimize}\n title={labels.minimize}\n onClick={onMinimize}\n >\n <ChevronDownIcon size={22} />\n </button>\n )}\n </div>\n </div>\n\n {banner}\n\n <div\n ref={listRef}\n className=\"channlize-messages channlize-chat-messages\"\n style={styles.messagesContainer}\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n aria-label={labels.messages}\n tabIndex={0}\n onScroll={handleScroll}\n onLoadCapture={handleMediaLoad}\n >\n {displayMessages.length === 0 ? (\n <div className=\"channlize-welcome\">\n <Avatar name={title} url={avatarUrl} node={avatar} />\n <h3 className=\"channlize-welcome-title\">{greeting}</h3>\n {welcomeMessage && (\n <p className=\"channlize-welcome-text\">{welcomeMessage}</p>\n )}\n {ended && !session && (\n <p className=\"channlize-notice\" role=\"status\">\n {labels.conversationEnded}\n </p>\n )}\n {suggestions && suggestions.length > 0 && (\n <div className=\"channlize-suggestions\">\n {suggestions.map(s => (\n <button\n key={s}\n type=\"button\"\n className=\"channlize-chip\"\n disabled={isConnecting}\n onClick={() => send(s, [])}\n >\n {s}\n </button>\n ))}\n </div>\n )}\n </div>\n ) : (\n sections.map(section => (\n <div key={section.key} className=\"channlize-day-section\">\n <div className=\"channlize-day\" role=\"separator\">\n <span>{formatDayLabel(section.date, labels, locale)}</span>\n </div>\n {section.groups.map(group => {\n const last = group.messages[group.messages.length - 1];\n const isUser = group.author === 'user';\n const speaker = isUser ? labels.you : group.authorName;\n return (\n <div\n key={group.key}\n className=\"channlize-group\"\n data-author={group.author}\n >\n {!isUser && (\n <Avatar\n name={group.authorName}\n url={\n group.avatarUrl ||\n (group.authorName === title ? avatarUrl : undefined)\n }\n node={group.authorName === title ? avatar : undefined}\n className=\"channlize-group-avatar\"\n />\n )}\n <div className=\"channlize-group-body\">\n {!isUser && group.authorName && (\n <div\n className=\"channlize-group-name\"\n aria-hidden=\"true\"\n >\n {group.authorName}\n </div>\n )}\n {group.messages.map((msg, i) => {\n const n = group.messages.length;\n const pos =\n n === 1\n ? 'single'\n : i === 0\n ? 'first'\n : i === n - 1\n ? 'last'\n : 'middle';\n return (\n <MessageBubble\n key={msg.key}\n msg={msg}\n pos={pos}\n speaker={speaker}\n locale={locale}\n labels={labels}\n styles={styles}\n onRetry={retry}\n onRemove={removePending}\n />\n );\n })}\n {showTimestamps && last && last.status === 'sent' && (\n <div\n className=\"channlize-message-timestamp\"\n style={styles.timestamp}\n >\n <time\n dateTime={\n isValidDate(last.timestamp)\n ? last.timestamp.toISOString()\n : undefined\n }\n >\n {formatTime(last.timestamp, locale)}\n </time>\n </div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n ))\n )}\n </div>\n\n <form\n className=\"channlize-chat-input-container\"\n style={styles.inputContainer}\n onSubmit={handleSubmit}\n >\n {files.length > 0 && (\n <div className=\"channlize-pending-files\">\n {files.map((f, i) => (\n <span key={`${f.name}-${i}`} className=\"channlize-pending-file\">\n <span title={f.name}>{f.name}</span>\n <button\n type=\"button\"\n aria-label={`${labels.removeAttachment}: ${f.name}`}\n onClick={() =>\n setFiles(prev => prev.filter((_, j) => j !== i))\n }\n >\n <CloseIcon size={14} />\n </button>\n </span>\n ))}\n </div>\n )}\n <div\n className=\"channlize-composer\"\n data-has-attach={allowAttachments ? 'true' : undefined}\n >\n {allowAttachments && (\n <>\n <button\n type=\"button\"\n className=\"channlize-icon-btn\"\n aria-label={labels.attach}\n title={labels.attach}\n onClick={() => fileInputRef.current?.click()}\n disabled={files.length >= MAX_FILES}\n >\n <PaperclipIcon size={18} />\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"channlize-file-input\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onChange={handleFileChange}\n />\n </>\n )}\n <textarea\n ref={inputRef}\n className=\"channlize-input\"\n rows={1}\n value={text}\n maxLength={maxLength}\n onChange={e => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder}\n enterKeyHint=\"send\"\n style={styles.input}\n />\n <button\n type=\"submit\"\n className=\"channlize-send\"\n disabled={!canSend}\n aria-label={sendButtonText}\n title={sendButtonText}\n style={styles.button}\n >\n <SendIcon size={18} />\n </button>\n </div>\n {counterVisible && (\n <div\n className=\"channlize-composer-footer\"\n data-over={text.length >= maxLength ? 'true' : undefined}\n aria-live=\"polite\"\n >\n {text.length}/{maxLength}\n <span className=\"channlize-visually-hidden\">\n {' '}\n {labels.charactersLeft}\n </span>\n </div>\n )}\n </form>\n\n {confirmOpen && (\n <div\n className=\"channlize-sheet-backdrop\"\n onClick={e => {\n if (e.target === e.currentTarget) closeConfirm();\n }}\n >\n <div\n className=\"channlize-sheet\"\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby={confirmTitleId}\n aria-describedby={confirmTextId}\n >\n <h3 className=\"channlize-sheet-title\" id={confirmTitleId}>\n {labels.endChatTitle}\n </h3>\n <p className=\"channlize-sheet-text\" id={confirmTextId}>\n {labels.endChatDescription}\n </p>\n <div className=\"channlize-sheet-actions\">\n <button\n ref={cancelRef}\n type=\"button\"\n className=\"channlize-btn channlize-btn-secondary\"\n onClick={closeConfirm}\n >\n {labels.cancel}\n </button>\n <button\n type=\"button\"\n className=\"channlize-btn channlize-btn-danger\"\n onClick={() => void confirmEnd()}\n >\n {labels.endChatConfirm}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction MessageBubble({\n msg,\n pos,\n speaker,\n locale,\n labels,\n styles,\n onRetry,\n onRemove,\n}: {\n msg: DisplayMessage;\n pos: string;\n speaker?: string;\n locale?: string;\n labels: SupportChatLabels;\n styles: NonNullable<SupportChatProps['styles']>;\n onRetry: (localId: string) => void;\n onRemove: (localId: string) => void;\n}) {\n const isUser = msg.author === 'user';\n const parts = useMemo(() => linkify(msg.content), [msg.content]);\n\n return (\n <>\n <div\n className={`channlize-message ${\n isUser ? 'channlize-message-user' : 'channlize-message-agent'\n }`}\n data-pos={pos}\n data-status={msg.status}\n title={formatFullDate(msg.timestamp, locale) || undefined}\n style={{\n ...styles.message,\n ...(isUser ? styles.userMessage : styles.agentMessage),\n }}\n >\n {speaker && (\n <span className=\"channlize-visually-hidden\">{speaker}: </span>\n )}\n <div className=\"channlize-message-content\">\n {parts.map((part, i) =>\n part.type === 'link' ? (\n <a\n key={i}\n href={part.href}\n target=\"_blank\"\n rel=\"noopener noreferrer nofollow\"\n >\n {part.value}\n </a>\n ) : (\n <span key={i}>{part.value}</span>\n )\n )}\n </div>\n {msg.attachments.length > 0 && (\n <div className=\"channlize-attachments\">\n {msg.attachments.map(a => (\n <AttachmentView key={a.key} attachment={a} />\n ))}\n </div>\n )}\n </div>\n {msg.status === 'sending' && (\n <div className=\"channlize-message-meta\" data-status=\"sending\">\n {labels.sending}\n </div>\n )}\n {msg.status === 'failed' && msg.localId && (\n <div\n className=\"channlize-message-meta\"\n data-status=\"failed\"\n role=\"alert\"\n >\n <AlertIcon size={14} />\n <span>{labels.failed}</span>\n <span aria-hidden=\"true\">·</span>\n <button\n type=\"button\"\n className=\"channlize-link-btn\"\n onClick={() => onRetry(msg.localId as string)}\n >\n {labels.retry}\n </button>\n <span aria-hidden=\"true\">·</span>\n <button\n type=\"button\"\n className=\"channlize-link-btn\"\n onClick={() => onRemove(msg.localId as string)}\n >\n {labels.remove}\n </button>\n </div>\n )}\n </>\n );\n}\n\nfunction AttachmentView({ attachment }: { attachment: DisplayAttachment }) {\n const size = formatFileSize(attachment.size);\n\n if (attachment.url && isImage(attachment)) {\n return (\n <a\n className=\"channlize-attachment-image\"\n href={attachment.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <img\n src={attachment.url}\n alt={attachment.name}\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n />\n </a>\n );\n }\n\n const body = (\n <>\n <FileIcon size={18} />\n <span className=\"channlize-attachment-text\">\n <span className=\"channlize-attachment-name\">{attachment.name}</span>\n {size && <span className=\"channlize-attachment-size\">{size}</span>}\n </span>\n </>\n );\n\n return attachment.url ? (\n <a\n className=\"channlize-attachment-file\"\n href={attachment.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n download={attachment.name}\n >\n {body}\n </a>\n ) : (\n <div className=\"channlize-attachment-file\">{body}</div>\n );\n}\n","import {\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n useState,\n type ReactNode,\n} from 'react';\nimport { WIDGET_CSS } from './styles';\nimport { initials, safeUrl } from './utils';\n\n/** Set when an ancestor (ChannlizeChat) already rendered the stylesheet. */\nconst StylesContext = createContext(false);\n\nexport function WidgetStylesProvider({ children }: { children: ReactNode }) {\n return (\n <StylesContext.Provider value={true}>\n <WidgetStyles />\n {children}\n </StylesContext.Provider>\n );\n}\n\n/** Renders the widget stylesheet unless an ancestor already did. */\nexport function WidgetStyles({ ifMissing = false }: { ifMissing?: boolean }) {\n const provided = useContext(StylesContext);\n if (ifMissing && provided) return null;\n // Static, trusted CSS. dangerouslySetInnerHTML keeps `>` selectors intact\n // when the component is server-rendered.\n return (\n <style\n data-channlize-widget=\"\"\n dangerouslySetInnerHTML={{ __html: WIDGET_CSS }}\n />\n );\n}\n\nexport const useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\n/**\n * Returns true only once `value` has stayed true for `delayMs`, and false as\n * soon as it turns false. Used so brief, routine states (the SSE stream\n * reconnecting every ~50s) never flash in the UI.\n */\nexport function useDelayedFlag(value: boolean, delayMs: number): boolean {\n const [elapsed, setElapsed] = useState(false);\n\n useEffect(() => {\n if (!value) return;\n const timer = setTimeout(() => setElapsed(true), delayMs);\n return () => {\n clearTimeout(timer);\n setElapsed(false);\n };\n }, [value, delayMs]);\n\n return value && elapsed;\n}\n\nexport function Avatar({\n name,\n url,\n node,\n className = '',\n}: {\n name?: string;\n url?: string;\n node?: ReactNode;\n className?: string;\n}) {\n const [failedUrl, setFailedUrl] = useState<string | null>(null);\n const src = safeUrl(url);\n\n if (node) {\n return (\n <span className={`channlize-avatar ${className}`} aria-hidden=\"true\">\n {node}\n </span>\n );\n }\n\n return (\n <span className={`channlize-avatar ${className}`} aria-hidden=\"true\">\n {src && failedUrl !== src ? (\n <img\n src={src}\n alt=\"\"\n referrerPolicy=\"no-referrer\"\n onError={() => setFailedUrl(src)}\n />\n ) : (\n initials(name)\n )}\n </span>\n );\n}\n","/**\n * Scoped stylesheet for the chat widget.\n *\n * Every rule is prefixed with `.channlize-widget`, so nothing leaks into the\n * host page, and the reset below neutralises common global element styles\n * (button, textarea, h2, p, img ...) from the host. Inline `styles` props\n * still win over these rules, so existing customisations keep working.\n *\n * Theme values are CSS custom properties. Set `--chz-primary` and\n * `--chz-on-primary` (via the `primaryColor` prop) to brand the widget.\n */\nexport const WIDGET_CSS = `\n.channlize-widget{\n --chz-primary:#2563eb;\n --chz-on-primary:#ffffff;\n --chz-bg:#ffffff;\n --chz-surface:#f6f7f9;\n --chz-bubble:#eff1f4;\n --chz-text:#111827;\n --chz-muted:#5d6572;\n --chz-border:#e3e6eb;\n --chz-danger:#b91c1c;\n --chz-danger-bg:#fdecec;\n --chz-warn-bg:#fff6e0;\n --chz-warn-text:#7a4b00;\n --chz-online:#22c55e;\n --chz-away:#f59e0b;\n --chz-offline:#9ca3af;\n --chz-shadow:0 24px 48px -12px rgba(15,23,42,.28),0 0 0 1px rgba(15,23,42,.06);\n --chz-radius:18px;\n font-family:ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;\n font-size:14px;\n line-height:1.45;\n font-weight:400;\n font-style:normal;\n letter-spacing:normal;\n text-transform:none;\n text-align:left;\n color:var(--chz-text);\n -webkit-font-smoothing:antialiased;\n -moz-osx-font-smoothing:grayscale;\n -webkit-tap-highlight-color:transparent;\n}\n.channlize-widget[data-theme=\"dark\"]{\n --chz-bg:#16181d;\n --chz-surface:#1f2228;\n --chz-bubble:#2a2e36;\n --chz-text:#f2f4f7;\n --chz-muted:#a7aebb;\n --chz-border:#2f343d;\n --chz-danger:#ff9b9b;\n --chz-danger-bg:#3b1e22;\n --chz-warn-bg:#352a10;\n --chz-warn-text:#f6c768;\n --chz-offline:#6b7280;\n --chz-shadow:0 24px 48px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.06);\n}\n@media (prefers-color-scheme: dark){\n .channlize-widget[data-theme=\"auto\"]{\n --chz-bg:#16181d;\n --chz-surface:#1f2228;\n --chz-bubble:#2a2e36;\n --chz-text:#f2f4f7;\n --chz-muted:#a7aebb;\n --chz-border:#2f343d;\n --chz-danger:#ff9b9b;\n --chz-danger-bg:#3b1e22;\n --chz-warn-bg:#352a10;\n --chz-warn-text:#f6c768;\n --chz-offline:#6b7280;\n --chz-shadow:0 24px 48px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.06);\n }\n}\n.channlize-widget *,.channlize-widget *::before,.channlize-widget *::after{box-sizing:border-box;letter-spacing:inherit;word-spacing:inherit;text-transform:inherit;text-indent:0;}\n.channlize-widget :where(h1,h2,h3,h4,p,ul,ol,li,figure,form,fieldset){margin:0;padding:0;border:0;font:inherit;color:inherit;background:none;}\n.channlize-widget :where(button,textarea,input){font:inherit;color:inherit;letter-spacing:inherit;text-transform:none;text-shadow:none;margin:0;}\n.channlize-widget :where(button){appearance:none;-webkit-appearance:none;background:none;border:0;border-radius:0;padding:0;box-shadow:none;cursor:pointer;width:auto;height:auto;min-width:0;min-height:0;line-height:inherit;text-align:center;text-decoration:none;}\n.channlize-widget :where(button:disabled){cursor:default;}\n.channlize-widget :where(img,svg){display:block;max-width:100%;border:0;}\n.channlize-widget :where(a){color:inherit;}\n.channlize-widget :where(:focus-visible){outline:2px solid var(--chz-primary);outline-offset:2px;}\n\n/* ---------- Floating widget (ChannlizeChat) ---------- */\n.channlize-floating{position:static;}\n.channlize-floating .channlize-launcher-wrap,.channlize-floating .channlize-panel{position:fixed;z-index:var(--chz-z,2147483000);}\n.channlize-floating[data-position$=\"right\"] .channlize-launcher-wrap,.channlize-floating[data-position$=\"right\"] .channlize-panel{right:calc(var(--chz-x) + env(safe-area-inset-right,0px));}\n.channlize-floating[data-position$=\"left\"] .channlize-launcher-wrap,.channlize-floating[data-position$=\"left\"] .channlize-panel{left:calc(var(--chz-x) + env(safe-area-inset-left,0px));}\n.channlize-floating[data-position^=\"bottom\"] .channlize-launcher-wrap,.channlize-floating[data-position^=\"bottom\"] .channlize-panel{bottom:calc(var(--chz-y) + env(safe-area-inset-bottom,0px));}\n.channlize-floating[data-position^=\"top\"] .channlize-launcher-wrap,.channlize-floating[data-position^=\"top\"] .channlize-panel{top:calc(var(--chz-y) + env(safe-area-inset-top,0px));}\n\n.channlize-launcher{position:relative;display:flex;align-items:center;justify-content:center;width:var(--chz-launcher-size,56px);height:var(--chz-launcher-size,56px);border-radius:999px;background:var(--chz-launcher-bg,var(--chz-primary));color:var(--chz-launcher-fg,var(--chz-on-primary));box-shadow:0 8px 24px -6px rgba(15,23,42,.35),0 2px 6px rgba(15,23,42,.12);transition:transform .2s cubic-bezier(.2,.8,.2,1),opacity .2s ease,box-shadow .2s ease,background-color .2s ease,visibility 0s;}\n.channlize-launcher:hover{transform:translateY(-2px) scale(1.04);background:var(--chz-launcher-hover,var(--chz-launcher-bg,var(--chz-primary)));box-shadow:0 12px 28px -6px rgba(15,23,42,.4),0 2px 6px rgba(15,23,42,.12);}\n.channlize-launcher:active{transform:scale(.96);}\n.channlize-launcher:focus-visible{outline:3px solid var(--chz-launcher-bg,var(--chz-primary));outline-offset:3px;}\n.channlize-launcher-custom{display:block;cursor:pointer;}\n.channlize-launcher-wrap{transition:opacity .2s ease,transform .2s cubic-bezier(.2,.8,.2,1),visibility 0s;}\n.channlize-floating[data-open=\"true\"] .channlize-launcher-wrap{opacity:0;transform:scale(.6);visibility:hidden;pointer-events:none;transition:opacity .15s ease,transform .15s ease,visibility 0s linear .15s;}\n.channlize-badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;padding:0 6px;border-radius:999px;background:#d92d20;color:#ffffff;font-size:11px;font-weight:700;line-height:20px;text-align:center;box-shadow:0 0 0 2px var(--chz-bg);animation:channlize-pop .3s cubic-bezier(.2,.8,.2,1);}\n\n.channlize-panel{display:flex;opacity:0;visibility:hidden;transform:translateY(16px) scale(.97);transform-origin:bottom right;transition:opacity .18s ease,transform .24s cubic-bezier(.2,.8,.2,1),visibility 0s linear .24s;}\n.channlize-floating[data-position=\"bottom-left\"] .channlize-panel{transform-origin:bottom left;}\n.channlize-floating[data-position=\"top-right\"] .channlize-panel{transform-origin:top right;transform:translateY(-16px) scale(.97);}\n.channlize-floating[data-position=\"top-left\"] .channlize-panel{transform-origin:top left;transform:translateY(-16px) scale(.97);}\n.channlize-floating[data-open=\"true\"] .channlize-panel{opacity:1;visibility:visible;transform:none;transition:opacity .18s ease,transform .24s cubic-bezier(.2,.8,.2,1),visibility 0s;}\n.channlize-panel .channlize-chat-container{width:var(--chz-panel-width,380px);height:640px;max-height:calc(100vh - var(--chz-y) * 2);max-height:calc(100dvh - var(--chz-y) * 2);min-height:0;border:0;box-shadow:var(--chz-shadow);}\n\n.channlize-widget[data-animate=\"false\"] *,.channlize-widget[data-animate=\"false\"]{transition:none !important;animation:none !important;}\n@media (prefers-reduced-motion: reduce){\n .channlize-widget,.channlize-widget *{transition-duration:.01ms !important;animation-duration:.01ms !important;animation-iteration-count:1 !important;scroll-behavior:auto !important;}\n .channlize-panel{transform:none !important;}\n}\n\n@media (max-width: 640px){\n .channlize-floating[data-hide-mobile=\"true\"] .channlize-launcher-wrap{display:none;}\n .channlize-floating .channlize-panel{inset:0 !important;width:100%;height:100%;transform-origin:bottom center !important;}\n .channlize-panel .channlize-chat-container{width:100% !important;height:100% !important;max-height:none !important;border-radius:0 !important;box-shadow:none !important;}\n .channlize-panel .channlize-chat-header{padding-top:max(14px, env(safe-area-inset-top,0px));}\n .channlize-panel .channlize-chat-input-container{padding-bottom:max(12px, env(safe-area-inset-bottom,0px));}\n}\n\n/* ---------- Chat container ---------- */\n.channlize-chat-container{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:420px;overflow:hidden;background:var(--chz-bg);color:var(--chz-text);border:1px solid var(--chz-border);border-radius:16px;isolation:isolate;}\n\n/* Header */\n.channlize-chat-header{display:flex;align-items:center;gap:12px;padding:14px 12px 14px 16px;background:var(--chz-primary);color:var(--chz-on-primary);flex-shrink:0;}\n.channlize-header-text{flex:1;min-width:0;}\n.channlize-chat-title{font-size:15px;font-weight:650;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\n.channlize-chat-status{display:flex;align-items:center;gap:6px;margin-top:2px;font-size:12.5px;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\n.channlize-chat-status>span:last-child{overflow:hidden;text-overflow:ellipsis;}\n.channlize-status-dot{flex-shrink:0;width:8px;height:8px;border-radius:999px;background:var(--chz-online);box-shadow:0 0 0 2px color-mix(in srgb, var(--chz-on-primary) 35%, transparent);}\n.channlize-chat-status[data-status=\"connecting\"] .channlize-status-dot{background:var(--chz-away);animation:channlize-pulse 1.4s ease-in-out infinite;}\n.channlize-chat-status[data-status=\"offline\"] .channlize-status-dot{background:var(--chz-offline);}\n.channlize-header-actions{display:flex;align-items:center;gap:2px;flex-shrink:0;}\n.channlize-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:10px;color:inherit;transition:background-color .15s ease;}\n.channlize-icon-btn:hover{background:rgba(127,127,127,.16);background:color-mix(in srgb, currentColor 14%, transparent);}\n.channlize-chat-header .channlize-icon-btn:focus-visible{outline-color:var(--chz-on-primary);outline-offset:0;}\n\n/* Avatars */\n.channlize-avatar{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:28px;height:28px;border-radius:999px;overflow:hidden;background:var(--chz-primary);color:var(--chz-on-primary);font-size:11px;font-weight:650;line-height:1;user-select:none;}\n.channlize-avatar img{width:100%;height:100%;object-fit:cover;}\n.channlize-header-avatar{width:40px;height:40px;font-size:15px;background:rgba(255,255,255,.18);background:color-mix(in srgb, var(--chz-on-primary) 18%, transparent);color:inherit;box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--chz-on-primary) 20%, transparent);}\n\n/* Overflow menu */\n.channlize-menu-wrap{position:relative;}\n.channlize-menu{position:absolute;top:calc(100% + 6px);right:0;z-index:3;min-width:200px;padding:6px;border-radius:12px;background:var(--chz-bg);color:var(--chz-text);border:1px solid var(--chz-border);box-shadow:0 12px 32px -8px rgba(15,23,42,.3);animation:channlize-fade-in .14s ease;}\n.channlize-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:9px 10px;border-radius:8px;text-align:left;font-size:14px;color:var(--chz-text);}\n.channlize-menu-item:hover,.channlize-menu-item:focus-visible{background:var(--chz-surface);outline:none;}\n.channlize-menu-item svg{color:var(--chz-muted);}\n\n/* Banner */\n.channlize-banner{display:flex;align-items:center;gap:8px;padding:8px 14px;font-size:13px;line-height:1.35;background:var(--chz-warn-bg);color:var(--chz-warn-text);border-bottom:1px solid var(--chz-border);flex-shrink:0;animation:channlize-fade-in .2s ease;}\n.channlize-banner[data-tone=\"error\"]{background:var(--chz-danger-bg);color:var(--chz-danger);}\n.channlize-banner-text{flex:1;min-width:0;}\n.channlize-banner-action{font-weight:600;text-decoration:underline;text-underline-offset:2px;border-radius:4px;padding:2px 4px;}\n.channlize-spinner{width:12px;height:12px;flex-shrink:0;border-radius:999px;border:2px solid currentColor;border-right-color:transparent;animation:channlize-spin .8s linear infinite;}\n\n/* Messages */\n.channlize-messages{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px 14px 8px;background:var(--chz-bg);}\n.channlize-day{display:flex;align-items:center;gap:10px;margin:8px 0 12px;font-size:12px;font-weight:550;color:var(--chz-muted);}\n.channlize-day::before,.channlize-day::after{content:\"\";flex:1;height:1px;background:var(--chz-border);}\n.channlize-group{display:flex;align-items:flex-start;gap:8px;margin-bottom:14px;}\n.channlize-group[data-author=\"user\"]{justify-content:flex-end;}\n.channlize-group-body{display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-width:0;max-width:82%;}\n.channlize-group[data-author=\"user\"] .channlize-group-body{align-items:flex-end;}\n.channlize-group-avatar{margin-top:20px;}\n.channlize-group-name{font-size:12px;font-weight:600;color:var(--chz-muted);padding:0 4px 1px;}\n.channlize-message{position:relative;max-width:100%;padding:9px 13px;border-radius:var(--chz-radius);font-size:14px;line-height:1.45;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;}\n.channlize-message-agent{background:var(--chz-bubble);color:var(--chz-text);}\n.channlize-message-user{background:var(--chz-primary);color:var(--chz-on-primary);}\n.channlize-message-agent[data-pos=\"first\"]{border-bottom-left-radius:6px;}\n.channlize-message-agent[data-pos=\"middle\"]{border-top-left-radius:6px;border-bottom-left-radius:6px;}\n.channlize-message-agent[data-pos=\"last\"]{border-top-left-radius:6px;}\n.channlize-message-user[data-pos=\"first\"]{border-bottom-right-radius:6px;}\n.channlize-message-user[data-pos=\"middle\"]{border-top-right-radius:6px;border-bottom-right-radius:6px;}\n.channlize-message-user[data-pos=\"last\"]{border-top-right-radius:6px;}\n.channlize-message[data-status=\"sending\"]{opacity:.7;}\n.channlize-message[data-status=\"failed\"]{opacity:.85;box-shadow:0 0 0 2px var(--chz-danger);}\n.channlize-message-content a{color:inherit;text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px;}\n.channlize-message-content a:hover{text-decoration-thickness:2px;}\n.channlize-message-content:empty{display:none;}\n.channlize-message-timestamp{font-size:11.5px;color:var(--chz-muted);padding:1px 4px 0;}\n.channlize-message-meta{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--chz-muted);padding:1px 4px 0;}\n.channlize-message-meta[data-status=\"failed\"]{color:var(--chz-danger);}\n.channlize-link-btn{font-weight:600;text-decoration:underline;text-underline-offset:2px;border-radius:4px;padding:0 2px;color:inherit;}\n\n/* Attachments */\n.channlize-attachments{display:flex;flex-direction:column;gap:6px;margin-top:6px;white-space:normal;}\n.channlize-message-content:empty+.channlize-attachments{margin-top:0;}\n.channlize-attachment-image{display:block;border-radius:12px;overflow:hidden;max-width:240px;background:rgba(127,127,127,.12);}\n.channlize-attachment-image img{width:100%;height:auto;max-height:220px;object-fit:cover;}\n.channlize-attachment-file{display:flex;align-items:center;gap:10px;min-width:0;max-width:260px;padding:8px 10px;border-radius:12px;background:rgba(127,127,127,.14);background:color-mix(in srgb, currentColor 10%, transparent);color:inherit;text-decoration:none;}\na.channlize-attachment-file:hover{background:color-mix(in srgb, currentColor 16%, transparent);}\n.channlize-attachment-name{display:block;font-size:13px;font-weight:550;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\n.channlize-attachment-size{display:block;font-size:11.5px;opacity:.8;}\n.channlize-attachment-text{min-width:0;}\n\n/* Welcome / empty state */\n.channlize-welcome{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;padding:28px 12px 12px;animation:channlize-fade-in .3s ease;}\n.channlize-welcome .channlize-avatar{width:52px;height:52px;font-size:18px;margin-bottom:8px;}\n.channlize-welcome-title{font-size:18px;font-weight:650;line-height:1.3;color:var(--chz-text);}\n.channlize-welcome-text{font-size:14px;color:var(--chz-muted);max-width:280px;}\n.channlize-notice{margin:4px 0 0;font-size:12.5px;color:var(--chz-muted);}\n.channlize-suggestions{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:16px;}\n.channlize-chip{padding:8px 14px;border-radius:999px;font-size:13.5px;font-weight:550;line-height:1.3;color:var(--chz-text);background:var(--chz-bg);border:1px solid var(--chz-border);transition:border-color .15s ease,background-color .15s ease;text-align:left;}\n.channlize-chip:hover:not(:disabled){border-color:var(--chz-primary);background:var(--chz-surface);}\n.channlize-chip:disabled{opacity:.55;}\n\n/* Composer */\n.channlize-chat-input-container{flex-shrink:0;padding:10px 12px 12px;background:var(--chz-bg);border-top:1px solid var(--chz-border);}\n.channlize-composer{display:flex;align-items:flex-end;gap:6px;padding:6px 6px 6px 12px;border-radius:22px;background:var(--chz-surface);border:1px solid var(--chz-border);transition:border-color .15s ease,box-shadow .15s ease;}\n.channlize-composer:focus-within{border-color:var(--chz-primary);box-shadow:0 0 0 3px rgba(37,99,235,.15);box-shadow:0 0 0 3px color-mix(in srgb, var(--chz-primary) 18%, transparent);}\n.channlize-composer[data-has-attach=\"true\"]{padding-left:4px;}\n.channlize-input{flex:1;min-width:0;display:block;resize:none;border:0;outline:none;background:transparent;color:var(--chz-text);padding:7px 0;max-height:140px;font-size:15px;line-height:1.4;overflow-y:auto;box-shadow:none;border-radius:0;}\n.channlize-input:focus,.channlize-input:focus-visible{outline:none;}\n.channlize-input::placeholder{color:var(--chz-muted);opacity:1;}\n.channlize-input:disabled{opacity:.7;}\n.channlize-send{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:34px;height:34px;border-radius:999px;background:var(--chz-primary);color:var(--chz-on-primary);transition:opacity .15s ease,transform .15s ease,background-color .15s ease;}\n.channlize-send:hover:not(:disabled){transform:scale(1.05);}\n.channlize-send:disabled{background:var(--chz-border);color:var(--chz-muted);}\n.channlize-composer .channlize-icon-btn{width:34px;height:34px;border-radius:999px;color:var(--chz-muted);}\n.channlize-composer .channlize-icon-btn:hover{color:var(--chz-text);}\n.channlize-file-input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;}\n.channlize-pending-files{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;}\n.channlize-pending-file{display:inline-flex;align-items:center;gap:6px;max-width:100%;padding:4px 4px 4px 10px;border-radius:999px;background:var(--chz-surface);border:1px solid var(--chz-border);font-size:12.5px;}\n.channlize-pending-file span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:180px;}\n.channlize-pending-file button{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:999px;color:var(--chz-muted);}\n.channlize-pending-file button:hover{background:var(--chz-border);color:var(--chz-text);}\n.channlize-composer-footer{display:flex;justify-content:flex-end;padding:4px 6px 0;font-size:11.5px;color:var(--chz-muted);}\n.channlize-composer-footer[data-over=\"true\"]{color:var(--chz-danger);}\n@media (max-width: 640px), (pointer: coarse){\n .channlize-input{font-size:16px;}\n}\n\n/* End-chat confirmation sheet */\n.channlize-sheet-backdrop{position:absolute;inset:0;z-index:5;display:flex;align-items:flex-end;background:rgba(15,23,42,.35);animation:channlize-fade-in .15s ease;}\n.channlize-sheet{width:100%;padding:20px 18px max(18px, env(safe-area-inset-bottom,0px));background:var(--chz-bg);color:var(--chz-text);border-radius:18px 18px 0 0;box-shadow:0 -8px 30px rgba(15,23,42,.18);animation:channlize-slide-up .22s cubic-bezier(.2,.8,.2,1);}\n.channlize-sheet-title{font-size:16px;font-weight:650;}\n.channlize-sheet-text{margin-top:4px;font-size:14px;color:var(--chz-muted);}\n.channlize-sheet-actions{display:flex;gap:8px;margin-top:16px;}\n.channlize-btn{flex:1;padding:10px 14px;border-radius:12px;font-size:14px;font-weight:600;transition:background-color .15s ease,filter .15s ease;}\n.channlize-btn-secondary{background:var(--chz-surface);color:var(--chz-text);border:1px solid var(--chz-border);}\n.channlize-btn-secondary:hover{background:var(--chz-border);}\n.channlize-btn-danger{background:#b42318;color:#ffffff;}\n.channlize-btn-danger:hover{filter:brightness(.92);}\n.channlize-btn-primary{background:var(--chz-primary);color:var(--chz-on-primary);}\n\n.channlize-visually-hidden{position:absolute !important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}\n\n@keyframes channlize-spin{to{transform:rotate(360deg);}}\n@keyframes channlize-pulse{0%,100%{opacity:1;}50%{opacity:.4;}}\n@keyframes channlize-fade-in{from{opacity:0;}to{opacity:1;}}\n@keyframes channlize-slide-up{from{transform:translateY(24px);opacity:0;}to{transform:none;opacity:1;}}\n@keyframes channlize-pop{from{transform:scale(.4);}to{transform:scale(1);}}\n`;\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { ChannlizeProvider } from '../context/ChannlizeContext';\nimport { SupportChat } from './SupportChat';\nimport type { ChannlizeConfig, ChatMessage } from '@channlize/core';\nimport type { ChatTheme, SupportChatProps } from './SupportChat';\nimport { WidgetStylesProvider } from './chat/internal';\nimport { ChatIcon } from './chat/icons';\nimport { readableTextColor } from './chat/utils';\n\nexport interface ChannlizeChatProps {\n /** Channlize configuration */\n config: ChannlizeConfig;\n\n /** Position of the floating button */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n\n /** Offset from edges in pixels */\n offset?: { x?: number; y?: number };\n\n /** Custom button element (overrides default button) */\n buttonElement?: ReactNode;\n\n /** Custom button icon (only used if buttonElement is not provided) */\n buttonIcon?: ReactNode;\n\n /** Button size in pixels */\n buttonSize?: number;\n\n /** Launcher colours. Default to `primaryColor`. */\n buttonColors?: {\n background?: string;\n hover?: string;\n text?: string;\n };\n\n /** Chat window props (passed to SupportChat) */\n chatProps?: Omit<SupportChatProps, 'autoConnect' | 'onMinimize'>;\n\n /** Accent colour for the launcher and chat window (hex recommended) */\n primaryColor?: string;\n\n /** Colour scheme. `auto` (default) follows `prefers-color-scheme`. */\n theme?: ChatTheme;\n\n /** Whether to start closed or open */\n defaultOpen?: boolean;\n\n /**\n * Show `unreadCount` on the launcher instead of the built-in count. Without\n * it, the launcher counts agent replies received while the chat is closed.\n */\n showBadge?: boolean;\n\n /** Unread count (for badge, used with `showBadge`) */\n unreadCount?: number;\n\n /** Custom z-index */\n zIndex?: number;\n\n /** Whether to show the launcher on small screens (< 640px) */\n showOnMobile?: boolean;\n\n /** Callback when chat opens */\n onOpen?: () => void;\n\n /** Callback when chat closes */\n onClose?: () => void;\n\n /** Whether to enable animations (always reduced with `prefers-reduced-motion`) */\n enableAnimations?: boolean;\n\n /** Custom class for button container */\n buttonClassName?: string;\n\n /** Custom class for chat container */\n chatClassName?: string;\n}\n\nconst emptySubscribe = () => () => {};\n\n/**\n * ChannlizeChat - All-in-one floating chat widget with provider\n *\n * Drop this component anywhere in your React app for instant live chat support.\n * Includes the provider, floating button, and chat window.\n *\n * @example\n * ```tsx\n * <ChannlizeChat\n * config={{\n * apiKey: \"your-widget-key\",\n * projectId: \"your-project-id\",\n * }}\n * position=\"bottom-right\"\n * primaryColor=\"#2563eb\"\n * chatProps={{\n * title: \"Acme Support\",\n * greeting: \"Hi there!\",\n * welcomeMessage: \"Ask us anything.\",\n * }}\n * />\n * ```\n */\nexport function ChannlizeChat({\n config,\n position = 'bottom-right',\n offset,\n buttonElement,\n buttonIcon,\n buttonSize = 56,\n buttonColors,\n chatProps = {},\n primaryColor,\n theme,\n defaultOpen = false,\n showBadge = false,\n unreadCount = 0,\n zIndex = 2147483000,\n showOnMobile = true,\n onOpen,\n onClose,\n enableAnimations = true,\n buttonClassName = '',\n chatClassName = '',\n}: ChannlizeChatProps) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n const [autoUnread, setAutoUnread] = useState(0);\n const launcherRef = useRef<HTMLElement | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const isOpenRef = useRef(isOpen);\n const userOnMessageRef = useRef(chatProps.onMessage);\n\n // Client-only render without setState-in-effect (eslint-plugin-react-hooks v7)\n const isMounted = useSyncExternalStore(\n emptySubscribe,\n () => true,\n () => false\n );\n\n useEffect(() => {\n isOpenRef.current = isOpen;\n userOnMessageRef.current = chatProps.onMessage;\n });\n\n // Stable so the hook's EventSource handlers never hold a stale callback.\n const handleMessage = useCallback((message: ChatMessage) => {\n if (!isOpenRef.current && message.author === 'agent') {\n setAutoUnread(n => n + 1);\n }\n userOnMessageRef.current?.(message);\n }, []);\n\n const open = useCallback(() => {\n setIsOpen(true);\n setAutoUnread(0);\n onOpen?.();\n }, [onOpen]);\n\n const close = useCallback(() => {\n // Return focus to the launcher only if it was inside the panel.\n const hadFocus = !!panelRef.current?.contains(document.activeElement);\n setIsOpen(false);\n onClose?.();\n if (hadFocus) {\n requestAnimationFrame(() => launcherRef.current?.focus());\n }\n }, [onClose]);\n\n // Move focus into the panel when it opens. On touch devices focus the\n // panel itself, so the on-screen keyboard doesn't pop up uninvited.\n useEffect(() => {\n const panel = panelRef.current;\n if (!panel) return;\n panel.inert = !isOpen;\n if (!isOpen) return;\n const frame = requestAnimationFrame(() => {\n const coarse = window.matchMedia?.('(pointer: coarse)').matches;\n const input = panel.querySelector<HTMLTextAreaElement>('textarea');\n if (input && !coarse) input.focus();\n else panel.focus();\n });\n return () => cancelAnimationFrame(frame);\n }, [isOpen, isMounted]);\n\n // Don't render on server to avoid hydration issues\n if (!isMounted) {\n return null;\n }\n\n const accent = primaryColor || chatProps.primaryColor;\n const launcherBg = buttonColors?.background || accent;\n const badgeCount = showBadge ? unreadCount : autoUnread;\n const title = chatProps.title || 'Support';\n\n const rootStyle = {\n '--chz-x': `${offset?.x ?? 24}px`,\n '--chz-y': `${offset?.y ?? 24}px`,\n '--chz-z': String(zIndex),\n '--chz-launcher-size': `${buttonSize}px`,\n ...(accent && {\n '--chz-primary': accent,\n '--chz-on-primary':\n chatProps.primaryTextColor || readableTextColor(accent),\n }),\n ...(launcherBg && { '--chz-launcher-bg': launcherBg }),\n ...(buttonColors?.hover && { '--chz-launcher-hover': buttonColors.hover }),\n ...((buttonColors?.text || launcherBg) && {\n '--chz-launcher-fg':\n buttonColors?.text || readableTextColor(launcherBg as string),\n }),\n } as CSSProperties;\n\n const launcherLabel =\n badgeCount > 0\n ? `Open chat, ${badgeCount} unread ${badgeCount === 1 ? 'message' : 'messages'}`\n : 'Open chat';\n\n const badge =\n badgeCount > 0 ? (\n <span className=\"channlize-badge\" aria-hidden=\"true\">\n {badgeCount > 99 ? '99+' : badgeCount}\n </span>\n ) : null;\n\n const onCustomLauncherKey = (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n open();\n }\n };\n\n const widget = (\n <ChannlizeProvider config={config}>\n <WidgetStylesProvider>\n <div\n className=\"channlize-widget channlize-floating\"\n data-theme={theme || chatProps.theme || 'auto'}\n data-position={position}\n data-open={isOpen ? 'true' : 'false'}\n data-animate={enableAnimations ? 'true' : 'false'}\n data-hide-mobile={showOnMobile ? undefined : 'true'}\n style={rootStyle}\n >\n <div className={`channlize-launcher-wrap ${buttonClassName}`}>\n {buttonElement ? (\n <div\n ref={el => {\n launcherRef.current = el;\n }}\n className=\"channlize-launcher-custom\"\n role=\"button\"\n tabIndex={isOpen ? -1 : 0}\n aria-label={launcherLabel}\n aria-expanded={isOpen}\n onClick={open}\n onKeyDown={onCustomLauncherKey}\n >\n {buttonElement}\n </div>\n ) : (\n <button\n ref={el => {\n launcherRef.current = el;\n }}\n type=\"button\"\n className=\"channlize-launcher\"\n onClick={open}\n aria-label={launcherLabel}\n aria-expanded={isOpen}\n tabIndex={isOpen ? -1 : 0}\n >\n {buttonIcon || (\n <ChatIcon size={Math.round(buttonSize * 0.46)} />\n )}\n {badge}\n </button>\n )}\n </div>\n\n <div\n ref={panelRef}\n className={`channlize-panel ${chatClassName}`}\n role=\"dialog\"\n aria-modal=\"false\"\n aria-label={title}\n aria-hidden={!isOpen}\n tabIndex={-1}\n >\n <SupportChat\n persistSession={true}\n title={title}\n showTimestamps={true}\n {...chatProps}\n theme={theme || chatProps.theme}\n primaryColor={accent}\n autoConnect={isOpen}\n onMessage={handleMessage}\n onMinimize={close}\n />\n </div>\n </div>\n </WidgetStylesProvider>\n </ChannlizeProvider>\n );\n\n // Render at the end of <body> so host transforms, overflow and stacking\n // contexts can't clip the fixed-position widget.\n return typeof document !== 'undefined'\n ? createPortal(widget, document.body)\n : widget;\n}\n"],"mappings":"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","names":["import_react","error","import_react","error","normalizedMessages","import_react","import_react","import_jsx_runtime","import_jsx_runtime","errors","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","DEFAULT_PRIMARY","import_react","import_jsx_runtime"]}
|