@enjoys/react-chatbot-plugin 1.0.0 → 1.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/context/ChatContext.ts","../src/styles/theme.ts","../src/components/Launcher.tsx","../src/components/ChatHeader.tsx","../src/components/WelcomeScreen.tsx","../src/components/forms/TextField.tsx","../src/components/forms/SelectField.tsx","../src/components/forms/RadioField.tsx","../src/components/forms/CheckboxField.tsx","../src/components/forms/FileUploadField.tsx","../src/components/forms/DynamicForm.tsx","../src/components/LoginScreen.tsx","../src/components/MessageBubble.tsx","../src/components/QuickReplies.tsx","../src/components/TypingIndicator.tsx","../src/components/MessageList.tsx","../src/components/ChatInput.tsx","../src/engine/FlowEngine.ts","../src/utils/helpers.ts","../src/hooks/useChat.ts","../src/components/ChatWindow.tsx","../src/components/ChatBot.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\r\nimport type { ChatMessage, ChatBotProps } from '../types';\r\n\r\nexport interface ChatState {\r\n isOpen: boolean;\r\n messages: ChatMessage[];\r\n isTyping: boolean;\r\n showWelcome: boolean;\r\n currentStepId: string | null;\r\n collectedData: Record<string, unknown>;\r\n isLoggedIn: boolean;\r\n}\r\n\r\nexport type ChatAction =\r\n | { type: 'TOGGLE_OPEN' }\r\n | { type: 'SET_OPEN'; payload: boolean }\r\n | { type: 'ADD_MESSAGE'; payload: ChatMessage }\r\n | { type: 'ADD_MESSAGES'; payload: ChatMessage[] }\r\n | { type: 'SET_TYPING'; payload: boolean }\r\n | { type: 'DISMISS_WELCOME' }\r\n | { type: 'SET_STEP'; payload: string | null }\r\n | { type: 'SET_DATA'; payload: Record<string, unknown> }\r\n | { type: 'SET_LOGGED_IN'; payload: boolean }\r\n | { type: 'CLEAR_QUICK_REPLIES' };\r\n\r\nexport function chatReducer(state: ChatState, action: ChatAction): ChatState {\r\n switch (action.type) {\r\n case 'TOGGLE_OPEN':\r\n return { ...state, isOpen: !state.isOpen };\r\n case 'SET_OPEN':\r\n return { ...state, isOpen: action.payload };\r\n case 'ADD_MESSAGE':\r\n return { ...state, messages: [...state.messages, action.payload] };\r\n case 'ADD_MESSAGES':\r\n return { ...state, messages: [...state.messages, ...action.payload] };\r\n case 'SET_TYPING':\r\n return { ...state, isTyping: action.payload };\r\n case 'DISMISS_WELCOME':\r\n return { ...state, showWelcome: false };\r\n case 'SET_STEP':\r\n return { ...state, currentStepId: action.payload };\r\n case 'SET_DATA':\r\n return { ...state, collectedData: { ...state.collectedData, ...action.payload } };\r\n case 'SET_LOGGED_IN':\r\n return { ...state, isLoggedIn: action.payload };\r\n case 'CLEAR_QUICK_REPLIES':\r\n return {\r\n ...state,\r\n messages: state.messages.map((m) =>\r\n m.quickReplies ? { ...m, quickReplies: undefined } : m,\r\n ),\r\n };\r\n default:\r\n return state;\r\n }\r\n}\r\n\r\nexport const initialState = (props: ChatBotProps): ChatState => ({\r\n isOpen: props.defaultOpen ?? false,\r\n messages: props.initialMessages ?? [],\r\n isTyping: false,\r\n showWelcome: !!props.welcomeScreen,\r\n currentStepId: null,\r\n collectedData: {},\r\n isLoggedIn: !props.loginForm,\r\n});\r\n\r\ninterface ChatContextValue {\r\n state: ChatState;\r\n dispatch: React.Dispatch<ChatAction>;\r\n props: ChatBotProps;\r\n}\r\n\r\nexport const ChatContext = createContext<ChatContextValue | null>(null);\r\n\r\nexport function useChatContext(): ChatContextValue {\r\n const ctx = useContext(ChatContext);\r\n if (!ctx) throw new Error('useChatContext must be used within ChatProvider');\r\n return ctx;\r\n}\r\n","import type { ChatTheme, ChatStyle } from '../types';\r\nimport type { CSSProperties } from 'react';\r\n\r\nconst defaults: Required<ChatTheme> = {\r\n primaryColor: '#0066FF',\r\n headerBg: '#0066FF',\r\n headerText: '#FFFFFF',\r\n bubbleBg: '#F1F1F1',\r\n bubbleText: '#333333',\r\n userBubbleBg: '#0066FF',\r\n userBubbleText: '#FFFFFF',\r\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\r\n fontSize: '14px',\r\n borderRadius: '12px',\r\n windowWidth: '380px',\r\n windowHeight: '550px',\r\n};\r\n\r\nexport function resolveTheme(theme?: ChatTheme): Required<ChatTheme> {\r\n return { ...defaults, ...theme };\r\n}\r\n\r\nexport function buildStyles(\r\n theme: Required<ChatTheme>,\r\n overrides?: ChatStyle,\r\n) {\r\n const styles = {\r\n root: {\r\n fontFamily: theme.fontFamily,\r\n fontSize: theme.fontSize,\r\n lineHeight: '1.5',\r\n } satisfies CSSProperties,\r\n\r\n launcher: {\r\n position: 'fixed',\r\n width: '60px',\r\n height: '60px',\r\n borderRadius: '50%',\r\n backgroundColor: theme.primaryColor,\r\n color: '#fff',\r\n border: 'none',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n boxShadow: '0 4px 12px rgba(0,0,0,0.15)',\r\n transition: 'transform 0.2s ease',\r\n zIndex: 9998,\r\n ...overrides?.launcher,\r\n } satisfies CSSProperties,\r\n\r\n window: {\r\n position: 'fixed',\r\n width: theme.windowWidth,\r\n height: theme.windowHeight,\r\n maxHeight: '80vh',\r\n borderRadius: theme.borderRadius,\r\n overflow: 'hidden',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n boxShadow: '0 8px 32px rgba(0,0,0,0.15)',\r\n backgroundColor: '#FFFFFF',\r\n zIndex: 9999,\r\n ...overrides?.window,\r\n } satisfies CSSProperties,\r\n\r\n header: {\r\n backgroundColor: theme.headerBg,\r\n color: theme.headerText,\r\n padding: '16px 20px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'space-between',\r\n gap: '12px',\r\n flexShrink: 0,\r\n ...overrides?.header,\r\n } satisfies CSSProperties,\r\n\r\n messageList: {\r\n flex: 1,\r\n overflowY: 'auto',\r\n padding: '16px',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: '8px',\r\n ...overrides?.messageList,\r\n } satisfies CSSProperties,\r\n\r\n inputArea: {\r\n padding: '12px 16px',\r\n borderTop: '1px solid #E8E8E8',\r\n display: 'flex',\r\n gap: '8px',\r\n alignItems: 'flex-end',\r\n flexShrink: 0,\r\n ...overrides?.inputArea,\r\n } satisfies CSSProperties,\r\n\r\n botBubble: {\r\n backgroundColor: theme.bubbleBg,\r\n color: theme.bubbleText,\r\n padding: '10px 14px',\r\n borderRadius: '16px 16px 16px 4px',\r\n maxWidth: '80%',\r\n alignSelf: 'flex-start',\r\n wordBreak: 'break-word',\r\n whiteSpace: 'pre-wrap',\r\n } satisfies CSSProperties,\r\n\r\n userBubble: {\r\n backgroundColor: theme.userBubbleBg,\r\n color: theme.userBubbleText,\r\n padding: '10px 14px',\r\n borderRadius: '16px 16px 4px 16px',\r\n maxWidth: '80%',\r\n alignSelf: 'flex-end',\r\n wordBreak: 'break-word',\r\n whiteSpace: 'pre-wrap',\r\n } satisfies CSSProperties,\r\n };\r\n\r\n return styles;\r\n}\r\n\r\nexport type ChatStyles = ReturnType<typeof buildStyles>;\r\n","import React from 'react';\r\nimport type { CSSProperties } from 'react';\r\nimport type { ChatStyles } from '../styles/theme';\r\n\r\ninterface LauncherProps {\r\n onClick: () => void;\r\n isOpen: boolean;\r\n position: 'bottom-right' | 'bottom-left';\r\n styles: ChatStyles;\r\n icon?: React.ReactNode;\r\n closeIcon?: React.ReactNode;\r\n zIndex?: number;\r\n}\r\n\r\nexport const Launcher: React.FC<LauncherProps> = ({\r\n onClick,\r\n isOpen,\r\n position,\r\n styles,\r\n icon,\r\n closeIcon,\r\n zIndex,\r\n}) => {\r\n const posStyle: CSSProperties =\r\n position === 'bottom-left'\r\n ? { bottom: '20px', left: '20px' }\r\n : { bottom: '20px', right: '20px' };\r\n\r\n return (\r\n <button\r\n onClick={onClick}\r\n aria-label={isOpen ? 'Close chat' : 'Open chat'}\r\n style={{\r\n ...styles.launcher,\r\n ...posStyle,\r\n ...(zIndex != null ? { zIndex } : {}),\r\n transform: isOpen ? 'scale(0.9)' : 'scale(1)',\r\n }}\r\n >\r\n {isOpen\r\n ? closeIcon ?? <CloseIcon />\r\n : icon ?? <ChatIcon />}\r\n </button>\r\n );\r\n};\r\n\r\nconst ChatIcon: React.FC = () => (\r\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\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\" />\r\n </svg>\r\n);\r\n\r\nconst CloseIcon: React.FC = () => (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </svg>\r\n);\r\n","import React from 'react';\r\nimport type { HeaderConfig } from '../types';\r\nimport type { ChatStyles as ThemeStyles } from '../styles/theme';\r\n\r\ninterface ChatHeaderProps {\r\n config: HeaderConfig;\r\n styles: ThemeStyles;\r\n onClose: () => void;\r\n}\r\n\r\nexport const ChatHeader: React.FC<ChatHeaderProps> = ({ config, styles, onClose }) => {\r\n return (\r\n <div style={styles.header}>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '10px', flex: 1 }}>\r\n {config.avatar && (\r\n <img\r\n src={config.avatar}\r\n alt=\"\"\r\n style={{ width: '36px', height: '36px', borderRadius: '50%', objectFit: 'cover' }}\r\n />\r\n )}\r\n <div>\r\n <div style={{ fontWeight: 600, fontSize: '15px' }}>\r\n {config.title ?? 'Chat with us'}\r\n </div>\r\n {config.subtitle && (\r\n <div style={{ fontSize: '12px', opacity: 0.85 }}>{config.subtitle}</div>\r\n )}\r\n </div>\r\n </div>\r\n {config.showClose !== false && (\r\n <button\r\n onClick={onClose}\r\n aria-label=\"Close chat\"\r\n style={{\r\n background: 'none',\r\n border: 'none',\r\n color: 'inherit',\r\n cursor: 'pointer',\r\n padding: '4px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n }}\r\n >\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </svg>\r\n </button>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { ReactNode } from 'react';\r\n\r\ninterface WelcomeScreenProps {\r\n content: ReactNode;\r\n onDismiss: () => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const WelcomeScreen: React.FC<WelcomeScreenProps> = ({ content, onDismiss, primaryColor }) => {\r\n return (\r\n <div\r\n style={{\r\n flex: 1,\r\n display: 'flex',\r\n flexDirection: 'column',\r\n overflow: 'auto',\r\n }}\r\n >\r\n <div style={{ flex: 1, padding: '20px', overflow: 'auto' }}>\r\n {content}\r\n </div>\r\n <div style={{ padding: '12px 16px', borderTop: '1px solid #E8E8E8', flexShrink: 0 }}>\r\n <button\r\n onClick={onDismiss}\r\n style={{\r\n width: '100%',\r\n padding: '12px',\r\n backgroundColor: primaryColor,\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '8px',\r\n fontSize: '14px',\r\n fontWeight: 600,\r\n cursor: 'pointer',\r\n }}\r\n >\r\n Start Chat\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface TextFieldProps {\r\n field: FormFieldConfig;\r\n value: string;\r\n onChange: (value: string) => void;\r\n error?: string;\r\n}\r\n\r\nexport const TextField: React.FC<TextFieldProps> = ({ field, value, onChange, error }) => {\r\n const isTextarea = field.type === 'textarea';\r\n const inputType = field.type === 'textarea' ? undefined : field.type;\r\n\r\n const baseStyle: React.CSSProperties = {\r\n width: '100%',\r\n padding: '8px 12px',\r\n border: `1px solid ${error ? '#E53E3E' : '#D1D5DB'}`,\r\n borderRadius: '8px',\r\n fontSize: '13px',\r\n fontFamily: 'inherit',\r\n outline: 'none',\r\n boxSizing: 'border-box',\r\n transition: 'border-color 0.15s ease',\r\n };\r\n\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n {isTextarea ? (\r\n <textarea\r\n value={value}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder={field.placeholder}\r\n required={field.required}\r\n rows={3}\r\n style={{ ...baseStyle, resize: 'vertical' }}\r\n minLength={field.validation?.minLength}\r\n maxLength={field.validation?.maxLength}\r\n />\r\n ) : (\r\n <input\r\n type={inputType}\r\n value={value}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder={field.placeholder}\r\n required={field.required}\r\n style={baseStyle}\r\n min={field.validation?.min}\r\n max={field.validation?.max}\r\n minLength={field.validation?.minLength}\r\n maxLength={field.validation?.maxLength}\r\n pattern={field.validation?.pattern}\r\n />\r\n )}\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface SelectFieldProps {\r\n field: FormFieldConfig;\r\n value: string | string[];\r\n onChange: (value: string | string[]) => void;\r\n error?: string;\r\n}\r\n\r\nexport const SelectField: React.FC<SelectFieldProps> = ({ field, value, onChange, error }) => {\r\n const isMulti = field.type === 'multiselect' || field.multiple;\r\n\r\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\r\n if (isMulti) {\r\n const selected = Array.from(e.target.selectedOptions, (opt) => opt.value);\r\n onChange(selected);\r\n } else {\r\n onChange(e.target.value);\r\n }\r\n };\r\n\r\n const selectValue = isMulti\r\n ? Array.isArray(value) ? value : [value].filter(Boolean)\r\n : typeof value === 'string' ? value : '';\r\n\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n <select\r\n value={selectValue}\r\n onChange={handleChange}\r\n multiple={isMulti}\r\n required={field.required}\r\n style={{\r\n width: '100%',\r\n padding: '8px 12px',\r\n border: `1px solid ${error ? '#E53E3E' : '#D1D5DB'}`,\r\n borderRadius: '8px',\r\n fontSize: '13px',\r\n fontFamily: 'inherit',\r\n outline: 'none',\r\n backgroundColor: '#fff',\r\n boxSizing: 'border-box',\r\n ...(isMulti ? { minHeight: '80px' } : {}),\r\n }}\r\n >\r\n {!isMulti && <option value=\"\">Select...</option>}\r\n {field.options?.map((opt) => (\r\n <option key={opt.value} value={opt.value}>\r\n {opt.label}\r\n </option>\r\n ))}\r\n </select>\r\n {isMulti && (\r\n <div style={{ fontSize: '11px', color: '#888', marginTop: '2px' }}>\r\n Hold Ctrl/Cmd to select multiple\r\n </div>\r\n )}\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface RadioFieldProps {\r\n field: FormFieldConfig;\r\n value: string;\r\n onChange: (value: string) => void;\r\n error?: string;\r\n}\r\n\r\nexport const RadioField: React.FC<RadioFieldProps> = ({ field, value, onChange, error }) => {\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '6px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\r\n {field.options?.map((opt) => (\r\n <label\r\n key={opt.value}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n }}\r\n >\r\n <input\r\n type=\"radio\"\r\n name={field.name}\r\n value={opt.value}\r\n checked={value === opt.value}\r\n onChange={() => onChange(opt.value)}\r\n style={{ margin: 0 }}\r\n />\r\n {opt.label}\r\n </label>\r\n ))}\r\n </div>\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface CheckboxFieldProps {\r\n field: FormFieldConfig;\r\n value: string[];\r\n onChange: (value: string[]) => void;\r\n error?: string;\r\n}\r\n\r\nexport const CheckboxField: React.FC<CheckboxFieldProps> = ({ field, value, onChange, error }) => {\r\n const handleToggle = (optValue: string) => {\r\n if (value.includes(optValue)) {\r\n onChange(value.filter((v) => v !== optValue));\r\n } else {\r\n onChange([...value, optValue]);\r\n }\r\n };\r\n\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '6px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\r\n {field.options?.map((opt) => (\r\n <label\r\n key={opt.value}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n }}\r\n >\r\n <input\r\n type=\"checkbox\"\r\n checked={value.includes(opt.value)}\r\n onChange={() => handleToggle(opt.value)}\r\n style={{ margin: 0 }}\r\n />\r\n {opt.label}\r\n </label>\r\n ))}\r\n </div>\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React, { useRef } from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface FileUploadFieldProps {\r\n field: FormFieldConfig;\r\n value: FileList | null;\r\n onChange: (files: FileList | null) => void;\r\n error?: string;\r\n primaryColor: string;\r\n}\r\n\r\nexport const FileUploadField: React.FC<FileUploadFieldProps> = ({\r\n field,\r\n value,\r\n onChange,\r\n error,\r\n primaryColor,\r\n}) => {\r\n const inputRef = useRef<HTMLInputElement>(null);\r\n\r\n const fileNames = value ? Array.from(value).map((f) => f.name).join(', ') : '';\r\n\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n <input\r\n ref={inputRef}\r\n type=\"file\"\r\n accept={field.accept}\r\n multiple={field.multiple}\r\n onChange={(e) => onChange(e.target.files)}\r\n style={{ display: 'none' }}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => inputRef.current?.click()}\r\n style={{\r\n padding: '8px 16px',\r\n border: `1px dashed ${error ? '#E53E3E' : '#D1D5DB'}`,\r\n borderRadius: '8px',\r\n backgroundColor: '#FAFAFA',\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n color: '#555',\r\n width: '100%',\r\n textAlign: 'left',\r\n }}\r\n >\r\n {fileNames || field.placeholder || 'Choose file(s)...'}\r\n </button>\r\n {fileNames && (\r\n <div style={{ fontSize: '12px', color: primaryColor, marginTop: '4px' }}>\r\n {Array.from(value!).length} file(s) selected\r\n </div>\r\n )}\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useCallback } from 'react';\r\nimport type { FormConfig, FormFieldConfig } from '../../types';\r\nimport { TextField } from './TextField';\r\nimport { SelectField } from './SelectField';\r\nimport { RadioField } from './RadioField';\r\nimport { CheckboxField } from './CheckboxField';\r\nimport { FileUploadField } from './FileUploadField';\r\n\r\ninterface DynamicFormProps {\r\n config: FormConfig;\r\n onSubmit: (data: Record<string, unknown>) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const DynamicForm: React.FC<DynamicFormProps> = ({ config, onSubmit, primaryColor }) => {\r\n const [values, setValues] = useState<Record<string, unknown>>(() => {\r\n const init: Record<string, unknown> = {};\r\n for (const field of config.fields) {\r\n if (field.defaultValue !== undefined) {\r\n init[field.name] = field.defaultValue;\r\n } else if (field.type === 'checkbox' || field.type === 'multiselect') {\r\n init[field.name] = [];\r\n } else if (field.type === 'file') {\r\n init[field.name] = null;\r\n } else {\r\n init[field.name] = '';\r\n }\r\n }\r\n return init;\r\n });\r\n\r\n const [errors, setErrors] = useState<Record<string, string>>({});\r\n const [submitted, setSubmitted] = useState(false);\r\n\r\n const setValue = useCallback((name: string, value: unknown) => {\r\n setValues((prev) => ({ ...prev, [name]: value }));\r\n setErrors((prev) => {\r\n const next = { ...prev };\r\n delete next[name];\r\n return next;\r\n });\r\n }, []);\r\n\r\n const validate = (): boolean => {\r\n const newErrors: Record<string, string> = {};\r\n\r\n for (const field of config.fields) {\r\n const val = values[field.name];\r\n\r\n // Required check\r\n if (field.required) {\r\n if (\r\n val === '' ||\r\n val === null ||\r\n val === undefined ||\r\n (Array.isArray(val) && val.length === 0)\r\n ) {\r\n newErrors[field.name] = field.validation?.message ?? `${field.label || field.name} is required`;\r\n continue;\r\n }\r\n }\r\n\r\n // Pattern check\r\n if (field.validation?.pattern && typeof val === 'string' && val) {\r\n const regex = new RegExp(field.validation.pattern);\r\n if (!regex.test(val)) {\r\n newErrors[field.name] = field.validation.message ?? 'Invalid format';\r\n }\r\n }\r\n }\r\n\r\n setErrors(newErrors);\r\n return Object.keys(newErrors).length === 0;\r\n };\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!validate()) return;\r\n setSubmitted(true);\r\n onSubmit(values);\r\n };\r\n\r\n if (submitted) {\r\n return (\r\n <div\r\n style={{\r\n padding: '12px',\r\n backgroundColor: '#F0FFF4',\r\n borderRadius: '8px',\r\n fontSize: '13px',\r\n color: '#276749',\r\n textAlign: 'center',\r\n }}\r\n >\r\n Submitted successfully\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <form\r\n onSubmit={handleSubmit}\r\n style={{\r\n backgroundColor: '#FAFAFA',\r\n borderRadius: '10px',\r\n padding: '16px',\r\n border: '1px solid #E8E8E8',\r\n }}\r\n >\r\n {config.title && (\r\n <div style={{ fontWeight: 600, fontSize: '14px', marginBottom: '4px' }}>\r\n {config.title}\r\n </div>\r\n )}\r\n {config.description && (\r\n <div style={{ fontSize: '12px', color: '#888', marginBottom: '12px' }}>\r\n {config.description}\r\n </div>\r\n )}\r\n\r\n {config.fields.map((field) => (\r\n <FormField\r\n key={field.name}\r\n field={field}\r\n value={values[field.name]}\r\n onChange={(v) => setValue(field.name, v)}\r\n error={errors[field.name]}\r\n primaryColor={primaryColor}\r\n />\r\n ))}\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: '100%',\r\n padding: '10px',\r\n backgroundColor: primaryColor,\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '8px',\r\n fontSize: '14px',\r\n fontWeight: 600,\r\n cursor: 'pointer',\r\n marginTop: '4px',\r\n }}\r\n >\r\n {config.submitLabel ?? 'Submit'}\r\n </button>\r\n </form>\r\n );\r\n};\r\n\r\n// ─── Field Router ────────────────────────────────────────────────\r\n\r\ninterface FormFieldProps {\r\n field: FormFieldConfig;\r\n value: unknown;\r\n onChange: (value: unknown) => void;\r\n error?: string;\r\n primaryColor: string;\r\n}\r\n\r\nconst FormField: React.FC<FormFieldProps> = ({ field, value, onChange, error, primaryColor }) => {\r\n switch (field.type) {\r\n case 'text':\r\n case 'email':\r\n case 'password':\r\n case 'number':\r\n case 'tel':\r\n case 'url':\r\n case 'textarea':\r\n case 'date':\r\n case 'time':\r\n return (\r\n <TextField\r\n field={field}\r\n value={String(value ?? '')}\r\n onChange={onChange as (v: string) => void}\r\n error={error}\r\n />\r\n );\r\n case 'select':\r\n case 'multiselect':\r\n return (\r\n <SelectField\r\n field={field}\r\n value={value as string | string[]}\r\n onChange={onChange as (v: string | string[]) => void}\r\n error={error}\r\n />\r\n );\r\n case 'radio':\r\n return (\r\n <RadioField\r\n field={field}\r\n value={String(value ?? '')}\r\n onChange={onChange as (v: string) => void}\r\n error={error}\r\n />\r\n );\r\n case 'checkbox':\r\n return (\r\n <CheckboxField\r\n field={field}\r\n value={(value as string[]) ?? []}\r\n onChange={onChange as (v: string[]) => void}\r\n error={error}\r\n />\r\n );\r\n case 'file':\r\n return (\r\n <FileUploadField\r\n field={field}\r\n value={value as FileList | null}\r\n onChange={onChange as (v: FileList | null) => void}\r\n error={error}\r\n primaryColor={primaryColor}\r\n />\r\n );\r\n case 'hidden':\r\n return <input type=\"hidden\" name={field.name} value={String(value ?? '')} />;\r\n default:\r\n return null;\r\n }\r\n};\r\n","import React from 'react';\r\nimport type { FormConfig } from '../types';\r\nimport { DynamicForm } from './forms/DynamicForm';\r\n\r\ninterface LoginScreenProps {\r\n config: FormConfig;\r\n onLogin: (data: Record<string, unknown>) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const LoginScreen: React.FC<LoginScreenProps> = ({ config, onLogin, primaryColor }) => {\r\n return (\r\n <div\r\n style={{\r\n flex: 1,\r\n display: 'flex',\r\n flexDirection: 'column',\r\n justifyContent: 'center',\r\n padding: '20px',\r\n overflow: 'auto',\r\n }}\r\n >\r\n <DynamicForm config={config} onSubmit={onLogin} primaryColor={primaryColor} />\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { ChatMessage } from '../types';\r\nimport type { ChatStyles } from '../styles/theme';\r\n\r\ninterface MessageBubbleProps {\r\n message: ChatMessage;\r\n styles: ChatStyles;\r\n}\r\n\r\nexport const MessageBubble: React.FC<MessageBubbleProps> = ({ message, styles }) => {\r\n const isBot = message.sender === 'bot';\r\n const bubbleStyle = isBot ? styles.botBubble : styles.userBubble;\r\n\r\n if (!message.text && !message.attachment) return null;\r\n\r\n return (\r\n <div style={bubbleStyle}>\r\n {message.text && <span>{message.text}</span>}\r\n {message.attachment && (\r\n <div style={{ marginTop: message.text ? '6px' : 0 }}>\r\n <a\r\n href={message.attachment.url}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n style={{ color: 'inherit', textDecoration: 'underline', fontSize: '13px' }}\r\n >\r\n 📎 {message.attachment.name}\r\n </a>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FlowQuickReply } from '../types';\r\n\r\ninterface QuickRepliesProps {\r\n replies: FlowQuickReply[];\r\n onSelect: (value: string, label: string) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const QuickReplies: React.FC<QuickRepliesProps> = ({ replies, onSelect, primaryColor }) => {\r\n return (\r\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', alignSelf: 'flex-start', maxWidth: '90%' }}>\r\n {replies.map((reply) => (\r\n <button\r\n key={reply.value}\r\n onClick={() => onSelect(reply.value, reply.label)}\r\n style={{\r\n padding: '6px 14px',\r\n borderRadius: '18px',\r\n border: `1px solid ${primaryColor}`,\r\n backgroundColor: 'transparent',\r\n color: primaryColor,\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n fontWeight: 500,\r\n transition: 'all 0.15s ease',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = primaryColor;\r\n e.currentTarget.style.color = '#fff';\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = 'transparent';\r\n e.currentTarget.style.color = primaryColor;\r\n }}\r\n >\r\n {reply.label}\r\n </button>\r\n ))}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\n\r\ninterface TypingIndicatorProps {\r\n color: string;\r\n}\r\n\r\nexport const TypingIndicator: React.FC<TypingIndicatorProps> = ({ color }) => {\r\n const dotStyle: React.CSSProperties = {\r\n width: '8px',\r\n height: '8px',\r\n borderRadius: '50%',\r\n backgroundColor: color,\r\n opacity: 0.4,\r\n animation: 'chatbot-typing-bounce 1.4s infinite ease-in-out',\r\n };\r\n\r\n return (\r\n <>\r\n <style>{`\r\n @keyframes chatbot-typing-bounce {\r\n 0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; }\r\n 40% { transform: scale(1); opacity: 1; }\r\n }\r\n `}</style>\r\n <div\r\n style={{\r\n display: 'flex',\r\n gap: '4px',\r\n padding: '12px 16px',\r\n backgroundColor: '#F1F1F1',\r\n borderRadius: '16px 16px 16px 4px',\r\n alignSelf: 'flex-start',\r\n alignItems: 'center',\r\n }}\r\n >\r\n <span style={{ ...dotStyle, animationDelay: '0s' }} />\r\n <span style={{ ...dotStyle, animationDelay: '0.2s' }} />\r\n <span style={{ ...dotStyle, animationDelay: '0.4s' }} />\r\n </div>\r\n </>\r\n );\r\n};\r\n","import React, { useRef, useEffect } from 'react';\r\nimport type { ChatMessage } from '../types';\r\nimport type { ChatStyles } from '../styles/theme';\r\nimport { MessageBubble } from './MessageBubble';\r\nimport { QuickReplies } from './QuickReplies';\r\nimport { TypingIndicator } from './TypingIndicator';\r\nimport { DynamicForm } from './forms/DynamicForm';\r\n\r\ninterface MessageListProps {\r\n messages: ChatMessage[];\r\n isTyping: boolean;\r\n styles: ChatStyles;\r\n primaryColor: string;\r\n onQuickReply: (value: string, label: string) => void;\r\n onFormSubmit: (formId: string, data: Record<string, unknown>) => void;\r\n}\r\n\r\nexport const MessageList: React.FC<MessageListProps> = ({\r\n messages,\r\n isTyping,\r\n styles,\r\n primaryColor,\r\n onQuickReply,\r\n onFormSubmit,\r\n}) => {\r\n const bottomRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' });\r\n }, [messages, isTyping]);\r\n\r\n return (\r\n <div style={styles.messageList}>\r\n {messages.map((msg) => (\r\n <React.Fragment key={msg.id}>\r\n <MessageBubble message={msg} styles={styles} />\r\n {msg.quickReplies && msg.quickReplies.length > 0 && (\r\n <QuickReplies\r\n replies={msg.quickReplies}\r\n onSelect={onQuickReply}\r\n primaryColor={primaryColor}\r\n />\r\n )}\r\n {msg.form && (\r\n <div style={{ alignSelf: 'flex-start', width: '90%' }}>\r\n <DynamicForm\r\n config={msg.form}\r\n onSubmit={(data) => onFormSubmit(msg.form!.id, data)}\r\n primaryColor={primaryColor}\r\n />\r\n </div>\r\n )}\r\n </React.Fragment>\r\n ))}\r\n {isTyping && <TypingIndicator color={primaryColor} />}\r\n <div ref={bottomRef} />\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useRef } from 'react';\r\nimport type { CSSProperties } from 'react';\r\n\r\ninterface ChatInputProps {\r\n onSend: (text: string) => void;\r\n placeholder?: string;\r\n primaryColor: string;\r\n disabled?: boolean;\r\n styleOverride?: CSSProperties;\r\n}\r\n\r\nexport const ChatInput: React.FC<ChatInputProps> = ({\r\n onSend,\r\n placeholder = 'Type a message...',\r\n primaryColor,\r\n disabled,\r\n styleOverride,\r\n}) => {\r\n const [text, setText] = useState('');\r\n const inputRef = useRef<HTMLTextAreaElement>(null);\r\n\r\n const handleSend = () => {\r\n const trimmed = text.trim();\r\n if (!trimmed) return;\r\n onSend(trimmed);\r\n setText('');\r\n inputRef.current?.focus();\r\n };\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent) => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n handleSend();\r\n }\r\n };\r\n\r\n return (\r\n <div style={{ display: 'flex', gap: '8px', alignItems: 'flex-end', ...styleOverride }}>\r\n <textarea\r\n ref={inputRef}\r\n value={text}\r\n onChange={(e) => setText(e.target.value)}\r\n onKeyDown={handleKeyDown}\r\n placeholder={placeholder}\r\n disabled={disabled}\r\n rows={1}\r\n style={{\r\n flex: 1,\r\n padding: '10px 14px',\r\n border: '1px solid #E0E0E0',\r\n borderRadius: '20px',\r\n outline: 'none',\r\n resize: 'none',\r\n fontFamily: 'inherit',\r\n fontSize: '14px',\r\n lineHeight: '1.4',\r\n maxHeight: '100px',\r\n overflowY: 'auto',\r\n }}\r\n />\r\n <button\r\n onClick={handleSend}\r\n disabled={disabled || !text.trim()}\r\n aria-label=\"Send message\"\r\n style={{\r\n width: '38px',\r\n height: '38px',\r\n borderRadius: '50%',\r\n backgroundColor: text.trim() ? primaryColor : '#CCC',\r\n color: '#fff',\r\n border: 'none',\r\n cursor: text.trim() ? 'pointer' : 'default',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n flexShrink: 0,\r\n transition: 'background-color 0.15s ease',\r\n }}\r\n >\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n );\r\n};\r\n","import type { FlowConfig, FlowStep, ChatMessage, FlowQuickReply } from '../types';\r\n\r\nlet idCounter = 0;\r\nconst uid = (): string => `msg_${Date.now()}_${++idCounter}`;\r\n\r\nexport class FlowEngine {\r\n private steps: Map<string, FlowStep>;\r\n private startStep: string;\r\n private collectedData: Record<string, unknown> = {};\r\n\r\n constructor(flow: FlowConfig) {\r\n this.startStep = flow.startStep;\r\n this.steps = new Map(flow.steps.map((s) => [s.id, s]));\r\n }\r\n\r\n getStartStepId(): string {\r\n return this.startStep;\r\n }\r\n\r\n getStep(id: string): FlowStep | undefined {\r\n return this.steps.get(id);\r\n }\r\n\r\n getData(): Record<string, unknown> {\r\n return { ...this.collectedData };\r\n }\r\n\r\n setData(key: string, value: unknown): void {\r\n this.collectedData[key] = value;\r\n }\r\n\r\n mergeData(data: Record<string, unknown>): void {\r\n Object.assign(this.collectedData, data);\r\n }\r\n\r\n resolveNext(step: FlowStep, userValue?: string): string | undefined {\r\n // Conditional branching\r\n if (step.condition) {\r\n const { field, operator, value, then: thenStep, else: elseStep } = step.condition;\r\n const fieldVal = this.collectedData[field];\r\n const match = this.evaluate(fieldVal, operator, value);\r\n return match ? thenStep : elseStep;\r\n }\r\n\r\n // Quick-reply selected → find the reply's next\r\n if (userValue && step.quickReplies) {\r\n const reply = step.quickReplies.find((r) => r.value === userValue);\r\n if (reply?.next) return reply.next;\r\n }\r\n\r\n return step.next;\r\n }\r\n\r\n buildMessages(step: FlowStep): ChatMessage[] {\r\n const messages: ChatMessage[] = [];\r\n\r\n const texts = step.messages ?? (step.message ? [step.message] : []);\r\n for (const text of texts) {\r\n messages.push({\r\n id: uid(),\r\n sender: 'bot',\r\n text,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n\r\n // Attach quick replies to the last message\r\n if (step.quickReplies && messages.length > 0) {\r\n messages[messages.length - 1]!.quickReplies = step.quickReplies;\r\n }\r\n\r\n // If step has a form, create a form message\r\n if (step.form) {\r\n messages.push({\r\n id: uid(),\r\n sender: 'bot',\r\n timestamp: Date.now(),\r\n form: step.form,\r\n });\r\n }\r\n\r\n return messages;\r\n }\r\n\r\n private evaluate(\r\n fieldVal: unknown,\r\n operator: string,\r\n value: string | number,\r\n ): boolean {\r\n switch (operator) {\r\n case 'eq':\r\n return String(fieldVal) === String(value);\r\n case 'neq':\r\n return String(fieldVal) !== String(value);\r\n case 'contains':\r\n return String(fieldVal).includes(String(value));\r\n case 'gt':\r\n return Number(fieldVal) > Number(value);\r\n case 'lt':\r\n return Number(fieldVal) < Number(value);\r\n default:\r\n return false;\r\n }\r\n }\r\n}\r\n\r\nexport function createQuickReplyMessage(\r\n replies: FlowQuickReply[],\r\n): ChatMessage {\r\n return {\r\n id: uid(),\r\n sender: 'bot',\r\n timestamp: Date.now(),\r\n quickReplies: replies,\r\n };\r\n}\r\n","let counter = 0;\r\n\r\nexport const uid = (): string => `msg_${Date.now()}_${++counter}`;\r\n\r\nexport const classNames = (...args: (string | false | null | undefined)[]): string =>\r\n args.filter(Boolean).join(' ');\r\n\r\nexport const delay = (ms: number): Promise<void> =>\r\n new Promise((resolve) => setTimeout(resolve, ms));\r\n","import { useCallback, useRef, useEffect } from 'react';\r\nimport { useChatContext } from '../context/ChatContext';\r\nimport { FlowEngine } from '../engine/FlowEngine';\r\nimport { uid, delay } from '../utils/helpers';\r\nimport type { ChatMessage, FormConfig } from '../types';\r\n\r\nexport function useChat() {\r\n const { state, dispatch, props } = useChatContext();\r\n const flowRef = useRef<FlowEngine | null>(null);\r\n const flowStartedRef = useRef(false);\r\n\r\n // Initialize flow engine\r\n useEffect(() => {\r\n if (props.flow) {\r\n flowRef.current = new FlowEngine(props.flow);\r\n flowStartedRef.current = false;\r\n }\r\n }, [props.flow]);\r\n\r\n const addBotMessage = useCallback(\r\n async (text: string, extras?: Partial<ChatMessage>) => {\r\n dispatch({ type: 'SET_TYPING', payload: true });\r\n await delay(400);\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'bot',\r\n text,\r\n timestamp: Date.now(),\r\n ...extras,\r\n };\r\n dispatch({ type: 'SET_TYPING', payload: false });\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n props.callbacks?.onMessageReceive?.(msg);\r\n },\r\n [dispatch, props.callbacks],\r\n );\r\n\r\n const sendMessage = useCallback(\r\n (text: string) => {\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'user',\r\n text,\r\n timestamp: Date.now(),\r\n };\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n props.callbacks?.onMessageSend?.(msg);\r\n props.callbacks?.onSubmit?.({ message: text });\r\n\r\n // Process flow\r\n if (flowRef.current && state.currentStepId) {\r\n const step = flowRef.current.getStep(state.currentStepId);\r\n if (step) {\r\n flowRef.current.setData(step.id, text);\r\n const nextId = flowRef.current.resolveNext(step, text);\r\n if (nextId) {\r\n processFlowStep(nextId);\r\n } else {\r\n props.callbacks?.onFlowEnd?.(flowRef.current.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n }\r\n }\r\n },\r\n [dispatch, props.callbacks, state.currentStepId],\r\n );\r\n\r\n const processFlowStep = useCallback(\r\n async (stepId: string) => {\r\n const engine = flowRef.current;\r\n if (!engine) return;\r\n\r\n const step = engine.getStep(stepId);\r\n if (!step) return;\r\n\r\n dispatch({ type: 'SET_STEP', payload: stepId });\r\n dispatch({ type: 'SET_TYPING', payload: true });\r\n await delay(step.delay ?? 500);\r\n\r\n const messages = engine.buildMessages(step);\r\n dispatch({ type: 'SET_TYPING', payload: false });\r\n dispatch({ type: 'ADD_MESSAGES', payload: messages });\r\n\r\n messages.forEach((m) => props.callbacks?.onMessageReceive?.(m));\r\n\r\n // Auto-advance if no user input required\r\n if (!step.quickReplies && !step.form && step.next) {\r\n await delay(300);\r\n processFlowStep(step.next);\r\n }\r\n },\r\n [dispatch, props.callbacks],\r\n );\r\n\r\n const startFlow = useCallback(() => {\r\n const engine = flowRef.current;\r\n if (!engine || flowStartedRef.current) return;\r\n flowStartedRef.current = true;\r\n processFlowStep(engine.getStartStepId());\r\n }, [processFlowStep]);\r\n\r\n // Auto-start flow when all conditions are met\r\n useEffect(() => {\r\n if (\r\n props.flow &&\r\n !state.showWelcome &&\r\n state.isLoggedIn &&\r\n !flowStartedRef.current\r\n ) {\r\n startFlow();\r\n }\r\n }, [props.flow, state.showWelcome, state.isLoggedIn, startFlow]);\r\n\r\n const handleQuickReply = useCallback(\r\n (value: string, label: string) => {\r\n dispatch({ type: 'CLEAR_QUICK_REPLIES' });\r\n // Add user message\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'user',\r\n text: label,\r\n timestamp: Date.now(),\r\n };\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n props.callbacks?.onQuickReply?.(value, label);\r\n\r\n // Continue flow\r\n if (flowRef.current && state.currentStepId) {\r\n const step = flowRef.current.getStep(state.currentStepId);\r\n if (step) {\r\n flowRef.current.setData(step.id, value);\r\n const nextId = flowRef.current.resolveNext(step, value);\r\n if (nextId) {\r\n processFlowStep(nextId);\r\n } else {\r\n props.callbacks?.onFlowEnd?.(flowRef.current.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n }\r\n }\r\n },\r\n [dispatch, props.callbacks, state.currentStepId, processFlowStep],\r\n );\r\n\r\n const handleFormSubmit = useCallback(\r\n async (formId: string, data: Record<string, unknown>) => {\r\n dispatch({ type: 'SET_DATA', payload: data });\r\n if (flowRef.current) {\r\n flowRef.current.mergeData(data);\r\n }\r\n\r\n // Summary message\r\n const summaryLines = Object.entries(data)\r\n .filter(([, v]) => v !== undefined && v !== '')\r\n .map(([k, v]) => `${k}: ${String(v)}`)\r\n .join('\\n');\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'user',\r\n text: summaryLines,\r\n formData: data,\r\n timestamp: Date.now(),\r\n };\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n\r\n await props.callbacks?.onFormSubmit?.(formId, data);\r\n\r\n // Advance flow\r\n if (flowRef.current && state.currentStepId) {\r\n const step = flowRef.current.getStep(state.currentStepId);\r\n if (step) {\r\n const nextId = flowRef.current.resolveNext(step);\r\n if (nextId) {\r\n processFlowStep(nextId);\r\n } else {\r\n props.callbacks?.onFlowEnd?.(flowRef.current.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n }\r\n }\r\n },\r\n [dispatch, props.callbacks, state.currentStepId, processFlowStep],\r\n );\r\n\r\n const handleLogin = useCallback(\r\n async (data: Record<string, unknown>) => {\r\n await props.callbacks?.onLogin?.(data);\r\n dispatch({ type: 'SET_LOGGED_IN', payload: true });\r\n },\r\n [dispatch, props.callbacks],\r\n );\r\n\r\n const toggleChat = useCallback(() => {\r\n const willOpen = !state.isOpen;\r\n dispatch({ type: 'TOGGLE_OPEN' });\r\n if (willOpen) {\r\n props.callbacks?.onOpen?.();\r\n } else {\r\n props.callbacks?.onClose?.();\r\n }\r\n }, [dispatch, state.isOpen, props.callbacks]);\r\n\r\n const dismissWelcome = useCallback(() => {\r\n dispatch({ type: 'DISMISS_WELCOME' });\r\n }, [dispatch]);\r\n\r\n return {\r\n state,\r\n sendMessage,\r\n addBotMessage,\r\n handleQuickReply,\r\n handleFormSubmit,\r\n handleLogin,\r\n toggleChat,\r\n dismissWelcome,\r\n startFlow,\r\n processFlowStep,\r\n };\r\n}\r\n","import React from 'react';\r\nimport type { CSSProperties } from 'react';\r\nimport type { ChatStyles } from '../styles/theme';\r\nimport { ChatHeader } from './ChatHeader';\r\nimport { WelcomeScreen } from './WelcomeScreen';\r\nimport { LoginScreen } from './LoginScreen';\r\nimport { MessageList } from './MessageList';\r\nimport { ChatInput } from './ChatInput';\r\nimport { useChat } from '../hooks/useChat';\r\nimport { useChatContext } from '../context/ChatContext';\r\nimport { resolveTheme } from '../styles/theme';\r\n\r\ninterface ChatWindowProps {\r\n styles: ChatStyles;\r\n position: 'bottom-right' | 'bottom-left';\r\n zIndex?: number;\r\n}\r\n\r\nexport const ChatWindow: React.FC<ChatWindowProps> = ({ styles, position, zIndex }) => {\r\n const { props } = useChatContext();\r\n const theme = resolveTheme(props.theme);\r\n const {\r\n state,\r\n sendMessage,\r\n handleQuickReply,\r\n handleFormSubmit,\r\n handleLogin,\r\n toggleChat,\r\n dismissWelcome,\r\n } = useChat();\r\n\r\n const posStyle: CSSProperties =\r\n position === 'bottom-left'\r\n ? { bottom: '90px', left: '20px' }\r\n : { bottom: '90px', right: '20px' };\r\n\r\n return (\r\n <div\r\n style={{\r\n ...styles.window,\r\n ...posStyle,\r\n ...(zIndex != null ? { zIndex } : {}),\r\n }}\r\n >\r\n <ChatHeader\r\n config={props.header ?? { title: 'Chat with us' }}\r\n styles={styles}\r\n onClose={toggleChat}\r\n />\r\n\r\n {/* Welcome Screen */}\r\n {state.showWelcome && props.welcomeScreen ? (\r\n <WelcomeScreen\r\n content={props.welcomeScreen}\r\n onDismiss={dismissWelcome}\r\n primaryColor={theme.primaryColor}\r\n />\r\n ) : /* Login Screen */\r\n !state.isLoggedIn && props.loginForm ? (\r\n <LoginScreen\r\n config={props.loginForm}\r\n onLogin={handleLogin}\r\n primaryColor={theme.primaryColor}\r\n />\r\n ) : (\r\n /* Chat Area */\r\n <>\r\n <MessageList\r\n messages={state.messages}\r\n isTyping={state.isTyping}\r\n styles={styles}\r\n primaryColor={theme.primaryColor}\r\n onQuickReply={handleQuickReply}\r\n onFormSubmit={handleFormSubmit}\r\n />\r\n <div style={styles.inputArea}>\r\n <ChatInput\r\n onSend={sendMessage}\r\n placeholder={props.inputPlaceholder}\r\n primaryColor={theme.primaryColor}\r\n />\r\n </div>\r\n </>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import React, { useReducer } from 'react';\r\nimport type { ChatBotProps } from '../types';\r\nimport { ChatContext, chatReducer, initialState } from '../context/ChatContext';\r\nimport { resolveTheme, buildStyles } from '../styles/theme';\r\nimport { Launcher } from './Launcher';\r\nimport { ChatWindow } from './ChatWindow';\r\n\r\nexport const ChatBot: React.FC<ChatBotProps> = (props) => {\r\n const [state, dispatch] = useReducer(chatReducer, props, initialState);\r\n const theme = resolveTheme(props.theme);\r\n const styles = buildStyles(theme, props.style);\r\n const position = props.position ?? 'bottom-right';\r\n const showLauncher = props.showLauncher !== false;\r\n\r\n\r\n\r\n return (\r\n <ChatContext.Provider value={{ state, dispatch, props }}>\r\n <div style={styles.root} className={props.className}>\r\n {state.isOpen && (\r\n <ChatWindow styles={styles} position={position} zIndex={props.zIndex} />\r\n )}\r\n {showLauncher && (\r\n <Launcher\r\n onClick={() => {\r\n const willOpen = !state.isOpen;\r\n dispatch({ type: 'TOGGLE_OPEN' });\r\n if (willOpen) props.callbacks?.onOpen?.();\r\n else props.callbacks?.onClose?.();\r\n }}\r\n isOpen={state.isOpen}\r\n position={position}\r\n styles={styles}\r\n icon={props.launcherIcon}\r\n closeIcon={props.closeIcon}\r\n zIndex={props.zIndex}\r\n />\r\n )}\r\n </div>\r\n </ChatContext.Provider>\r\n );\r\n};\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/context/ChatContext.ts","../src/styles/theme.ts","../src/components/icons/Icons.tsx","../src/components/Launcher.tsx","../src/components/ChatHeader.tsx","../src/components/WelcomeScreen.tsx","../src/components/forms/TextField.tsx","../src/components/forms/SelectField.tsx","../src/components/forms/RadioField.tsx","../src/components/forms/CheckboxField.tsx","../src/components/forms/FileUploadField.tsx","../src/components/forms/DynamicForm.tsx","../src/components/LoginScreen.tsx","../src/components/MessageBubble.tsx","../src/components/QuickReplies.tsx","../src/components/TypingIndicator.tsx","../src/components/MessageList.tsx","../src/components/EmojiPicker.tsx","../src/components/FileUpload.tsx","../src/components/ChatInput.tsx","../src/components/Branding.tsx","../src/engine/FlowEngine.ts","../src/utils/helpers.ts","../src/hooks/useChat.ts","../src/components/ChatWindow.tsx","../src/core/PluginManager.ts","../src/components/ChatBot.tsx","../src/plugins/analyticsPlugin.ts","../src/plugins/webhookPlugin.ts","../src/plugins/persistencePlugin.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\r\nimport type { ChatMessage, ChatBotProps } from '../types';\r\n\r\nexport interface ChatState {\r\n isOpen: boolean;\r\n messages: ChatMessage[];\r\n isTyping: boolean;\r\n showWelcome: boolean;\r\n currentStepId: string | null;\r\n collectedData: Record<string, unknown>;\r\n isLoggedIn: boolean;\r\n}\r\n\r\nexport type ChatAction =\r\n | { type: 'TOGGLE_OPEN' }\r\n | { type: 'SET_OPEN'; payload: boolean }\r\n | { type: 'ADD_MESSAGE'; payload: ChatMessage }\r\n | { type: 'ADD_MESSAGES'; payload: ChatMessage[] }\r\n | { type: 'SET_TYPING'; payload: boolean }\r\n | { type: 'DISMISS_WELCOME' }\r\n | { type: 'SET_STEP'; payload: string | null }\r\n | { type: 'SET_DATA'; payload: Record<string, unknown> }\r\n | { type: 'SET_LOGGED_IN'; payload: boolean }\r\n | { type: 'CLEAR_QUICK_REPLIES' }\r\n | { type: 'RESET_CHAT' }\r\n | { type: 'UPDATE_MESSAGE'; payload: { id: string; updates: Partial<ChatMessage> } };\r\n\r\nexport function chatReducer(state: ChatState, action: ChatAction): ChatState {\r\n switch (action.type) {\r\n case 'TOGGLE_OPEN':\r\n return { ...state, isOpen: !state.isOpen };\r\n case 'SET_OPEN':\r\n return { ...state, isOpen: action.payload };\r\n case 'ADD_MESSAGE':\r\n return { ...state, messages: [...state.messages, action.payload] };\r\n case 'ADD_MESSAGES':\r\n return { ...state, messages: [...state.messages, ...action.payload] };\r\n case 'SET_TYPING':\r\n return { ...state, isTyping: action.payload };\r\n case 'DISMISS_WELCOME':\r\n return { ...state, showWelcome: false };\r\n case 'SET_STEP':\r\n return { ...state, currentStepId: action.payload };\r\n case 'SET_DATA':\r\n return { ...state, collectedData: { ...state.collectedData, ...action.payload } };\r\n case 'SET_LOGGED_IN':\r\n return { ...state, isLoggedIn: action.payload };\r\n case 'CLEAR_QUICK_REPLIES': {\r\n // Only clear quick replies from the last message that has them\r\n let lastIdx = -1;\r\n for (let i = state.messages.length - 1; i >= 0; i--) {\r\n if (state.messages[i].quickReplies) { lastIdx = i; break; }\r\n }\r\n if (lastIdx === -1) return state;\r\n const updated = [...state.messages];\r\n updated[lastIdx] = { ...updated[lastIdx], quickReplies: undefined };\r\n return { ...state, messages: updated };\r\n }\r\n case 'RESET_CHAT':\r\n return {\r\n ...state,\r\n messages: [],\r\n isTyping: false,\r\n currentStepId: null,\r\n collectedData: {},\r\n };\r\n case 'UPDATE_MESSAGE':\r\n return {\r\n ...state,\r\n messages: state.messages.map((m) =>\r\n m.id === action.payload.id ? { ...m, ...action.payload.updates } : m,\r\n ),\r\n };\r\n default:\r\n return state;\r\n }\r\n}\r\n\r\nexport const initialState = (props: ChatBotProps): ChatState => ({\r\n isOpen: props.defaultOpen ?? false,\r\n messages: props.initialMessages ?? [],\r\n isTyping: false,\r\n showWelcome: !!props.welcomeScreen,\r\n currentStepId: null,\r\n collectedData: {},\r\n isLoggedIn: !props.loginForm,\r\n});\r\n\r\ninterface ChatContextValue {\r\n state: ChatState;\r\n dispatch: React.Dispatch<ChatAction>;\r\n props: ChatBotProps;\r\n}\r\n\r\nexport const ChatContext = createContext<ChatContextValue | null>(null);\r\n\r\nexport function useChatContext(): ChatContextValue {\r\n const ctx = useContext(ChatContext);\r\n if (!ctx) throw new Error('useChatContext must be used within ChatProvider');\r\n return ctx;\r\n}\r\n","import type { ChatTheme, ChatStyle } from '../types';\r\nimport type { CSSProperties } from 'react';\r\n\r\n// ─── Light Mode Defaults ─────────────────────────────────────────\r\n\r\nconst lightDefaults: Required<ChatTheme> = {\r\n primaryColor: '#6C5CE7',\r\n headerBg: 'linear-gradient(135deg, #6C5CE7 0%, #A29BFE 100%)',\r\n headerText: '#FFFFFF',\r\n bubbleBg: 'rgba(241, 243, 249, 0.85)',\r\n bubbleText: '#2D3436',\r\n userBubbleBg: 'linear-gradient(135deg, #6C5CE7 0%, #A29BFE 100%)',\r\n userBubbleText: '#FFFFFF',\r\n fontFamily: '\"Inter\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\r\n fontSize: '14px',\r\n borderRadius: '20px',\r\n windowWidth: '400px',\r\n windowHeight: '600px',\r\n mode: 'light',\r\n};\r\n\r\n// ─── Dark Mode Overrides ─────────────────────────────────────────\r\n\r\nconst darkOverrides: Partial<ChatTheme> = {\r\n headerBg: 'linear-gradient(135deg, #2D1B69 0%, #4A3298 100%)',\r\n headerText: '#F0F0FF',\r\n bubbleBg: 'rgba(45, 45, 70, 0.85)',\r\n bubbleText: '#E8E8F0',\r\n userBubbleBg: 'linear-gradient(135deg, #6C5CE7 0%, #A29BFE 100%)',\r\n userBubbleText: '#FFFFFF',\r\n};\r\n\r\nexport function resolveTheme(theme?: ChatTheme): Required<ChatTheme> {\r\n const base = { ...lightDefaults, ...theme };\r\n if (base.mode === 'dark') {\r\n return { ...base, ...darkOverrides, ...theme };\r\n }\r\n return base;\r\n}\r\n\r\n// ─── CSS Custom Properties ───────────────────────────────────────\r\n\r\nexport function buildCSSVariables(theme: Required<ChatTheme>): Record<string, string> {\r\n return {\r\n '--cb-primary': theme.primaryColor,\r\n '--cb-header-bg': theme.headerBg,\r\n '--cb-header-text': theme.headerText,\r\n '--cb-bubble-bg': theme.bubbleBg,\r\n '--cb-bubble-text': theme.bubbleText,\r\n '--cb-user-bubble-bg': theme.userBubbleBg,\r\n '--cb-user-bubble-text': theme.userBubbleText,\r\n '--cb-font-family': theme.fontFamily,\r\n '--cb-font-size': theme.fontSize,\r\n '--cb-border-radius': theme.borderRadius,\r\n '--cb-window-width': theme.windowWidth,\r\n '--cb-window-height': theme.windowHeight,\r\n '--cb-bg': theme.mode === 'dark' ? 'rgba(22, 22, 40, 0.95)' : 'rgba(255, 255, 255, 0.92)',\r\n '--cb-border': theme.mode === 'dark' ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)',\r\n '--cb-input-bg': theme.mode === 'dark' ? 'rgba(40, 40, 65, 0.8)' : 'rgba(245, 247, 252, 0.9)',\r\n '--cb-input-border': theme.mode === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.06)',\r\n '--cb-input-text': theme.mode === 'dark' ? '#E0E0E0' : '#2D3436',\r\n '--cb-branding-bg': theme.mode === 'dark' ? 'rgba(20, 20, 35, 0.8)' : 'rgba(250, 250, 255, 0.8)',\r\n };\r\n}\r\n\r\n// ─── Inline Styles Builder ───────────────────────────────────────\r\n\r\nexport function buildStyles(\r\n theme: Required<ChatTheme>,\r\n overrides?: ChatStyle,\r\n) {\r\n const isDark = theme.mode === 'dark';\r\n\r\n const styles = {\r\n root: {\r\n fontFamily: theme.fontFamily,\r\n fontSize: theme.fontSize,\r\n lineHeight: '1.5',\r\n } satisfies CSSProperties,\r\n\r\n launcher: {\r\n position: 'fixed',\r\n width: '62px',\r\n height: '62px',\r\n borderRadius: '50%',\r\n background: theme.headerBg,\r\n color: '#fff',\r\n border: 'none',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n boxShadow: `0 6px 24px rgba(108, 92, 231, 0.4), 0 2px 8px rgba(0,0,0,0.1)`,\r\n transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',\r\n zIndex: 9998,\r\n ...overrides?.launcher,\r\n } satisfies CSSProperties,\r\n\r\n window: {\r\n position: 'fixed',\r\n width: theme.windowWidth,\r\n height: theme.windowHeight,\r\n maxHeight: '85vh',\r\n borderRadius: theme.borderRadius,\r\n overflow: 'hidden',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n boxShadow: isDark\r\n ? '0 20px 60px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.05)'\r\n : '0 20px 60px rgba(108, 92, 231, 0.15), 0 8px 24px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04)',\r\n backgroundColor: isDark ? 'rgba(22, 22, 40, 0.95)' : 'rgba(255, 255, 255, 0.95)',\r\n backdropFilter: 'blur(20px)',\r\n WebkitBackdropFilter: 'blur(20px)',\r\n border: isDark ? '1px solid rgba(255,255,255,0.08)' : '1px solid rgba(255,255,255,0.8)',\r\n zIndex: 9999,\r\n animation: 'cb-window-enter 0.35s cubic-bezier(0.4, 0, 0.2, 1)',\r\n ...overrides?.window,\r\n } satisfies CSSProperties,\r\n\r\n header: {\r\n background: theme.headerBg,\r\n color: theme.headerText,\r\n padding: '18px 20px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'space-between',\r\n gap: '12px',\r\n flexShrink: 0,\r\n position: 'relative',\r\n overflow: 'hidden',\r\n ...overrides?.header,\r\n } satisfies CSSProperties,\r\n\r\n messageList: {\r\n flex: 1,\r\n overflowY: 'auto',\r\n padding: '20px 16px',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: '10px',\r\n background: isDark\r\n ? 'linear-gradient(180deg, rgba(22, 22, 40, 0.98) 0%, rgba(30, 30, 50, 0.98) 100%)'\r\n : 'linear-gradient(180deg, rgba(248, 249, 254, 0.95) 0%, rgba(255, 255, 255, 0.95) 100%)',\r\n ...overrides?.messageList,\r\n } satisfies CSSProperties,\r\n\r\n inputArea: {\r\n padding: '12px 16px 14px',\r\n borderTop: `1px solid ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.05)'}`,\r\n backgroundColor: isDark ? 'rgba(20, 20, 38, 0.9)' : 'rgba(255, 255, 255, 0.95)',\r\n backdropFilter: 'blur(12px)',\r\n WebkitBackdropFilter: 'blur(12px)',\r\n flexShrink: 0,\r\n ...overrides?.inputArea,\r\n } satisfies CSSProperties,\r\n\r\n botBubble: {\r\n background: isDark ? 'rgba(45, 45, 70, 0.7)' : 'rgba(241, 243, 249, 0.9)',\r\n color: isDark ? '#E8E8F0' : '#2D3436',\r\n padding: '12px 16px',\r\n borderRadius: '18px 18px 18px 4px',\r\n maxWidth: '82%',\r\n alignSelf: 'flex-start',\r\n wordBreak: 'break-word',\r\n whiteSpace: 'pre-wrap',\r\n backdropFilter: 'blur(8px)',\r\n WebkitBackdropFilter: 'blur(8px)',\r\n border: isDark ? '1px solid rgba(255,255,255,0.06)' : '1px solid rgba(0,0,0,0.04)',\r\n boxShadow: isDark\r\n ? '0 2px 8px rgba(0,0,0,0.2)'\r\n : '0 2px 8px rgba(0,0,0,0.04)',\r\n fontSize: '14px',\r\n lineHeight: '1.55',\r\n letterSpacing: '0.01em',\r\n } satisfies CSSProperties,\r\n\r\n userBubble: {\r\n background: theme.userBubbleBg,\r\n color: theme.userBubbleText,\r\n padding: '12px 16px',\r\n borderRadius: '18px 18px 4px 18px',\r\n maxWidth: '82%',\r\n alignSelf: 'flex-end',\r\n wordBreak: 'break-word',\r\n whiteSpace: 'pre-wrap',\r\n boxShadow: '0 4px 14px rgba(108, 92, 231, 0.25)',\r\n fontSize: '14px',\r\n lineHeight: '1.55',\r\n letterSpacing: '0.01em',\r\n } satisfies CSSProperties,\r\n };\r\n\r\n return styles;\r\n}\r\n\r\nexport type ChatStyles = ReturnType<typeof buildStyles>;\r\n","import React from 'react';\r\n\r\ninterface IconProps {\r\n size?: number;\r\n color?: string;\r\n className?: string;\r\n}\r\n\r\nexport const SendIcon: React.FC<IconProps> = ({ size = 18, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill={color}>\r\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\" />\r\n </svg>\r\n);\r\n\r\nexport const ChatBubbleIcon: React.FC<IconProps> = ({ size = 28, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\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\" />\r\n </svg>\r\n);\r\n\r\nexport const CloseIcon: React.FC<IconProps> = ({ size = 20, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </svg>\r\n);\r\n\r\nexport const MinimizeIcon: React.FC<IconProps> = ({ size = 20, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\r\n </svg>\r\n);\r\n\r\nexport const EmojiIcon: React.FC<IconProps> = ({ size = 20, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path d=\"M8 14s1.5 2 4 2 4-2 4-2\" />\r\n <line x1=\"9\" y1=\"9\" x2=\"9.01\" y2=\"9\" />\r\n <line x1=\"15\" y1=\"9\" x2=\"15.01\" y2=\"9\" />\r\n </svg>\r\n);\r\n\r\nexport const AttachmentIcon: React.FC<IconProps> = ({ size = 20, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48\" />\r\n </svg>\r\n);\r\n\r\nexport const FileIcon: React.FC<IconProps> = ({ size = 16, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\" />\r\n <polyline points=\"14 2 14 8 20 8\" />\r\n </svg>\r\n);\r\n\r\nexport const ImageIcon: React.FC<IconProps> = ({ size = 16, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\r\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\r\n <polyline points=\"21 15 16 10 5 21\" />\r\n </svg>\r\n);\r\n\r\nexport const RemoveIcon: React.FC<IconProps> = ({ size = 14, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\r\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\r\n </svg>\r\n);\r\n\r\nexport const RestartIcon: React.FC<IconProps> = ({ size = 16, color = 'currentColor' }) => (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polyline points=\"1 4 1 10 7 10\" />\r\n <path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\" />\r\n </svg>\r\n);\r\n","import React from 'react';\r\nimport type { CSSProperties } from 'react';\r\nimport type { ChatStyles } from '../styles/theme';\r\nimport { ChatBubbleIcon, CloseIcon } from './icons';\r\n\r\ninterface LauncherProps {\r\n onClick: () => void;\r\n isOpen: boolean;\r\n position: 'bottom-right' | 'bottom-left';\r\n styles: ChatStyles;\r\n icon?: React.ReactNode;\r\n closeIcon?: React.ReactNode;\r\n zIndex?: number;\r\n}\r\n\r\nexport const Launcher: React.FC<LauncherProps> = ({\r\n onClick,\r\n isOpen,\r\n position,\r\n styles,\r\n icon,\r\n closeIcon,\r\n zIndex,\r\n}) => {\r\n const posStyle: CSSProperties =\r\n position === 'bottom-left'\r\n ? { bottom: '24px', left: '24px' }\r\n : { bottom: '24px', right: '24px' };\r\n\r\n return (\r\n <button\r\n onClick={onClick}\r\n aria-label={isOpen ? 'Close chat' : 'Open chat'}\r\n style={{\r\n ...styles.launcher,\r\n ...posStyle,\r\n ...(zIndex != null ? { zIndex } : {}),\r\n transform: isOpen ? 'scale(0.92) rotate(90deg)' : 'scale(1)',\r\n animation: isOpen ? 'none' : 'cb-launcher-pulse 3s ease-in-out infinite',\r\n }}\r\n >\r\n {isOpen\r\n ? closeIcon ?? <CloseIcon size={22} />\r\n : icon ?? <ChatBubbleIcon size={26} />}\r\n </button>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { HeaderConfig } from '../types';\r\nimport type { ChatStyles as ThemeStyles } from '../styles/theme';\r\nimport { CloseIcon, MinimizeIcon, RestartIcon } from './icons';\r\n\r\ninterface ChatHeaderProps {\r\n config: HeaderConfig;\r\n styles: ThemeStyles;\r\n onClose: () => void;\r\n onRestart?: () => void;\r\n logo?: string;\r\n logoWidth?: string;\r\n}\r\n\r\nexport const ChatHeader: React.FC<ChatHeaderProps> = ({ config, styles, onClose, onRestart, logo, logoWidth }) => {\r\n return (\r\n <div style={styles.header}>\r\n {/* Decorative glow overlay */}\r\n <div\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n background: 'linear-gradient(135deg, rgba(255,255,255,0.12) 0%, transparent 50%)',\r\n pointerEvents: 'none',\r\n }}\r\n />\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '12px', flex: 1, position: 'relative', zIndex: 1 }}>\r\n {config.avatar && (\r\n <div style={{ position: 'relative' }}>\r\n <img\r\n src={config.avatar}\r\n alt=\"\"\r\n style={{\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n objectFit: 'cover',\r\n border: '2px solid rgba(255,255,255,0.3)',\r\n }}\r\n />\r\n <span\r\n style={{\r\n position: 'absolute',\r\n bottom: '1px',\r\n right: '1px',\r\n width: '10px',\r\n height: '10px',\r\n backgroundColor: '#2ECC71',\r\n borderRadius: '50%',\r\n border: '2px solid rgba(255,255,255,0.8)',\r\n }}\r\n />\r\n </div>\r\n )}\r\n {logo && !config.avatar && (\r\n <img\r\n src={logo}\r\n alt=\"\"\r\n style={{ width: logoWidth ?? '36px', height: 'auto', objectFit: 'contain', filter: 'brightness(1.1)' }}\r\n />\r\n )}\r\n {!config.avatar && !logo && (\r\n <div\r\n style={{\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n background: 'rgba(255,255,255,0.2)',\r\n backdropFilter: 'blur(4px)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: '18px',\r\n fontWeight: 700,\r\n color: 'rgba(255,255,255,0.9)',\r\n border: '1px solid rgba(255,255,255,0.2)',\r\n }}\r\n >\r\n {(config.title ?? 'C').charAt(0).toUpperCase()}\r\n </div>\r\n )}\r\n <div>\r\n <div style={{ fontWeight: 600, fontSize: '16px', letterSpacing: '-0.01em' }}>\r\n {config.title ?? 'Chat with us'}\r\n </div>\r\n {config.subtitle && (\r\n <div style={{\r\n fontSize: '12px',\r\n opacity: 0.8,\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '5px',\r\n marginTop: '1px',\r\n }}>\r\n <span style={{\r\n width: '6px',\r\n height: '6px',\r\n borderRadius: '50%',\r\n backgroundColor: '#2ECC71',\r\n display: 'inline-block',\r\n }} />\r\n {config.subtitle}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '2px', position: 'relative', zIndex: 1 }}>\r\n {config.showRestart && onRestart && (\r\n <button\r\n onClick={onRestart}\r\n aria-label=\"Restart conversation\"\r\n title=\"Restart conversation\"\r\n style={{\r\n background: 'rgba(255,255,255,0.1)',\r\n border: 'none',\r\n color: 'inherit',\r\n cursor: 'pointer',\r\n padding: '6px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n borderRadius: '8px',\r\n transition: 'background 0.2s ease',\r\n }}\r\n onMouseEnter={(e) => (e.currentTarget.style.background = 'rgba(255,255,255,0.2)')}\r\n onMouseLeave={(e) => (e.currentTarget.style.background = 'rgba(255,255,255,0.1)')}\r\n >\r\n <RestartIcon size={16} />\r\n </button>\r\n )}\r\n {config.showMinimize && (\r\n <button\r\n onClick={onClose}\r\n aria-label=\"Minimize chat\"\r\n style={{\r\n background: 'rgba(255,255,255,0.1)',\r\n border: 'none',\r\n color: 'inherit',\r\n cursor: 'pointer',\r\n padding: '6px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n borderRadius: '8px',\r\n transition: 'background 0.2s ease',\r\n }}\r\n onMouseEnter={(e) => (e.currentTarget.style.background = 'rgba(255,255,255,0.2)')}\r\n onMouseLeave={(e) => (e.currentTarget.style.background = 'rgba(255,255,255,0.1)')}\r\n >\r\n <MinimizeIcon size={16} />\r\n </button>\r\n )}\r\n {config.showClose !== false && (\r\n <button\r\n onClick={onClose}\r\n aria-label=\"Close chat\"\r\n style={{\r\n background: 'rgba(255,255,255,0.1)',\r\n border: 'none',\r\n color: 'inherit',\r\n cursor: 'pointer',\r\n padding: '6px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n borderRadius: '8px',\r\n transition: 'background 0.2s ease',\r\n }}\r\n onMouseEnter={(e) => (e.currentTarget.style.background = 'rgba(255,255,255,0.2)')}\r\n onMouseLeave={(e) => (e.currentTarget.style.background = 'rgba(255,255,255,0.1)')}\r\n >\r\n <CloseIcon size={18} />\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { ReactNode } from 'react';\r\n\r\ninterface WelcomeScreenProps {\r\n content: ReactNode;\r\n onDismiss: () => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const WelcomeScreen: React.FC<WelcomeScreenProps> = ({ content, onDismiss, primaryColor }) => {\r\n return (\r\n <div\r\n style={{\r\n flex: 1,\r\n display: 'flex',\r\n flexDirection: 'column',\r\n overflow: 'auto',\r\n background: 'linear-gradient(180deg, rgba(248, 249, 254, 0.95) 0%, rgba(255, 255, 255, 0.98) 100%)',\r\n }}\r\n >\r\n <div style={{ flex: 1, padding: '28px 24px', overflow: 'auto' }}>\r\n {content}\r\n </div>\r\n <div\r\n style={{\r\n padding: '16px 20px',\r\n borderTop: '1px solid rgba(0,0,0,0.05)',\r\n backdropFilter: 'blur(12px)',\r\n WebkitBackdropFilter: 'blur(12px)',\r\n flexShrink: 0,\r\n }}\r\n >\r\n <button\r\n onClick={onDismiss}\r\n style={{\r\n width: '100%',\r\n padding: '14px',\r\n background: `linear-gradient(135deg, ${primaryColor} 0%, ${adjustColor(primaryColor, 30)} 100%)`,\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '14px',\r\n fontSize: '15px',\r\n fontWeight: 600,\r\n cursor: 'pointer',\r\n fontFamily: 'inherit',\r\n letterSpacing: '0.02em',\r\n boxShadow: `0 6px 20px ${primaryColor}44`,\r\n transition: 'all 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.transform = 'translateY(-1px)';\r\n e.currentTarget.style.boxShadow = `0 8px 28px ${primaryColor}55`;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n e.currentTarget.style.boxShadow = `0 6px 20px ${primaryColor}44`;\r\n }}\r\n >\r\n Start Chat\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nfunction adjustColor(hex: string, amount: number): string {\r\n const num = parseInt(hex.replace('#', ''), 16);\r\n const r = Math.min(255, ((num >> 16) & 0xff) + amount);\r\n const g = Math.min(255, ((num >> 8) & 0xff) + amount);\r\n const b = Math.min(255, (num & 0xff) + amount);\r\n return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;\r\n}\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface TextFieldProps {\r\n field: FormFieldConfig;\r\n value: string;\r\n onChange: (value: string) => void;\r\n error?: string;\r\n}\r\n\r\nexport const TextField: React.FC<TextFieldProps> = ({ field, value, onChange, error }) => {\r\n const isTextarea = field.type === 'textarea';\r\n const inputType = field.type === 'textarea' ? undefined : field.type;\r\n\r\n const baseStyle: React.CSSProperties = {\r\n width: '100%',\r\n padding: '10px 14px',\r\n border: `1.5px solid ${error ? 'rgba(229, 62, 62, 0.5)' : 'rgba(0,0,0,0.08)'}`,\r\n borderRadius: '12px',\r\n fontSize: '13px',\r\n fontFamily: 'inherit',\r\n outline: 'none',\r\n boxSizing: 'border-box',\r\n transition: 'all 0.2s ease',\r\n backgroundColor: 'rgba(245, 247, 252, 0.6)',\r\n color: '#2D3436',\r\n letterSpacing: '0.01em',\r\n };\r\n\r\n return (\r\n <div style={{ marginBottom: '14px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '6px', fontSize: '13px', fontWeight: 500, color: '#2D3436' }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '3px' }}>*</span>}\r\n </label>\r\n )}\r\n {isTextarea ? (\r\n <textarea\r\n value={value}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder={field.placeholder}\r\n required={field.required}\r\n rows={3}\r\n style={{ ...baseStyle, resize: 'vertical' }}\r\n minLength={field.validation?.minLength}\r\n maxLength={field.validation?.maxLength}\r\n />\r\n ) : (\r\n <input\r\n type={inputType}\r\n value={value}\r\n onChange={(e) => onChange(e.target.value)}\r\n placeholder={field.placeholder}\r\n required={field.required}\r\n style={baseStyle}\r\n min={field.validation?.min}\r\n max={field.validation?.max}\r\n minLength={field.validation?.minLength}\r\n maxLength={field.validation?.maxLength}\r\n pattern={field.validation?.pattern}\r\n />\r\n )}\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface SelectFieldProps {\r\n field: FormFieldConfig;\r\n value: string | string[];\r\n onChange: (value: string | string[]) => void;\r\n error?: string;\r\n}\r\n\r\nexport const SelectField: React.FC<SelectFieldProps> = ({ field, value, onChange, error }) => {\r\n const isMulti = field.type === 'multiselect' || field.multiple;\r\n\r\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\r\n if (isMulti) {\r\n const selected = Array.from(e.target.selectedOptions, (opt) => opt.value);\r\n onChange(selected);\r\n } else {\r\n onChange(e.target.value);\r\n }\r\n };\r\n\r\n const selectValue = isMulti\r\n ? Array.isArray(value) ? value : [value].filter(Boolean)\r\n : typeof value === 'string' ? value : '';\r\n\r\n return (\r\n <div style={{ marginBottom: '14px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '6px', fontSize: '13px', fontWeight: 500, color: '#2D3436' }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '3px' }}>*</span>}\r\n </label>\r\n )}\r\n <select\r\n value={selectValue}\r\n onChange={handleChange}\r\n multiple={isMulti}\r\n required={field.required}\r\n style={{\r\n width: '100%',\r\n padding: '10px 14px',\r\n border: `1.5px solid ${error ? 'rgba(229, 62, 62, 0.5)' : 'rgba(0,0,0,0.08)'}`,\r\n borderRadius: '12px',\r\n fontSize: '13px',\r\n fontFamily: 'inherit',\r\n outline: 'none',\r\n backgroundColor: 'rgba(245, 247, 252, 0.6)',\r\n color: '#2D3436',\r\n boxSizing: 'border-box',\r\n transition: 'all 0.2s ease',\r\n ...(isMulti ? { minHeight: '80px' } : {}),\r\n }}\r\n >\r\n {!isMulti && <option value=\"\">Select...</option>}\r\n {field.options?.map((opt) => (\r\n <option key={opt.value} value={opt.value}>\r\n {opt.label}\r\n </option>\r\n ))}\r\n </select>\r\n {isMulti && (\r\n <div style={{ fontSize: '11px', color: '#888', marginTop: '2px' }}>\r\n Hold Ctrl/Cmd to select multiple\r\n </div>\r\n )}\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface RadioFieldProps {\r\n field: FormFieldConfig;\r\n value: string;\r\n onChange: (value: string) => void;\r\n error?: string;\r\n}\r\n\r\nexport const RadioField: React.FC<RadioFieldProps> = ({ field, value, onChange, error }) => {\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '6px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\r\n {field.options?.map((opt) => (\r\n <label\r\n key={opt.value}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n }}\r\n >\r\n <input\r\n type=\"radio\"\r\n name={field.name}\r\n value={opt.value}\r\n checked={value === opt.value}\r\n onChange={() => onChange(opt.value)}\r\n style={{ margin: 0 }}\r\n />\r\n {opt.label}\r\n </label>\r\n ))}\r\n </div>\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface CheckboxFieldProps {\r\n field: FormFieldConfig;\r\n value: string[];\r\n onChange: (value: string[]) => void;\r\n error?: string;\r\n}\r\n\r\nexport const CheckboxField: React.FC<CheckboxFieldProps> = ({ field, value, onChange, error }) => {\r\n const handleToggle = (optValue: string) => {\r\n if (value.includes(optValue)) {\r\n onChange(value.filter((v) => v !== optValue));\r\n } else {\r\n onChange([...value, optValue]);\r\n }\r\n };\r\n\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '6px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>\r\n {field.options?.map((opt) => (\r\n <label\r\n key={opt.value}\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n }}\r\n >\r\n <input\r\n type=\"checkbox\"\r\n checked={value.includes(opt.value)}\r\n onChange={() => handleToggle(opt.value)}\r\n style={{ margin: 0 }}\r\n />\r\n {opt.label}\r\n </label>\r\n ))}\r\n </div>\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React, { useRef } from 'react';\r\nimport type { FormFieldConfig } from '../../types';\r\n\r\ninterface FileUploadFieldProps {\r\n field: FormFieldConfig;\r\n value: FileList | null;\r\n onChange: (files: FileList | null) => void;\r\n error?: string;\r\n primaryColor: string;\r\n}\r\n\r\nexport const FileUploadField: React.FC<FileUploadFieldProps> = ({\r\n field,\r\n value,\r\n onChange,\r\n error,\r\n primaryColor,\r\n}) => {\r\n const inputRef = useRef<HTMLInputElement>(null);\r\n\r\n const fileNames = value ? Array.from(value).map((f) => f.name).join(', ') : '';\r\n\r\n return (\r\n <div style={{ marginBottom: '12px' }}>\r\n {field.label && (\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '13px', fontWeight: 500 }}>\r\n {field.label}\r\n {field.required && <span style={{ color: '#E53E3E', marginLeft: '2px' }}>*</span>}\r\n </label>\r\n )}\r\n <input\r\n ref={inputRef}\r\n type=\"file\"\r\n accept={field.accept}\r\n multiple={field.multiple}\r\n onChange={(e) => onChange(e.target.files)}\r\n style={{ display: 'none' }}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => inputRef.current?.click()}\r\n style={{\r\n padding: '8px 16px',\r\n border: `1px dashed ${error ? '#E53E3E' : '#D1D5DB'}`,\r\n borderRadius: '8px',\r\n backgroundColor: '#FAFAFA',\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n color: '#555',\r\n width: '100%',\r\n textAlign: 'left',\r\n }}\r\n >\r\n {fileNames || field.placeholder || 'Choose file(s)...'}\r\n </button>\r\n {fileNames && (\r\n <div style={{ fontSize: '12px', color: primaryColor, marginTop: '4px' }}>\r\n {Array.from(value!).length} file(s) selected\r\n </div>\r\n )}\r\n {error && <div style={{ color: '#E53E3E', fontSize: '12px', marginTop: '2px' }}>{error}</div>}\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useCallback } from 'react';\r\nimport type { FormConfig, FormFieldConfig } from '../../types';\r\nimport { TextField } from './TextField';\r\nimport { SelectField } from './SelectField';\r\nimport { RadioField } from './RadioField';\r\nimport { CheckboxField } from './CheckboxField';\r\nimport { FileUploadField } from './FileUploadField';\r\n\r\ninterface DynamicFormProps {\r\n config: FormConfig;\r\n onSubmit: (data: Record<string, unknown>) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const DynamicForm: React.FC<DynamicFormProps> = ({ config, onSubmit, primaryColor }) => {\r\n const [values, setValues] = useState<Record<string, unknown>>(() => {\r\n const init: Record<string, unknown> = {};\r\n for (const field of config.fields) {\r\n if (field.defaultValue !== undefined) {\r\n init[field.name] = field.defaultValue;\r\n } else if (field.type === 'checkbox' || field.type === 'multiselect') {\r\n init[field.name] = [];\r\n } else if (field.type === 'file') {\r\n init[field.name] = null;\r\n } else {\r\n init[field.name] = '';\r\n }\r\n }\r\n return init;\r\n });\r\n\r\n const [errors, setErrors] = useState<Record<string, string>>({});\r\n const [submitted, setSubmitted] = useState(false);\r\n\r\n const setValue = useCallback((name: string, value: unknown) => {\r\n setValues((prev) => ({ ...prev, [name]: value }));\r\n setErrors((prev) => {\r\n const next = { ...prev };\r\n delete next[name];\r\n return next;\r\n });\r\n }, []);\r\n\r\n const validate = (): boolean => {\r\n const newErrors: Record<string, string> = {};\r\n\r\n for (const field of config.fields) {\r\n const val = values[field.name];\r\n\r\n // Required check\r\n if (field.required) {\r\n if (\r\n val === '' ||\r\n val === null ||\r\n val === undefined ||\r\n (Array.isArray(val) && val.length === 0)\r\n ) {\r\n newErrors[field.name] = field.validation?.message ?? `${field.label || field.name} is required`;\r\n continue;\r\n }\r\n }\r\n\r\n // Pattern check\r\n if (field.validation?.pattern && typeof val === 'string' && val) {\r\n try {\r\n const regex = new RegExp(field.validation.pattern);\r\n if (!regex.test(val)) {\r\n newErrors[field.name] = field.validation.message ?? 'Invalid format';\r\n }\r\n } catch {\r\n // Invalid regex pattern in config — skip validation\r\n }\r\n }\r\n }\r\n\r\n setErrors(newErrors);\r\n return Object.keys(newErrors).length === 0;\r\n };\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!validate()) return;\r\n setSubmitted(true);\r\n onSubmit(values);\r\n };\r\n\r\n if (submitted) {\r\n return (\r\n <div\r\n style={{\r\n padding: '16px',\r\n background: 'linear-gradient(135deg, rgba(46, 213, 115, 0.1), rgba(46, 213, 115, 0.05))',\r\n borderRadius: '14px',\r\n fontSize: '14px',\r\n color: '#2ecc71',\r\n textAlign: 'center',\r\n fontWeight: 500,\r\n border: '1px solid rgba(46, 213, 115, 0.15)',\r\n animation: 'cb-fade-in 0.3s ease-out',\r\n }}\r\n >\r\n ✓ Submitted successfully\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <form\r\n onSubmit={handleSubmit}\r\n style={{\r\n background: 'rgba(255, 255, 255, 0.7)',\r\n backdropFilter: 'blur(12px)',\r\n WebkitBackdropFilter: 'blur(12px)',\r\n borderRadius: '16px',\r\n padding: '20px',\r\n border: '1px solid rgba(0,0,0,0.06)',\r\n boxShadow: '0 4px 16px rgba(0,0,0,0.04)',\r\n animation: 'cb-slide-up 0.35s ease-out',\r\n }}\r\n >\r\n {config.title && (\r\n <div style={{ fontWeight: 600, fontSize: '15px', marginBottom: '4px', color: '#2D3436', letterSpacing: '-0.01em' }}>\r\n {config.title}\r\n </div>\r\n )}\r\n {config.description && (\r\n <div style={{ fontSize: '12px', color: 'rgba(0,0,0,0.45)', marginBottom: '16px', lineHeight: '1.5' }}>\r\n {config.description}\r\n </div>\r\n )}\r\n\r\n {config.fields.map((field) => (\r\n <FormField\r\n key={field.name}\r\n field={field}\r\n value={values[field.name]}\r\n onChange={(v) => setValue(field.name, v)}\r\n error={errors[field.name]}\r\n primaryColor={primaryColor}\r\n />\r\n ))}\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: '100%',\r\n padding: '12px',\r\n background: `linear-gradient(135deg, ${primaryColor} 0%, ${adjustColor(primaryColor, 30)} 100%)`,\r\n color: '#fff',\r\n border: 'none',\r\n borderRadius: '12px',\r\n fontSize: '14px',\r\n fontWeight: 600,\r\n cursor: 'pointer',\r\n marginTop: '8px',\r\n fontFamily: 'inherit',\r\n letterSpacing: '0.02em',\r\n boxShadow: `0 4px 14px ${primaryColor}33`,\r\n transition: 'all 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.transform = 'translateY(-1px)';\r\n e.currentTarget.style.boxShadow = `0 6px 20px ${primaryColor}44`;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n e.currentTarget.style.boxShadow = `0 4px 14px ${primaryColor}33`;\r\n }}\r\n >\r\n {config.submitLabel ?? 'Submit'}\r\n </button>\r\n </form>\r\n );\r\n};\r\n\r\n// ─── Field Router ────────────────────────────────────────────────\r\n\r\ninterface FormFieldProps {\r\n field: FormFieldConfig;\r\n value: unknown;\r\n onChange: (value: unknown) => void;\r\n error?: string;\r\n primaryColor: string;\r\n}\r\n\r\nconst FormField: React.FC<FormFieldProps> = ({ field, value, onChange, error, primaryColor }) => {\r\n switch (field.type) {\r\n case 'text':\r\n case 'email':\r\n case 'password':\r\n case 'number':\r\n case 'tel':\r\n case 'url':\r\n case 'textarea':\r\n case 'date':\r\n case 'time':\r\n return (\r\n <TextField\r\n field={field}\r\n value={String(value ?? '')}\r\n onChange={onChange as (v: string) => void}\r\n error={error}\r\n />\r\n );\r\n case 'select':\r\n case 'multiselect':\r\n return (\r\n <SelectField\r\n field={field}\r\n value={value as string | string[]}\r\n onChange={onChange as (v: string | string[]) => void}\r\n error={error}\r\n />\r\n );\r\n case 'radio':\r\n return (\r\n <RadioField\r\n field={field}\r\n value={String(value ?? '')}\r\n onChange={onChange as (v: string) => void}\r\n error={error}\r\n />\r\n );\r\n case 'checkbox':\r\n return (\r\n <CheckboxField\r\n field={field}\r\n value={(value as string[]) ?? []}\r\n onChange={onChange as (v: string[]) => void}\r\n error={error}\r\n />\r\n );\r\n case 'file':\r\n return (\r\n <FileUploadField\r\n field={field}\r\n value={value as FileList | null}\r\n onChange={onChange as (v: FileList | null) => void}\r\n error={error}\r\n primaryColor={primaryColor}\r\n />\r\n );\r\n case 'hidden':\r\n return <input type=\"hidden\" name={field.name} value={String(value ?? '')} />;\r\n default:\r\n return null;\r\n }\r\n};\r\n\r\nfunction adjustColor(hex: string, amount: number): string {\r\n const num = parseInt(hex.replace('#', ''), 16);\r\n const r = Math.min(255, ((num >> 16) & 0xff) + amount);\r\n const g = Math.min(255, ((num >> 8) & 0xff) + amount);\r\n const b = Math.min(255, (num & 0xff) + amount);\r\n return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;\r\n}\r\n","import React from 'react';\r\nimport type { FormConfig } from '../types';\r\nimport { DynamicForm } from './forms/DynamicForm';\r\n\r\ninterface LoginScreenProps {\r\n config: FormConfig;\r\n onLogin: (data: Record<string, unknown>) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const LoginScreen: React.FC<LoginScreenProps> = ({ config, onLogin, primaryColor }) => {\r\n return (\r\n <div\r\n style={{\r\n flex: 1,\r\n display: 'flex',\r\n flexDirection: 'column',\r\n justifyContent: 'center',\r\n padding: '24px',\r\n overflow: 'auto',\r\n background: 'linear-gradient(180deg, rgba(248, 249, 254, 0.95) 0%, rgba(255, 255, 255, 0.98) 100%)',\r\n }}\r\n >\r\n <DynamicForm config={config} onSubmit={onLogin} primaryColor={primaryColor} />\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { ChatMessage, MessageAttachment } from '../types';\r\nimport type { ChatStyles } from '../styles/theme';\r\nimport { FileIcon } from './icons';\r\n\r\ninterface MessageBubbleProps {\r\n message: ChatMessage;\r\n styles: ChatStyles;\r\n}\r\n\r\nexport const MessageBubble: React.FC<MessageBubbleProps> = ({ message, styles }) => {\r\n const isBot = message.sender === 'bot';\r\n const isSystem = message.sender === 'system';\r\n const bubbleStyle = isBot || isSystem ? styles.botBubble : styles.userBubble;\r\n\r\n const hasContent = message.text || (message.attachments && message.attachments.length > 0);\r\n if (!hasContent) return null;\r\n\r\n const systemStyle: React.CSSProperties = isSystem\r\n ? {\r\n background: 'transparent',\r\n border: 'none',\r\n boxShadow: 'none',\r\n color: '#999',\r\n fontSize: '12px',\r\n alignSelf: 'center',\r\n padding: '6px 12px',\r\n backdropFilter: 'none',\r\n WebkitBackdropFilter: 'none',\r\n }\r\n : {};\r\n\r\n return (\r\n <div\r\n style={{\r\n ...bubbleStyle,\r\n ...systemStyle,\r\n animation: 'cb-fade-in 0.3s ease-out',\r\n }}\r\n >\r\n {message.text && (\r\n <span style={{ display: 'block' }}>{message.text}</span>\r\n )}\r\n {message.attachments && message.attachments.length > 0 && (\r\n <div style={{ marginTop: message.text ? '10px' : 0, display: 'flex', flexDirection: 'column', gap: '6px' }}>\r\n {message.attachments.map((attachment, i) => (\r\n <AttachmentPreview key={i} attachment={attachment} isBot={isBot} />\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n// ─── Attachment Preview ──────────────────────────────────────────\r\n\r\ninterface AttachmentPreviewProps {\r\n attachment: MessageAttachment;\r\n isBot: boolean;\r\n}\r\n\r\nconst AttachmentPreview: React.FC<AttachmentPreviewProps> = ({ attachment, isBot }) => {\r\n const isImage = attachment.type.startsWith('image/');\r\n\r\n if (isImage && attachment.url) {\r\n return (\r\n <div style={{ borderRadius: '12px', overflow: 'hidden', maxWidth: '220px' }}>\r\n <img\r\n src={attachment.url}\r\n alt={attachment.name}\r\n style={{\r\n width: '100%',\r\n height: 'auto',\r\n display: 'block',\r\n borderRadius: '12px',\r\n }}\r\n />\r\n <div style={{ fontSize: '11px', padding: '4px 0', opacity: 0.6 }}>{attachment.name}</div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <a\r\n href={attachment.url}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n padding: '8px 12px',\r\n backgroundColor: isBot ? 'rgba(0,0,0,0.04)' : 'rgba(255,255,255,0.15)',\r\n borderRadius: '10px',\r\n textDecoration: 'none',\r\n color: 'inherit',\r\n fontSize: '13px',\r\n border: isBot ? '1px solid rgba(0,0,0,0.06)' : '1px solid rgba(255,255,255,0.15)',\r\n transition: 'background 0.2s ease',\r\n }}\r\n >\r\n <FileIcon size={16} />\r\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flex: 1 }}>\r\n {attachment.name}\r\n </span>\r\n {attachment.size && (\r\n <span style={{ fontSize: '11px', opacity: 0.5, flexShrink: 0 }}>\r\n {formatFileSize(attachment.size)}\r\n </span>\r\n )}\r\n </a>\r\n );\r\n};\r\n\r\nfunction formatFileSize(bytes: number): string {\r\n if (bytes < 1024) return `${bytes}B`;\r\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\r\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\r\n}\r\n","import React from 'react';\r\nimport type { FlowQuickReply } from '../types';\r\n\r\ninterface QuickRepliesProps {\r\n replies: FlowQuickReply[];\r\n onSelect: (value: string, label: string) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const QuickReplies: React.FC<QuickRepliesProps> = ({ replies, onSelect, primaryColor }) => {\r\n return (\r\n <div\r\n style={{\r\n display: 'flex',\r\n flexWrap: 'wrap',\r\n gap: '8px',\r\n alignSelf: 'flex-start',\r\n maxWidth: '90%',\r\n animation: 'cb-slide-up 0.35s ease-out',\r\n padding: '4px 0',\r\n }}\r\n >\r\n {replies.map((reply) => (\r\n <button\r\n key={reply.value}\r\n onClick={() => onSelect(reply.value, reply.label)}\r\n style={{\r\n padding: '8px 18px',\r\n borderRadius: '22px',\r\n border: `1.5px solid ${primaryColor}`,\r\n backgroundColor: 'rgba(108, 92, 231, 0.06)',\r\n color: primaryColor,\r\n cursor: 'pointer',\r\n fontSize: '13px',\r\n fontWeight: 500,\r\n fontFamily: 'inherit',\r\n transition: 'all 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\r\n backdropFilter: 'blur(4px)',\r\n WebkitBackdropFilter: 'blur(4px)',\r\n letterSpacing: '0.01em',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = primaryColor;\r\n e.currentTarget.style.color = '#fff';\r\n e.currentTarget.style.transform = 'translateY(-1px)';\r\n e.currentTarget.style.boxShadow = `0 4px 14px ${primaryColor}44`;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = 'rgba(108, 92, 231, 0.06)';\r\n e.currentTarget.style.color = primaryColor;\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n e.currentTarget.style.boxShadow = 'none';\r\n }}\r\n >\r\n {reply.label}\r\n </button>\r\n ))}\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\n\r\ninterface TypingIndicatorProps {\r\n color: string;\r\n}\r\n\r\nexport const TypingIndicator: React.FC<TypingIndicatorProps> = ({ color }) => {\r\n const dotStyle: React.CSSProperties = {\r\n width: '7px',\r\n height: '7px',\r\n borderRadius: '50%',\r\n backgroundColor: color,\r\n opacity: 0.35,\r\n animation: 'cb-typing-bounce 1.4s infinite ease-in-out',\r\n };\r\n\r\n return (\r\n <div\r\n style={{\r\n display: 'flex',\r\n gap: '5px',\r\n padding: '14px 18px',\r\n background: 'rgba(241, 243, 249, 0.8)',\r\n backdropFilter: 'blur(8px)',\r\n WebkitBackdropFilter: 'blur(8px)',\r\n borderRadius: '18px 18px 18px 4px',\r\n alignSelf: 'flex-start',\r\n alignItems: 'center',\r\n border: '1px solid rgba(0,0,0,0.04)',\r\n boxShadow: '0 2px 8px rgba(0,0,0,0.04)',\r\n animation: 'cb-fade-in 0.3s ease-out',\r\n }}\r\n >\r\n <span style={{ ...dotStyle, animationDelay: '0s' }} />\r\n <span style={{ ...dotStyle, animationDelay: '0.2s' }} />\r\n <span style={{ ...dotStyle, animationDelay: '0.4s' }} />\r\n </div>\r\n );\r\n};\r\n","import React, { useRef, useEffect } from 'react';\r\nimport type { ComponentType } from 'react';\r\nimport type { ChatMessage } from '../types';\r\nimport type { StepComponentProps, FlowActionResult } from '../types/config';\r\nimport type { ChatStyles } from '../styles/theme';\r\nimport { MessageBubble } from './MessageBubble';\r\nimport { QuickReplies } from './QuickReplies';\r\nimport { TypingIndicator } from './TypingIndicator';\r\nimport { DynamicForm } from './forms/DynamicForm';\r\n\r\ninterface MessageListProps {\r\n messages: ChatMessage[];\r\n isTyping: boolean;\r\n styles: ChatStyles;\r\n primaryColor: string;\r\n onQuickReply: (value: string, label: string) => void;\r\n onFormSubmit: (formId: string, data: Record<string, unknown>) => void;\r\n /** Map of custom step components */\r\n components?: Record<string, ComponentType<StepComponentProps>>;\r\n /** Called when a custom component completes */\r\n onComponentComplete?: (result?: FlowActionResult) => void;\r\n /** Collected flow data — passed to custom components */\r\n collectedData?: Record<string, unknown>;\r\n /** Current step ID */\r\n currentStepId?: string | null;\r\n}\r\n\r\nexport const MessageList: React.FC<MessageListProps> = ({\r\n messages,\r\n isTyping,\r\n styles,\r\n primaryColor,\r\n onQuickReply,\r\n onFormSubmit,\r\n components,\r\n onComponentComplete,\r\n collectedData,\r\n currentStepId,\r\n}) => {\r\n const bottomRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' });\r\n }, [messages, isTyping]);\r\n\r\n return (\r\n <div style={styles.messageList} className=\"cb-scrollbar\">\r\n {messages.map((msg) => (\r\n <React.Fragment key={msg.id}>\r\n <MessageBubble message={msg} styles={styles} />\r\n {msg.quickReplies && msg.quickReplies.length > 0 && (\r\n <QuickReplies\r\n replies={msg.quickReplies}\r\n onSelect={onQuickReply}\r\n primaryColor={primaryColor}\r\n />\r\n )}\r\n {msg.form && (\r\n <div style={{ alignSelf: 'flex-start', width: '92%', animation: 'cb-slide-up 0.35s ease-out' }}>\r\n <DynamicForm\r\n config={msg.form}\r\n onSubmit={(data) => onFormSubmit(msg.form!.id, data)}\r\n primaryColor={primaryColor}\r\n />\r\n </div>\r\n )}\r\n {msg.component && components?.[msg.component] && (\r\n <div style={{ alignSelf: 'flex-start', width: '92%', animation: 'cb-slide-up 0.35s ease-out' }}>\r\n {React.createElement(components[msg.component], {\r\n stepId: currentStepId ?? '',\r\n data: collectedData ?? {},\r\n onComplete: (result?: FlowActionResult) => onComponentComplete?.(result),\r\n })}\r\n </div>\r\n )}\r\n </React.Fragment>\r\n ))}\r\n {isTyping && <TypingIndicator color={primaryColor} />}\r\n <div ref={bottomRef} />\r\n </div>\r\n );\r\n};\r\n","import React, { useState, useRef, useEffect } from 'react';\r\n\r\nconst EMOJI_CATEGORIES = [\r\n {\r\n name: 'Smileys',\r\n emojis: ['😀', '😃', '😄', '😁', '😅', '😂', '🤣', '😊', '😇', '🙂', '😉', '😍', '🥰', '😘', '😋', '😜', '🤪', '🤗', '🤔', '🤫', '🤭', '😏', '😐', '😑', '😶', '😌', '😴', '🤤', '😷', '🤒'],\r\n },\r\n {\r\n name: 'Gestures',\r\n emojis: ['👍', '👎', '👌', '✌️', '🤞', '🤟', '🤘', '👋', '🤚', '✋', '🖖', '👏', '🙌', '🤝', '🙏', '💪', '🖐️', '☝️', '👆', '👇', '👈', '👉', '🤙', '🫡', '🫶', '🫰', '🫳', '🫴', '🫲', '🫱'],\r\n },\r\n {\r\n name: 'Hearts',\r\n emojis: ['❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '♥️', '🫀', '💌', '💐', '🌹', '🌺', '🌸', '🌼', '🌻', '🌷', '💮'],\r\n },\r\n {\r\n name: 'Objects',\r\n emojis: ['🔥', '⭐', '✨', '💯', '🎉', '🎊', '🎯', '🚀', '💡', '📌', '📎', '🔗', '💻', '📱', '☎️', '📧', '📝', '📋', '📊', '📈', '🗂️', '📁', '🔒', '🔑', '⚙️', '🛠️', '🔧', '📦', '🏷️', '✅'],\r\n },\r\n];\r\n\r\ninterface EmojiPickerProps {\r\n onSelect: (emoji: string) => void;\r\n onClose: () => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const EmojiPicker: React.FC<EmojiPickerProps> = ({ onSelect, onClose, primaryColor }) => {\r\n const [activeCategory, setActiveCategory] = useState(0);\r\n const pickerRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n const handleClickOutside = (e: MouseEvent) => {\r\n if (pickerRef.current && !pickerRef.current.contains(e.target as Node)) {\r\n onClose();\r\n }\r\n };\r\n document.addEventListener('mousedown', handleClickOutside);\r\n return () => document.removeEventListener('mousedown', handleClickOutside);\r\n }, [onClose]);\r\n\r\n const currentEmojis = EMOJI_CATEGORIES[activeCategory]?.emojis ?? [];\r\n\r\n return (\r\n <div\r\n ref={pickerRef}\r\n style={{\r\n position: 'absolute',\r\n bottom: '100%',\r\n left: 0,\r\n width: '280px',\r\n backgroundColor: 'rgba(255, 255, 255, 0.92)',\r\n backdropFilter: 'blur(20px)',\r\n WebkitBackdropFilter: 'blur(20px)',\r\n borderRadius: '16px',\r\n boxShadow: '0 8px 32px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04)',\r\n border: '1px solid rgba(255,255,255,0.8)',\r\n overflow: 'hidden',\r\n zIndex: 10,\r\n marginBottom: '8px',\r\n animation: 'cb-slide-up 0.25s ease-out',\r\n }}\r\n >\r\n {/* Category tabs */}\r\n <div\r\n style={{\r\n display: 'flex',\r\n borderBottom: '1px solid rgba(0,0,0,0.06)',\r\n padding: '6px',\r\n gap: '3px',\r\n }}\r\n >\r\n {EMOJI_CATEGORIES.map((cat, idx) => (\r\n <button\r\n key={cat.name}\r\n onClick={() => setActiveCategory(idx)}\r\n title={cat.name}\r\n style={{\r\n flex: 1,\r\n padding: '6px 4px',\r\n border: 'none',\r\n borderRadius: '8px',\r\n cursor: 'pointer',\r\n fontSize: '11px',\r\n fontWeight: 600,\r\n fontFamily: 'inherit',\r\n letterSpacing: '0.02em',\r\n background: idx === activeCategory\r\n ? `linear-gradient(135deg, ${primaryColor}, ${primaryColor}CC)`\r\n : 'transparent',\r\n color: idx === activeCategory ? '#fff' : 'rgba(0,0,0,0.4)',\r\n transition: 'all 0.2s ease',\r\n boxShadow: idx === activeCategory ? `0 2px 8px ${primaryColor}33` : 'none',\r\n }}\r\n >\r\n {cat.name}\r\n </button>\r\n ))}\r\n </div>\r\n\r\n {/* Emoji Grid */}\r\n <div\r\n style={{\r\n display: 'grid',\r\n gridTemplateColumns: 'repeat(8, 1fr)',\r\n gap: '2px',\r\n padding: '8px',\r\n maxHeight: '180px',\r\n overflowY: 'auto',\r\n }}\r\n >\r\n {currentEmojis.map((emoji) => (\r\n <button\r\n key={emoji}\r\n onClick={() => {\r\n onSelect(emoji);\r\n onClose();\r\n }}\r\n style={{\r\n width: '30px',\r\n height: '30px',\r\n border: 'none',\r\n backgroundColor: 'transparent',\r\n cursor: 'pointer',\r\n fontSize: '18px',\r\n borderRadius: '6px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n transition: 'all 0.15s ease',\r\n }}\r\n onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = 'rgba(108, 92, 231, 0.08)')}\r\n onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = 'transparent')}\r\n >\r\n {emoji}\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React, { useRef } from 'react';\r\nimport type { FileUploadConfig } from '../types/config';\r\nimport { AttachmentIcon, RemoveIcon, FileIcon, ImageIcon } from './icons';\r\n\r\ninterface FileUploadButtonProps {\r\n config: FileUploadConfig;\r\n onFiles: (files: File[]) => void;\r\n selectedFiles: File[];\r\n onRemoveFile: (index: number) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const FileUploadButton: React.FC<FileUploadButtonProps> = ({\r\n config,\r\n onFiles,\r\n selectedFiles,\r\n onRemoveFile,\r\n primaryColor,\r\n}) => {\r\n const inputRef = useRef<HTMLInputElement>(null);\r\n\r\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const files = e.target.files;\r\n if (!files || files.length === 0) return;\r\n\r\n const fileArr = Array.from(files);\r\n\r\n // Validate file size\r\n if (config.maxSize) {\r\n const oversized = fileArr.filter((f) => f.size > config.maxSize!);\r\n if (oversized.length > 0) {\r\n alert(`File(s) too large. Max size: ${formatSize(config.maxSize)}`);\r\n return;\r\n }\r\n }\r\n\r\n // Validate max count\r\n const maxFiles = config.maxFiles ?? 5;\r\n if (selectedFiles.length + fileArr.length > maxFiles) {\r\n alert(`Maximum ${maxFiles} files allowed`);\r\n return;\r\n }\r\n\r\n onFiles(fileArr);\r\n // Reset input to allow re-selecting same file\r\n if (inputRef.current) inputRef.current.value = '';\r\n };\r\n\r\n return (\r\n <div>\r\n <input\r\n ref={inputRef}\r\n type=\"file\"\r\n accept={config.accept}\r\n multiple={config.multiple !== false}\r\n onChange={handleChange}\r\n style={{ display: 'none' }}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => inputRef.current?.click()}\r\n aria-label=\"Attach file\"\r\n title=\"Attach file\"\r\n style={{\r\n background: 'none',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n color: '#999',\r\n borderRadius: '6px',\r\n transition: 'color 0.15s ease',\r\n }}\r\n onMouseEnter={(e) => (e.currentTarget.style.color = primaryColor)}\r\n onMouseLeave={(e) => (e.currentTarget.style.color = '#999')}\r\n >\r\n <AttachmentIcon size={20} />\r\n </button>\r\n </div>\r\n );\r\n};\r\n\r\n// ─── File Preview List ───────────────────────────────────────────\r\n\r\ninterface FilePreviewListProps {\r\n files: File[];\r\n onRemove: (index: number) => void;\r\n primaryColor: string;\r\n}\r\n\r\nexport const FilePreviewList: React.FC<FilePreviewListProps> = ({\r\n files,\r\n onRemove,\r\n primaryColor,\r\n}) => {\r\n if (files.length === 0) return null;\r\n\r\n return (\r\n <div\r\n style={{\r\n display: 'flex',\r\n flexWrap: 'wrap',\r\n gap: '6px',\r\n padding: '8px 12px 0',\r\n }}\r\n >\r\n {files.map((file, idx) => (\r\n <FilePreviewChip\r\n key={`${file.name}-${idx}`}\r\n file={file}\r\n onRemove={() => onRemove(idx)}\r\n primaryColor={primaryColor}\r\n />\r\n ))}\r\n </div>\r\n );\r\n};\r\n\r\n// ─── Single File Chip ────────────────────────────────────────────\r\n\r\ninterface FilePreviewChipProps {\r\n file: File;\r\n onRemove: () => void;\r\n primaryColor: string;\r\n}\r\n\r\nconst FilePreviewChip: React.FC<FilePreviewChipProps> = ({ file, onRemove, primaryColor }) => {\r\n const isImage = file.type.startsWith('image/');\r\n\r\n return (\r\n <div\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '6px',\r\n padding: '4px 8px',\r\n backgroundColor: '#F3F4F6',\r\n borderRadius: '8px',\r\n fontSize: '12px',\r\n maxWidth: '200px',\r\n }}\r\n >\r\n <span style={{ color: primaryColor, flexShrink: 0 }}>\r\n {isImage ? <ImageIcon size={14} /> : <FileIcon size={14} />}\r\n </span>\r\n <span\r\n style={{\r\n overflow: 'hidden',\r\n textOverflow: 'ellipsis',\r\n whiteSpace: 'nowrap',\r\n color: '#555',\r\n }}\r\n >\r\n {file.name}\r\n </span>\r\n <span style={{ color: '#999', fontSize: '11px', flexShrink: 0 }}>\r\n {formatSize(file.size)}\r\n </span>\r\n <button\r\n onClick={onRemove}\r\n style={{\r\n background: 'none',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '0',\r\n display: 'flex',\r\n color: '#999',\r\n flexShrink: 0,\r\n }}\r\n >\r\n <RemoveIcon size={14} />\r\n </button>\r\n </div>\r\n );\r\n};\r\n\r\n// ─── Utils ───────────────────────────────────────────────────────\r\n\r\nfunction formatSize(bytes: number): string {\r\n if (bytes < 1024) return `${bytes}B`;\r\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\r\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\r\n}\r\n","import React, { useState, useRef, useCallback } from 'react';\r\nimport type { CSSProperties } from 'react';\r\nimport type { FileUploadConfig } from '../types/config';\r\nimport { SendIcon, EmojiIcon } from './icons';\r\nimport { EmojiPicker } from './EmojiPicker';\r\nimport { FileUploadButton, FilePreviewList } from './FileUpload';\r\n\r\ninterface ChatInputProps {\r\n onSend: (text: string, files?: File[]) => void;\r\n placeholder?: string;\r\n primaryColor: string;\r\n isDark?: boolean;\r\n disabled?: boolean;\r\n styleOverride?: CSSProperties;\r\n enableEmoji?: boolean;\r\n fileUpload?: FileUploadConfig;\r\n onFileUpload?: (files: File[]) => void;\r\n}\r\n\r\nexport const ChatInput: React.FC<ChatInputProps> = ({\r\n onSend,\r\n placeholder = 'Type a message...',\r\n primaryColor,\r\n isDark = false,\r\n disabled,\r\n styleOverride,\r\n enableEmoji = false,\r\n fileUpload,\r\n onFileUpload,\r\n}) => {\r\n const [text, setText] = useState('');\r\n const [showEmoji, setShowEmoji] = useState(false);\r\n const [attachedFiles, setAttachedFiles] = useState<File[]>([]);\r\n const inputRef = useRef<HTMLTextAreaElement>(null);\r\n\r\n const handleSend = useCallback(() => {\r\n const trimmed = text.trim();\r\n if (!trimmed && attachedFiles.length === 0) return;\r\n onSend(trimmed, attachedFiles.length > 0 ? attachedFiles : undefined);\r\n setText('');\r\n setAttachedFiles([]);\r\n inputRef.current?.focus();\r\n }, [text, attachedFiles, onSend]);\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent) => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n handleSend();\r\n }\r\n };\r\n\r\n const handleEmojiSelect = (emoji: string) => {\r\n setText((prev) => prev + emoji);\r\n inputRef.current?.focus();\r\n };\r\n\r\n const handleFiles = (files: File[]) => {\r\n setAttachedFiles((prev) => [...prev, ...files]);\r\n onFileUpload?.(files);\r\n };\r\n\r\n const handleRemoveFile = (index: number) => {\r\n setAttachedFiles((prev) => prev.filter((_, i) => i !== index));\r\n };\r\n\r\n const hasContent = text.trim() || attachedFiles.length > 0;\r\n\r\n return (\r\n <div style={{ position: 'relative', ...styleOverride }}>\r\n {/* File preview above input */}\r\n {attachedFiles.length > 0 && (\r\n <FilePreviewList\r\n files={attachedFiles}\r\n onRemove={handleRemoveFile}\r\n primaryColor={primaryColor}\r\n />\r\n )}\r\n\r\n {/* Emoji picker */}\r\n {showEmoji && (\r\n <EmojiPicker\r\n onSelect={handleEmojiSelect}\r\n onClose={() => setShowEmoji(false)}\r\n primaryColor={primaryColor}\r\n />\r\n )}\r\n\r\n <div\r\n style={{\r\n display: 'flex',\r\n gap: '8px',\r\n alignItems: 'flex-end',\r\n background: isDark ? 'rgba(40, 40, 65, 0.5)' : 'rgba(245, 247, 252, 0.7)',\r\n borderRadius: '16px',\r\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.05)'}`,\r\n backdropFilter: 'blur(8px)',\r\n WebkitBackdropFilter: 'blur(8px)',\r\n padding: '6px 6px 6px 12px',\r\n }}\r\n >\r\n {/* Action buttons */}\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '2px', flexShrink: 0, paddingBottom: '2px' }}>\r\n {enableEmoji && (\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowEmoji(!showEmoji)}\r\n aria-label=\"Emoji\"\r\n title=\"Emoji\"\r\n style={{\r\n background: 'none',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px',\r\n display: 'flex',\r\n color: showEmoji ? primaryColor : (isDark ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.3)'),\r\n borderRadius: '8px',\r\n transition: 'all 0.2s ease',\r\n }}\r\n >\r\n <EmojiIcon size={20} />\r\n </button>\r\n )}\r\n\r\n {fileUpload?.enabled && (\r\n <FileUploadButton\r\n config={fileUpload}\r\n onFiles={handleFiles}\r\n selectedFiles={attachedFiles}\r\n onRemoveFile={handleRemoveFile}\r\n primaryColor={primaryColor}\r\n />\r\n )}\r\n </div>\r\n\r\n {/* Text Input */}\r\n <textarea\r\n ref={inputRef}\r\n value={text}\r\n onChange={(e) => setText(e.target.value)}\r\n onKeyDown={handleKeyDown}\r\n placeholder={placeholder}\r\n disabled={disabled}\r\n rows={1}\r\n style={{\r\n flex: 1,\r\n padding: '8px 2px',\r\n border: 'none',\r\n borderRadius: '12px',\r\n outline: 'none',\r\n resize: 'none',\r\n fontFamily: 'inherit',\r\n fontSize: '14px',\r\n lineHeight: '1.45',\r\n maxHeight: '100px',\r\n overflowY: 'auto',\r\n backgroundColor: 'transparent',\r\n color: isDark ? '#E0E0E0' : '#2D3436',\r\n letterSpacing: '0.01em',\r\n }}\r\n />\r\n\r\n {/* Send Button */}\r\n <button\r\n onClick={handleSend}\r\n disabled={disabled || !hasContent}\r\n aria-label=\"Send message\"\r\n style={{\r\n width: '36px',\r\n height: '36px',\r\n borderRadius: '12px',\r\n background: hasContent\r\n ? `linear-gradient(135deg, ${primaryColor} 0%, ${adjustColor(primaryColor, 30)} 100%)`\r\n : (isDark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)'),\r\n color: hasContent ? '#fff' : (isDark ? 'rgba(255,255,255,0.25)' : 'rgba(0,0,0,0.2)'),\r\n border: 'none',\r\n cursor: hasContent ? 'pointer' : 'default',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n flexShrink: 0,\r\n transition: 'all 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\r\n boxShadow: hasContent ? `0 4px 12px ${primaryColor}44` : 'none',\r\n }}\r\n >\r\n <SendIcon size={16} />\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nfunction adjustColor(hex: string, amount: number): string {\r\n const num = parseInt(hex.replace('#', ''), 16);\r\n const r = Math.min(255, ((num >> 16) & 0xff) + amount);\r\n const g = Math.min(255, ((num >> 8) & 0xff) + amount);\r\n const b = Math.min(255, (num & 0xff) + amount);\r\n return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;\r\n}\r\n","import React from 'react';\r\nimport type { BrandingConfig } from '../types/config';\r\n\r\ninterface BrandingProps {\r\n config: BrandingConfig;\r\n primaryColor: string;\r\n}\r\n\r\nexport const Branding: React.FC<BrandingProps> = ({ config, primaryColor }) => {\r\n if (config.showBranding === false) return null;\r\n\r\n const text = config.poweredBy ?? 'React ChatBot';\r\n\r\n return (\r\n <div\r\n style={{\r\n padding: '8px 16px',\r\n textAlign: 'center',\r\n fontSize: '11px',\r\n color: 'rgba(0,0,0,0.35)',\r\n background: 'rgba(250, 250, 255, 0.7)',\r\n backdropFilter: 'blur(8px)',\r\n WebkitBackdropFilter: 'blur(8px)',\r\n borderTop: '1px solid rgba(0,0,0,0.04)',\r\n flexShrink: 0,\r\n letterSpacing: '0.02em',\r\n }}\r\n >\r\n Powered by{' '}\r\n {config.poweredByUrl ? (\r\n <a\r\n href={config.poweredByUrl}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n style={{\r\n color: primaryColor,\r\n textDecoration: 'none',\r\n fontWeight: 600,\r\n transition: 'opacity 0.2s ease',\r\n }}\r\n >\r\n {text}\r\n </a>\r\n ) : (\r\n <span style={{ color: primaryColor, fontWeight: 600 }}>{text}</span>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import type { FlowConfig, FlowStep, ChatMessage, FlowQuickReply } from '../types';\r\n\r\nexport class FlowEngine {\r\n private steps: Map<string, FlowStep>;\r\n private startStep: string;\r\n private collectedData: Record<string, unknown> = {};\r\n private idCounter = 0;\r\n private uid = (): string => `msg_${Date.now()}_${++this.idCounter}`;\r\n private stepHistory: string[] = [];\r\n\r\n constructor(flow: FlowConfig) {\r\n this.startStep = flow.startStep;\r\n this.steps = new Map(flow.steps.map((s) => [s.id, s]));\r\n }\r\n\r\n getStartStepId(): string {\r\n return this.startStep;\r\n }\r\n\r\n getStep(id: string): FlowStep | undefined {\r\n return this.steps.get(id);\r\n }\r\n\r\n getData(): Record<string, unknown> {\r\n return { ...this.collectedData };\r\n }\r\n\r\n setData(key: string, value: unknown): void {\r\n this.collectedData[key] = value;\r\n }\r\n\r\n mergeData(data: Record<string, unknown>): void {\r\n Object.assign(this.collectedData, data);\r\n }\r\n\r\n /** Push a step onto the history stack (called when entering a step) */\r\n pushHistory(stepId: string): void {\r\n this.stepHistory.push(stepId);\r\n }\r\n\r\n /** Pop and return the previous step (go back) */\r\n popHistory(): string | undefined {\r\n // Remove current step\r\n this.stepHistory.pop();\r\n // Return previous step\r\n return this.stepHistory.pop();\r\n }\r\n\r\n /** Check if there's a previous step to go back to */\r\n canGoBack(): boolean {\r\n return this.stepHistory.length > 1;\r\n }\r\n\r\n /** Reset the engine to initial state */\r\n reset(): void {\r\n this.collectedData = {};\r\n this.stepHistory = [];\r\n }\r\n\r\n resolveNext(step: FlowStep, userValue?: string): string | undefined {\r\n // Conditional branching\r\n if (step.condition) {\r\n const { field, operator, value, then: thenStep, else: elseStep } = step.condition;\r\n const fieldVal = this.collectedData[field];\r\n const match = this.evaluate(fieldVal, operator, value);\r\n return match ? thenStep : elseStep;\r\n }\r\n\r\n // Quick-reply selected → find the reply's next\r\n if (userValue && step.quickReplies) {\r\n const reply = step.quickReplies.find((r) => r.value === userValue);\r\n if (reply?.next) return reply.next;\r\n }\r\n\r\n return step.next;\r\n }\r\n\r\n /** Returns true if the step expects a quick reply (not free text) */\r\n stepExpectsQuickReply(step: FlowStep): boolean {\r\n return !!(step.quickReplies && step.quickReplies.length > 0);\r\n }\r\n\r\n /** Returns true if the step expects a form submission */\r\n stepExpectsForm(step: FlowStep): boolean {\r\n return !!step.form;\r\n }\r\n\r\n /** Try to fuzzy-match user text against quick reply labels */\r\n matchQuickReply(step: FlowStep, text: string): FlowQuickReply | undefined {\r\n if (!step.quickReplies) return undefined;\r\n const lower = text.toLowerCase().trim();\r\n // Exact value match\r\n const exact = step.quickReplies.find((r) => r.value.toLowerCase() === lower);\r\n if (exact) return exact;\r\n // Exact label match \r\n const labelMatch = step.quickReplies.find((r) => r.label.toLowerCase().replace(/[^\\w\\s]/g, '').trim() === lower);\r\n if (labelMatch) return labelMatch;\r\n // Contains match\r\n const contains = step.quickReplies.find((r) => lower.includes(r.value.toLowerCase()) || r.label.toLowerCase().includes(lower));\r\n return contains;\r\n }\r\n\r\n buildMessages(step: FlowStep): ChatMessage[] {\r\n const messages: ChatMessage[] = [];\r\n\r\n const texts = step.messages ?? (step.message ? [step.message] : []);\r\n for (const text of texts) {\r\n messages.push({\r\n id: this.uid(),\r\n sender: 'bot',\r\n text,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n\r\n // Attach quick replies to the last message\r\n if (step.quickReplies && messages.length > 0) {\r\n messages[messages.length - 1]!.quickReplies = step.quickReplies;\r\n }\r\n\r\n // If step has a form, create a form message\r\n if (step.form) {\r\n messages.push({\r\n id: this.uid(),\r\n sender: 'bot',\r\n timestamp: Date.now(),\r\n form: step.form,\r\n });\r\n }\r\n\r\n // If step has a custom component, create a component message\r\n if (step.component) {\r\n messages.push({\r\n id: this.uid(),\r\n sender: 'bot',\r\n timestamp: Date.now(),\r\n component: step.component,\r\n });\r\n }\r\n\r\n return messages;\r\n }\r\n\r\n private evaluate(\r\n fieldVal: unknown,\r\n operator: string,\r\n value: string | number,\r\n ): boolean {\r\n switch (operator) {\r\n case 'eq':\r\n return String(fieldVal) === String(value);\r\n case 'neq':\r\n return String(fieldVal) !== String(value);\r\n case 'contains':\r\n return String(fieldVal).includes(String(value));\r\n case 'gt':\r\n return Number(fieldVal) > Number(value);\r\n case 'lt':\r\n return Number(fieldVal) < Number(value);\r\n default:\r\n return false;\r\n }\r\n }\r\n}\r\n\r\nlet globalIdCounter = 0;\r\nexport function createQuickReplyMessage(\r\n replies: FlowQuickReply[],\r\n): ChatMessage {\r\n return {\r\n id: `msg_${Date.now()}_${++globalIdCounter}`,\r\n sender: 'bot',\r\n timestamp: Date.now(),\r\n quickReplies: replies,\r\n };\r\n}\r\n","let counter = 0;\r\n\r\nexport const uid = (): string => `msg_${Date.now()}_${++counter}`;\r\n\r\nexport const classNames = (...args: (string | false | null | undefined)[]): string =>\r\n args.filter(Boolean).join(' ');\r\n\r\nexport const delay = (ms: number): Promise<void> =>\r\n new Promise((resolve) => setTimeout(resolve, ms));\r\n","import { useCallback, useRef, useEffect } from 'react';\r\nimport { useChatContext } from '../context/ChatContext';\r\nimport { FlowEngine } from '../engine/FlowEngine';\r\nimport { uid, delay } from '../utils/helpers';\r\nimport type { ChatMessage } from '../types';\r\nimport type { FlowActionResult, ActionContext } from '../types/config';\r\n\r\n/** Slash commands the user can type */\r\nconst COMMANDS: Record<string, string> = {\r\n '/help': 'Show available commands',\r\n '/cancel': 'Cancel current step and go back',\r\n '/back': 'Go back to the previous step',\r\n '/restart': 'Restart the conversation from the beginning',\r\n};\r\n\r\nexport function useChat() {\r\n const { state, dispatch, props } = useChatContext();\r\n const flowRef = useRef<FlowEngine | null>(null);\r\n const flowStartedRef = useRef(false);\r\n\r\n // Keep fresh references for use inside async callbacks (avoids stale closures)\r\n const stateRef = useRef(state);\r\n stateRef.current = state;\r\n const propsRef = useRef(props);\r\n propsRef.current = props;\r\n\r\n // Initialize flow engine\r\n useEffect(() => {\r\n if (props.flow) {\r\n flowRef.current = new FlowEngine(props.flow);\r\n flowStartedRef.current = false;\r\n }\r\n }, [props.flow]);\r\n\r\n const addBotMessage = useCallback(\r\n async (text: string, extras?: Partial<ChatMessage>) => {\r\n dispatch({ type: 'SET_TYPING', payload: true });\r\n await delay(400);\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'bot',\r\n text,\r\n timestamp: Date.now(),\r\n ...extras,\r\n };\r\n dispatch({ type: 'SET_TYPING', payload: false });\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n propsRef.current.callbacks?.onMessageReceive?.(msg);\r\n },\r\n [dispatch],\r\n );\r\n\r\n const addSystemMessage = useCallback(\r\n (text: string) => {\r\n dispatch({\r\n type: 'ADD_MESSAGE',\r\n payload: { id: uid(), sender: 'system', text, timestamp: Date.now() },\r\n });\r\n },\r\n [dispatch],\r\n );\r\n\r\n // Use a ref so processFlowStep can call itself recursively without stale closure\r\n const processFlowStepRef = useRef<(stepId: string) => Promise<void>>(async () => {});\r\n processFlowStepRef.current = async (stepId: string) => {\r\n const engine = flowRef.current;\r\n if (!engine) return;\r\n\r\n const step = engine.getStep(stepId);\r\n if (!step) return;\r\n\r\n // Track step history for /back navigation\r\n engine.pushHistory(stepId);\r\n\r\n dispatch({ type: 'SET_STEP', payload: stepId });\r\n dispatch({ type: 'SET_TYPING', payload: true });\r\n await delay(step.delay ?? 500);\r\n\r\n const messages = engine.buildMessages(step);\r\n dispatch({ type: 'SET_TYPING', payload: false });\r\n dispatch({ type: 'ADD_MESSAGES', payload: messages });\r\n\r\n messages.forEach((m) => propsRef.current.callbacks?.onMessageReceive?.(m));\r\n\r\n // Handle async action (API calls, verification, etc.)\r\n if (step.asyncAction) {\r\n const handler = propsRef.current.actionHandlers?.[step.asyncAction.handler];\r\n if (handler) {\r\n const statusMsgId = uid();\r\n // Show loading/status message\r\n dispatch({\r\n type: 'ADD_MESSAGE',\r\n payload: {\r\n id: statusMsgId,\r\n sender: 'bot',\r\n text: step.asyncAction.loadingMessage ?? 'Processing...',\r\n timestamp: Date.now(),\r\n },\r\n });\r\n\r\n const ctx: ActionContext = {\r\n updateMessage: (text: string) => {\r\n dispatch({ type: 'UPDATE_MESSAGE', payload: { id: statusMsgId, updates: { text } } });\r\n },\r\n };\r\n\r\n try {\r\n const result = await handler(engine.getData(), ctx);\r\n\r\n // Merge result data into collected data\r\n if (result.data) {\r\n engine.mergeData(result.data);\r\n dispatch({ type: 'SET_DATA', payload: result.data });\r\n }\r\n\r\n // Update status message with final text\r\n const finalMsg =\r\n result.message ??\r\n (result.status === 'success'\r\n ? (step.asyncAction.successMessage ?? 'Done!')\r\n : (step.asyncAction.errorMessage ?? 'Something went wrong.'));\r\n dispatch({ type: 'UPDATE_MESSAGE', payload: { id: statusMsgId, updates: { text: finalMsg } } });\r\n\r\n // Route based on result\r\n const nextStepId = resolveAsyncRoute(step, result);\r\n if (nextStepId) {\r\n await delay(600);\r\n processFlowStepRef.current(nextStepId);\r\n }\r\n } catch {\r\n dispatch({\r\n type: 'UPDATE_MESSAGE',\r\n payload: { id: statusMsgId, updates: { text: step.asyncAction.errorMessage ?? '❌ Something went wrong.' } },\r\n });\r\n if (step.asyncAction.onError) {\r\n await delay(600);\r\n processFlowStepRef.current(step.asyncAction.onError);\r\n }\r\n }\r\n return; // async action handles routing — don't auto-advance\r\n }\r\n }\r\n\r\n // If step has a custom component, wait for onComplete — don't auto-advance\r\n if (step.component && propsRef.current.components?.[step.component]) {\r\n return;\r\n }\r\n\r\n // Auto-advance if no user input required\r\n if (!step.quickReplies && !step.form && step.next) {\r\n await delay(300);\r\n processFlowStepRef.current(step.next);\r\n }\r\n };\r\n\r\n /** Determine next step from async action result */\r\n function resolveAsyncRoute(\r\n step: { asyncAction?: { onSuccess?: string; onError?: string; routes?: Record<string, string> }; next?: string },\r\n result: FlowActionResult,\r\n ): string | undefined {\r\n // 1. Explicit next from result\r\n if (result.next) return result.next;\r\n // 2. Routes map\r\n if (step.asyncAction?.routes?.[result.status]) return step.asyncAction.routes[result.status];\r\n // 3. Success/error defaults\r\n if (result.status === 'success' && step.asyncAction?.onSuccess) return step.asyncAction.onSuccess;\r\n if (result.status === 'error' && step.asyncAction?.onError) return step.asyncAction.onError;\r\n // 4. Fallback\r\n return step.next;\r\n }\r\n\r\n const processFlowStep = useCallback(\r\n (stepId: string) => processFlowStepRef.current(stepId),\r\n [],\r\n );\r\n\r\n /** Go back to the previous step */\r\n const goBack = useCallback(() => {\r\n const engine = flowRef.current;\r\n if (!engine || !engine.canGoBack()) {\r\n addSystemMessage('There is no previous step to go back to.');\r\n return;\r\n }\r\n dispatch({ type: 'CLEAR_QUICK_REPLIES' });\r\n const prevStepId = engine.popHistory();\r\n if (prevStepId) {\r\n processFlowStep(prevStepId);\r\n } else {\r\n addSystemMessage('There is no previous step to go back to.');\r\n }\r\n }, [dispatch, processFlowStep, addSystemMessage]);\r\n\r\n /** Restart the entire conversation */\r\n const restartSession = useCallback(() => {\r\n const engine = flowRef.current;\r\n if (engine) {\r\n engine.reset();\r\n }\r\n flowStartedRef.current = false;\r\n dispatch({ type: 'RESET_CHAT' });\r\n // Re-start the flow after reset\r\n if (engine) {\r\n flowStartedRef.current = true;\r\n processFlowStep(engine.getStartStepId());\r\n }\r\n }, [dispatch, processFlowStep]);\r\n\r\n /** Handle slash commands. Returns true if the text was a command. */\r\n const handleCommandRef = useRef<(text: string) => boolean>(() => false);\r\n handleCommandRef.current = (text: string): boolean => {\r\n const cmd = text.trim().toLowerCase();\r\n if (!cmd.startsWith('/')) return false;\r\n\r\n switch (cmd) {\r\n case '/help': {\r\n const lines = Object.entries(COMMANDS)\r\n .map(([k, v]) => `**${k}** — ${v}`)\r\n .join('\\n');\r\n addSystemMessage(`Available commands:\\n${lines}`);\r\n return true;\r\n }\r\n case '/cancel':\r\n case '/back': {\r\n goBack();\r\n return true;\r\n }\r\n case '/restart': {\r\n restartSession();\r\n return true;\r\n }\r\n default:\r\n addSystemMessage(`Unknown command: ${cmd}. Type /help for available commands.`);\r\n return true;\r\n }\r\n };\r\n\r\n /** Handle completion from a custom component rendered in a step */\r\n const handleComponentComplete = useCallback(\r\n (result?: FlowActionResult) => {\r\n const engine = flowRef.current;\r\n const currentStepId = stateRef.current.currentStepId;\r\n if (!engine || !currentStepId) return;\r\n\r\n const step = engine.getStep(currentStepId);\r\n if (!step) return;\r\n\r\n // Merge result data\r\n if (result?.data) {\r\n engine.mergeData(result.data);\r\n dispatch({ type: 'SET_DATA', payload: result.data });\r\n }\r\n\r\n // Show optional message\r\n if (result?.message) {\r\n dispatch({\r\n type: 'ADD_MESSAGE',\r\n payload: { id: uid(), sender: 'bot', text: result.message, timestamp: Date.now() },\r\n });\r\n }\r\n\r\n // Determine next step\r\n const nextStepId = result?.next ?? step.next;\r\n if (nextStepId) {\r\n processFlowStep(nextStepId);\r\n } else {\r\n propsRef.current.callbacks?.onFlowEnd?.(engine.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n },\r\n [dispatch, processFlowStep],\r\n );\r\n\r\n const sendMessage = useCallback(\r\n (text: string) => {\r\n // Check for slash commands first\r\n if (handleCommandRef.current(text)) return;\r\n\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'user',\r\n text,\r\n timestamp: Date.now(),\r\n };\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n propsRef.current.callbacks?.onMessageSend?.(msg);\r\n propsRef.current.callbacks?.onSubmit?.({ message: text });\r\n\r\n const currentStepId = stateRef.current.currentStepId;\r\n if (flowRef.current && currentStepId) {\r\n const step = flowRef.current.getStep(currentStepId);\r\n if (step) {\r\n // Block text input during async action or component steps\r\n if (step.asyncAction || step.component) {\r\n addBotMessage(\"Please wait, I'm still processing. You can type /back to go back.\");\r\n return;\r\n }\r\n // If this step has quick replies, try to match user text\r\n if (flowRef.current.stepExpectsQuickReply(step)) {\r\n const matched = flowRef.current.matchQuickReply(step, text);\r\n if (matched) {\r\n // User typed something matching a quick reply — handle it\r\n dispatch({ type: 'CLEAR_QUICK_REPLIES' });\r\n flowRef.current.setData(step.id, matched.value);\r\n const nextId = flowRef.current.resolveNext(step, matched.value);\r\n if (nextId) {\r\n processFlowStep(nextId);\r\n } else {\r\n propsRef.current.callbacks?.onFlowEnd?.(flowRef.current.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n } else {\r\n // User typed something that doesn't match — re-show options\r\n addBotMessage(\r\n \"I didn't quite get that. Please choose one of the options below:\",\r\n {\r\n quickReplies: step.quickReplies,\r\n },\r\n );\r\n }\r\n } else if (flowRef.current.stepExpectsForm(step)) {\r\n // Step has a form, nudge user\r\n addBotMessage(\"Please fill out the form above to continue.\");\r\n } else {\r\n // Normal text input step\r\n flowRef.current.setData(step.id, text);\r\n const nextId = flowRef.current.resolveNext(step, text);\r\n if (nextId) {\r\n processFlowStep(nextId);\r\n } else {\r\n // End of flow — acknowledge\r\n addBotMessage(\"Thanks for your message! Our team will get back to you soon. 🙌\");\r\n propsRef.current.callbacks?.onFlowEnd?.(flowRef.current.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n }\r\n }\r\n }\r\n },\r\n [dispatch, addBotMessage, processFlowStep],\r\n );\r\n\r\n const startFlow = useCallback(() => {\r\n const engine = flowRef.current;\r\n if (!engine || flowStartedRef.current) return;\r\n flowStartedRef.current = true;\r\n processFlowStep(engine.getStartStepId());\r\n }, [processFlowStep]);\r\n\r\n // Auto-start flow when all conditions are met\r\n useEffect(() => {\r\n if (\r\n props.flow &&\r\n !state.showWelcome &&\r\n state.isLoggedIn &&\r\n !flowStartedRef.current\r\n ) {\r\n startFlow();\r\n }\r\n }, [props.flow, state.showWelcome, state.isLoggedIn, startFlow]);\r\n\r\n const handleQuickReply = useCallback(\r\n (value: string, label: string) => {\r\n dispatch({ type: 'CLEAR_QUICK_REPLIES' });\r\n // Add user message\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'user',\r\n text: label,\r\n timestamp: Date.now(),\r\n };\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n propsRef.current.callbacks?.onQuickReply?.(value, label);\r\n\r\n // Continue flow\r\n const currentStepId = stateRef.current.currentStepId;\r\n if (flowRef.current && currentStepId) {\r\n const step = flowRef.current.getStep(currentStepId);\r\n if (step) {\r\n flowRef.current.setData(step.id, value);\r\n const nextId = flowRef.current.resolveNext(step, value);\r\n if (nextId) {\r\n processFlowStep(nextId);\r\n } else {\r\n propsRef.current.callbacks?.onFlowEnd?.(flowRef.current.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n }\r\n }\r\n },\r\n [dispatch, processFlowStep],\r\n );\r\n\r\n const handleFormSubmit = useCallback(\r\n async (formId: string, data: Record<string, unknown>) => {\r\n dispatch({ type: 'SET_DATA', payload: data });\r\n if (flowRef.current) {\r\n flowRef.current.mergeData(data);\r\n }\r\n\r\n // Summary message\r\n const summaryLines = Object.entries(data)\r\n .filter(([, v]) => v !== undefined && v !== '')\r\n .map(([k, v]) => `${k}: ${String(v)}`)\r\n .join('\\n');\r\n const msg: ChatMessage = {\r\n id: uid(),\r\n sender: 'user',\r\n text: summaryLines,\r\n formData: data,\r\n timestamp: Date.now(),\r\n };\r\n dispatch({ type: 'ADD_MESSAGE', payload: msg });\r\n\r\n await propsRef.current.callbacks?.onFormSubmit?.(formId, data);\r\n\r\n // Advance flow\r\n const currentStepId = stateRef.current.currentStepId;\r\n if (flowRef.current && currentStepId) {\r\n const step = flowRef.current.getStep(currentStepId);\r\n if (step) {\r\n const nextId = flowRef.current.resolveNext(step);\r\n if (nextId) {\r\n processFlowStep(nextId);\r\n } else {\r\n propsRef.current.callbacks?.onFlowEnd?.(flowRef.current.getData());\r\n dispatch({ type: 'SET_STEP', payload: null });\r\n }\r\n }\r\n }\r\n },\r\n [dispatch, processFlowStep],\r\n );\r\n\r\n const handleLogin = useCallback(\r\n async (data: Record<string, unknown>) => {\r\n await propsRef.current.callbacks?.onLogin?.(data);\r\n dispatch({ type: 'SET_LOGGED_IN', payload: true });\r\n },\r\n [dispatch],\r\n );\r\n\r\n const toggleChat = useCallback(() => {\r\n const willOpen = !stateRef.current.isOpen;\r\n dispatch({ type: 'TOGGLE_OPEN' });\r\n if (willOpen) {\r\n propsRef.current.callbacks?.onOpen?.();\r\n } else {\r\n propsRef.current.callbacks?.onClose?.();\r\n }\r\n }, [dispatch]);\r\n\r\n const dismissWelcome = useCallback(() => {\r\n dispatch({ type: 'DISMISS_WELCOME' });\r\n }, [dispatch]);\r\n\r\n return {\r\n state,\r\n sendMessage,\r\n addBotMessage,\r\n handleQuickReply,\r\n handleFormSubmit,\r\n handleLogin,\r\n toggleChat,\r\n dismissWelcome,\r\n startFlow,\r\n processFlowStep,\r\n goBack,\r\n restartSession,\r\n handleComponentComplete,\r\n };\r\n}\r\n","import React, { useCallback, useMemo } from 'react';\r\nimport type { CSSProperties } from 'react';\r\nimport type { ChatStyles } from '../styles/theme';\r\nimport type { ChatRenderContext } from '../types/config';\r\nimport { ChatHeader } from './ChatHeader';\r\nimport { WelcomeScreen } from './WelcomeScreen';\r\nimport { LoginScreen } from './LoginScreen';\r\nimport { MessageList } from './MessageList';\r\nimport { ChatInput } from './ChatInput';\r\nimport { Branding } from './Branding';\r\nimport { useChat } from '../hooks/useChat';\r\nimport { useChatContext } from '../context/ChatContext';\r\nimport { resolveTheme } from '../styles/theme';\r\nimport { uid } from '../utils/helpers';\r\nimport type { MessageAttachment } from '../types/message';\r\n\r\ninterface ChatWindowProps {\r\n styles: ChatStyles;\r\n position: 'bottom-right' | 'bottom-left';\r\n zIndex?: number;\r\n hidden?: boolean;\r\n}\r\n\r\nexport const ChatWindow: React.FC<ChatWindowProps> = ({ styles, position, zIndex, hidden }) => {\r\n const { props, dispatch } = useChatContext();\r\n const theme = resolveTheme(props.theme);\r\n const isDark = theme.mode === 'dark';\r\n const {\r\n state,\r\n sendMessage,\r\n handleQuickReply,\r\n handleFormSubmit,\r\n handleLogin,\r\n toggleChat,\r\n dismissWelcome,\r\n restartSession,\r\n handleComponentComplete,\r\n } = useChat();\r\n\r\n const posStyle: CSSProperties =\r\n position === 'bottom-left'\r\n ? { bottom: '96px', left: '24px' }\r\n : { bottom: '96px', right: '24px' };\r\n\r\n const handleSendWithFiles = useCallback(\r\n (text: string, files?: File[]) => {\r\n if (files && files.length > 0) {\r\n const attachments: MessageAttachment[] = files.map((f) => ({\r\n name: f.name,\r\n url: URL.createObjectURL(f),\r\n type: f.type,\r\n size: f.size,\r\n }));\r\n if (text) {\r\n dispatch({\r\n type: 'ADD_MESSAGE',\r\n payload: {\r\n id: uid(),\r\n sender: 'user',\r\n text,\r\n timestamp: Date.now(),\r\n attachments,\r\n },\r\n });\r\n sendMessage(text);\r\n } else {\r\n dispatch({\r\n type: 'ADD_MESSAGE',\r\n payload: {\r\n id: uid(),\r\n sender: 'user',\r\n timestamp: Date.now(),\r\n attachments,\r\n },\r\n });\r\n }\r\n props.callbacks?.onFileUpload?.(files);\r\n } else if (text) {\r\n sendMessage(text);\r\n }\r\n },\r\n [sendMessage, dispatch, props.callbacks],\r\n );\r\n\r\n // Build render context for custom components\r\n const renderCtx: ChatRenderContext = useMemo(\r\n () => ({\r\n currentStepId: state.currentStepId,\r\n isOpen: state.isOpen,\r\n messages: state.messages,\r\n collectedData: state.collectedData,\r\n toggleChat,\r\n restartSession,\r\n sendMessage,\r\n }),\r\n [state.currentStepId, state.isOpen, state.messages, state.collectedData, toggleChat, restartSession, sendMessage],\r\n );\r\n\r\n // Default header element\r\n const defaultHeader = (\r\n <ChatHeader\r\n config={props.header ?? { title: 'Chat with us' }}\r\n styles={styles}\r\n onClose={toggleChat}\r\n onRestart={restartSession}\r\n logo={props.branding?.logo}\r\n logoWidth={props.branding?.logoWidth}\r\n />\r\n );\r\n\r\n // Default input element\r\n const defaultInput = (\r\n <ChatInput\r\n onSend={handleSendWithFiles}\r\n placeholder={props.inputPlaceholder}\r\n primaryColor={theme.primaryColor}\r\n isDark={isDark}\r\n enableEmoji={props.enableEmoji}\r\n fileUpload={props.fileUpload}\r\n onFileUpload={props.callbacks?.onFileUpload}\r\n />\r\n );\r\n\r\n if (hidden) {\r\n // Keep component mounted (hooks alive) but invisible\r\n return <div style={{ display: 'none' }} />;\r\n }\r\n\r\n return (\r\n <div\r\n style={{\r\n ...styles.window,\r\n ...posStyle,\r\n ...(zIndex != null ? { zIndex } : {}),\r\n }}\r\n >\r\n {props.renderHeader ? props.renderHeader(renderCtx, defaultHeader) : defaultHeader}\r\n\r\n {/* Welcome Screen */}\r\n {state.showWelcome && props.welcomeScreen ? (\r\n <WelcomeScreen\r\n content={props.welcomeScreen}\r\n onDismiss={dismissWelcome}\r\n primaryColor={theme.primaryColor}\r\n />\r\n ) : /* Login Screen */\r\n !state.isLoggedIn && props.loginForm ? (\r\n <LoginScreen\r\n config={props.loginForm}\r\n onLogin={handleLogin}\r\n primaryColor={theme.primaryColor}\r\n />\r\n ) : (\r\n /* Chat Area */\r\n <>\r\n <MessageList\r\n messages={state.messages}\r\n isTyping={state.isTyping}\r\n styles={styles}\r\n primaryColor={theme.primaryColor}\r\n onQuickReply={handleQuickReply}\r\n onFormSubmit={handleFormSubmit}\r\n components={props.components}\r\n onComponentComplete={handleComponentComplete}\r\n collectedData={state.collectedData}\r\n currentStepId={state.currentStepId}\r\n />\r\n <div style={styles.inputArea}>\r\n {props.renderInput ? props.renderInput(renderCtx, defaultInput) : defaultInput}\r\n </div>\r\n {props.branding && (\r\n <Branding config={props.branding} primaryColor={theme.primaryColor} />\r\n )}\r\n </>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import type { ChatPlugin, PluginContext, ChatPluginEvent } from '../types/plugin';\r\nimport type { ChatMessage } from '../types/message';\r\n\r\n/**\r\n * PluginManager — Manages plugin lifecycle (Open/Closed Principle)\r\n * Core is closed for modification, open for extension via plugins.\r\n */\r\nexport class PluginManager {\r\n private plugins: ChatPlugin[] = [];\r\n private context: PluginContext | null = null;\r\n private eventHandlers = new Map<string, Set<(...args: unknown[]) => void>>();\r\n\r\n register(plugins: ChatPlugin[]): void {\r\n this.plugins = [...plugins];\r\n }\r\n\r\n setContext(ctx: Omit<PluginContext, 'on' | 'emit'>): void {\r\n this.context = {\r\n ...ctx,\r\n on: (event, handler) => this.on(event, handler),\r\n emit: (event, ...args) => this.emit(event, ...args),\r\n };\r\n }\r\n\r\n private on(event: string, handler: (...args: unknown[]) => void): void {\r\n if (!this.eventHandlers.has(event)) {\r\n this.eventHandlers.set(event, new Set());\r\n }\r\n this.eventHandlers.get(event)!.add(handler);\r\n }\r\n\r\n private emit(event: string, ...args: unknown[]): void {\r\n const handlers = this.eventHandlers.get(event);\r\n if (handlers) {\r\n handlers.forEach((handler) => handler(...args));\r\n }\r\n }\r\n\r\n async init(): Promise<void> {\r\n if (!this.context) return;\r\n for (const plugin of this.plugins) {\r\n try {\r\n await plugin.onInit?.(this.context);\r\n } catch (err) {\r\n console.error(`[Plugin:${plugin.name}] onInit error:`, err);\r\n }\r\n }\r\n }\r\n\r\n async onMessage(message: ChatMessage): Promise<ChatMessage> {\r\n if (!this.context) return message;\r\n let msg = message;\r\n for (const plugin of this.plugins) {\r\n try {\r\n const result = await plugin.onMessage?.(msg, this.context);\r\n if (result && typeof result === 'object' && 'id' in result) {\r\n msg = result;\r\n }\r\n } catch (err) {\r\n console.error(`[Plugin:${plugin.name}] onMessage error:`, err);\r\n }\r\n }\r\n this.dispatchEvent({ type: 'message', payload: msg, timestamp: Date.now() });\r\n return msg;\r\n }\r\n\r\n async onSubmit(data: Record<string, unknown>): Promise<void> {\r\n if (!this.context) return;\r\n for (const plugin of this.plugins) {\r\n try {\r\n await plugin.onSubmit?.(data, this.context);\r\n } catch (err) {\r\n console.error(`[Plugin:${plugin.name}] onSubmit error:`, err);\r\n }\r\n }\r\n this.dispatchEvent({ type: 'submit', payload: data, timestamp: Date.now() });\r\n }\r\n\r\n async destroy(): Promise<void> {\r\n if (!this.context) return;\r\n for (const plugin of this.plugins) {\r\n try {\r\n await plugin.onDestroy?.(this.context);\r\n } catch (err) {\r\n console.error(`[Plugin:${plugin.name}] onDestroy error:`, err);\r\n }\r\n }\r\n this.eventHandlers.clear();\r\n this.plugins = [];\r\n }\r\n\r\n private dispatchEvent(event: ChatPluginEvent): void {\r\n if (!this.context) return;\r\n for (const plugin of this.plugins) {\r\n try {\r\n plugin.onEvent?.(event, this.context);\r\n } catch (err) {\r\n console.error(`[Plugin:${plugin.name}] onEvent error:`, err);\r\n }\r\n }\r\n }\r\n}\r\n","import React, { useReducer, useEffect, useRef, useCallback } from 'react';\r\nimport type { ChatBotProps } from '../types';\r\nimport { ChatContext, chatReducer, initialState } from '../context/ChatContext';\r\nimport { resolveTheme, buildStyles, buildCSSVariables } from '../styles/theme';\r\nimport { Launcher } from './Launcher';\r\nimport { ChatWindow } from './ChatWindow';\r\nimport { PluginManager } from '../core/PluginManager';\r\nimport { uid } from '../utils/helpers';\r\n\r\nconst GLOBAL_STYLES = `\r\n@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');\r\n\r\n@keyframes cb-window-enter {\r\n 0% { opacity: 0; transform: translateY(16px) scale(0.96); }\r\n 100% { opacity: 1; transform: translateY(0) scale(1); }\r\n}\r\n\r\n@keyframes cb-launcher-pulse {\r\n 0%, 100% { box-shadow: 0 6px 24px rgba(108, 92, 231, 0.4), 0 2px 8px rgba(0,0,0,0.1); }\r\n 50% { box-shadow: 0 8px 32px rgba(108, 92, 231, 0.55), 0 4px 12px rgba(0,0,0,0.15); }\r\n}\r\n\r\n@keyframes cb-fade-in {\r\n 0% { opacity: 0; transform: translateY(6px); }\r\n 100% { opacity: 1; transform: translateY(0); }\r\n}\r\n\r\n@keyframes cb-typing-bounce {\r\n 0%, 80%, 100% { transform: scale(0.6); opacity: 0.3; }\r\n 40% { transform: scale(1); opacity: 1; }\r\n}\r\n\r\n@keyframes cb-slide-up {\r\n 0% { opacity: 0; transform: translateY(10px); }\r\n 100% { opacity: 1; transform: translateY(0); }\r\n}\r\n\r\n.cb-scrollbar::-webkit-scrollbar {\r\n width: 5px;\r\n}\r\n.cb-scrollbar::-webkit-scrollbar-track {\r\n background: transparent;\r\n}\r\n.cb-scrollbar::-webkit-scrollbar-thumb {\r\n background: rgba(108, 92, 231, 0.2);\r\n border-radius: 10px;\r\n}\r\n.cb-scrollbar::-webkit-scrollbar-thumb:hover {\r\n background: rgba(108, 92, 231, 0.35);\r\n}\r\n`;\r\n\r\n// Inject styles globally once per document, not per component instance\r\nlet globalStyleInjected = false;\r\nfunction ensureGlobalStyles() {\r\n if (globalStyleInjected) return;\r\n if (typeof document === 'undefined') return;\r\n if (document.querySelector('style[data-chatbot-styles]')) {\r\n globalStyleInjected = true;\r\n return;\r\n }\r\n const style = document.createElement('style');\r\n style.setAttribute('data-chatbot-styles', '');\r\n style.textContent = GLOBAL_STYLES;\r\n document.head.appendChild(style);\r\n globalStyleInjected = true;\r\n}\r\n\r\nexport const ChatBot: React.FC<ChatBotProps> = (props) => {\r\n const [state, dispatch] = useReducer(chatReducer, props, initialState);\r\n const theme = resolveTheme(props.theme);\r\n const styles = buildStyles(theme, props.style);\r\n const cssVars = buildCSSVariables(theme);\r\n const position = props.position ?? 'bottom-right';\r\n const showLauncher = props.showLauncher !== false;\r\n const pluginManagerRef = useRef<PluginManager | null>(null);\r\n\r\n // Use refs so plugin context always reads fresh state\r\n const stateRef = useRef(state);\r\n stateRef.current = state;\r\n\r\n // Inject global styles once\r\n useEffect(() => {\r\n ensureGlobalStyles();\r\n }, []);\r\n\r\n // Initialize plugins\r\n useEffect(() => {\r\n if (props.plugins && props.plugins.length > 0) {\r\n const pm = new PluginManager();\r\n pm.register(props.plugins);\r\n pm.setContext({\r\n sendMessage: (text) => {\r\n dispatch({\r\n type: 'ADD_MESSAGE',\r\n payload: { id: uid(), sender: 'user', text, timestamp: Date.now() },\r\n });\r\n },\r\n addBotMessage: (text) => {\r\n dispatch({\r\n type: 'ADD_MESSAGE',\r\n payload: { id: uid(), sender: 'bot', text, timestamp: Date.now() },\r\n });\r\n },\r\n getMessages: () => stateRef.current.messages,\r\n getData: () => stateRef.current.collectedData,\r\n setData: (key, value) => dispatch({ type: 'SET_DATA', payload: { [key]: value } }),\r\n });\r\n pm.init();\r\n pluginManagerRef.current = pm;\r\n\r\n return () => {\r\n pm.destroy();\r\n };\r\n }\r\n }, [props.plugins]);\r\n\r\n const handleToggle = useCallback(() => {\r\n const willOpen = !state.isOpen;\r\n dispatch({ type: 'TOGGLE_OPEN' });\r\n if (willOpen) props.callbacks?.onOpen?.();\r\n else props.callbacks?.onClose?.();\r\n }, [state.isOpen, props.callbacks]);\r\n\r\n return (\r\n <ChatContext.Provider value={{ state, dispatch, props }}>\r\n <div style={{ ...styles.root, ...cssVars as React.CSSProperties }} className={props.className}>\r\n <ChatWindow styles={styles} position={position} zIndex={props.zIndex} hidden={!state.isOpen} />\r\n {showLauncher && (\r\n <Launcher\r\n onClick={handleToggle}\r\n isOpen={state.isOpen}\r\n position={position}\r\n styles={styles}\r\n icon={props.launcherIcon}\r\n closeIcon={props.closeIcon}\r\n zIndex={props.zIndex}\r\n />\r\n )}\r\n </div>\r\n </ChatContext.Provider>\r\n );\r\n};\r\n","import type { ChatPlugin } from '../types/plugin';\r\n\r\n/**\r\n * Analytics Plugin — tracks message counts, form completions, drop-offs\r\n */\r\nexport function analyticsPlugin(options?: {\r\n onTrack?: (event: string, data?: unknown) => void;\r\n}): ChatPlugin {\r\n let messageCount = 0;\r\n let formSubmissions = 0;\r\n\r\n return {\r\n name: 'analytics',\r\n\r\n onInit(ctx) {\r\n messageCount = 0;\r\n formSubmissions = 0;\r\n options?.onTrack?.('chatbot:init');\r\n },\r\n\r\n onMessage(message, ctx) {\r\n messageCount++;\r\n options?.onTrack?.('chatbot:message', {\r\n sender: message.sender,\r\n messageCount,\r\n });\r\n },\r\n\r\n onSubmit(data, ctx) {\r\n formSubmissions++;\r\n options?.onTrack?.('chatbot:submit', {\r\n formSubmissions,\r\n fields: Object.keys(data),\r\n });\r\n },\r\n\r\n onDestroy() {\r\n options?.onTrack?.('chatbot:destroy', {\r\n totalMessages: messageCount,\r\n totalFormSubmissions: formSubmissions,\r\n });\r\n },\r\n };\r\n}\r\n","import type { ChatPlugin } from '../types/plugin';\r\n\r\n/**\r\n * Webhook Plugin — sends messages/submissions to an external endpoint\r\n */\r\nexport function webhookPlugin(options: {\r\n url: string;\r\n headers?: Record<string, string>;\r\n events?: ('message' | 'submit' | 'init' | 'destroy')[];\r\n}): ChatPlugin {\r\n const events = options.events ?? ['message', 'submit'];\r\n\r\n const send = async (type: string, payload: unknown) => {\r\n try {\r\n await fetch(options.url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...options.headers,\r\n },\r\n body: JSON.stringify({ type, payload, timestamp: Date.now() }),\r\n });\r\n } catch (err) {\r\n console.error(`[webhook] Failed to send ${type}:`, err);\r\n }\r\n };\r\n\r\n return {\r\n name: 'webhook',\r\n\r\n async onInit() {\r\n if (events.includes('init')) {\r\n await send('init', {});\r\n }\r\n },\r\n\r\n async onMessage(message) {\r\n if (events.includes('message')) {\r\n await send('message', message);\r\n }\r\n },\r\n\r\n async onSubmit(data) {\r\n if (events.includes('submit')) {\r\n await send('submit', data);\r\n }\r\n },\r\n\r\n async onDestroy() {\r\n if (events.includes('destroy')) {\r\n await send('destroy', {});\r\n }\r\n },\r\n };\r\n}\r\n","import type { ChatPlugin } from '../types/plugin';\r\n\r\n/**\r\n * Persistence Plugin — saves/restores chat history via localStorage\r\n */\r\nexport function persistencePlugin(options?: {\r\n storageKey?: string;\r\n storage?: 'local' | 'session';\r\n}): ChatPlugin {\r\n const key = options?.storageKey ?? 'chatbot_history';\r\n const store = options?.storage === 'session' ? sessionStorage : localStorage;\r\n\r\n return {\r\n name: 'persistence',\r\n\r\n onInit(ctx) {\r\n try {\r\n const saved = store.getItem(key);\r\n if (saved) {\r\n const messages = JSON.parse(saved);\r\n if (Array.isArray(messages)) {\r\n messages.forEach((msg) => {\r\n if (msg.sender === 'bot') {\r\n ctx.addBotMessage(msg.text);\r\n }\r\n // Skip non-bot messages — re-adding user messages as bot bubbles is incorrect\r\n });\r\n }\r\n }\r\n } catch {\r\n // ignore parse errors\r\n }\r\n },\r\n\r\n onMessage(message, ctx) {\r\n try {\r\n const messages = ctx.getMessages();\r\n store.setItem(key, JSON.stringify(messages.slice(-50)));\r\n } catch {\r\n // storage full or unavailable\r\n }\r\n },\r\n\r\n onDestroy() {\r\n // Optionally clear on destroy\r\n },\r\n };\r\n}\r\n"],"mappings":"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"}