@devicai/ui 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/cjs/api/client.js +46 -13
  2. package/dist/cjs/api/client.js.map +1 -1
  3. package/dist/cjs/components/AICommandBar/AICommandBar.js +314 -0
  4. package/dist/cjs/components/AICommandBar/AICommandBar.js.map +1 -0
  5. package/dist/cjs/components/AICommandBar/useAICommandBar.js +595 -0
  6. package/dist/cjs/components/AICommandBar/useAICommandBar.js.map +1 -0
  7. package/dist/cjs/components/ChatDrawer/ChatDrawer.js +200 -22
  8. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
  9. package/dist/cjs/components/ChatDrawer/ChatInput.js +12 -12
  10. package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -1
  11. package/dist/cjs/components/ChatDrawer/ChatMessages.js +137 -29
  12. package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -1
  13. package/dist/cjs/components/ChatDrawer/ConversationSelector.js +93 -0
  14. package/dist/cjs/components/ChatDrawer/ConversationSelector.js.map +1 -0
  15. package/dist/cjs/components/ChatDrawer/ErrorBoundary.js +25 -0
  16. package/dist/cjs/components/ChatDrawer/ErrorBoundary.js.map +1 -0
  17. package/dist/cjs/components/Feedback/FeedbackModal.js +87 -0
  18. package/dist/cjs/components/Feedback/FeedbackModal.js.map +1 -0
  19. package/dist/cjs/components/Feedback/MessageActions.js +74 -0
  20. package/dist/cjs/components/Feedback/MessageActions.js.map +1 -0
  21. package/dist/cjs/hooks/useDevicChat.js +54 -27
  22. package/dist/cjs/hooks/useDevicChat.js.map +1 -1
  23. package/dist/cjs/hooks/useModelInterface.js +6 -6
  24. package/dist/cjs/hooks/usePolling.js +64 -30
  25. package/dist/cjs/hooks/usePolling.js.map +1 -1
  26. package/dist/cjs/index.js +11 -0
  27. package/dist/cjs/index.js.map +1 -1
  28. package/dist/cjs/provider/DevicContext.js +4 -4
  29. package/dist/cjs/provider/DevicProvider.js +2 -2
  30. package/dist/cjs/styles.css +1 -1
  31. package/dist/esm/api/client.d.ts +19 -3
  32. package/dist/esm/api/client.js +46 -13
  33. package/dist/esm/api/client.js.map +1 -1
  34. package/dist/esm/api/types.d.ts +40 -0
  35. package/dist/esm/components/AICommandBar/AICommandBar.d.ts +22 -0
  36. package/dist/esm/components/AICommandBar/AICommandBar.js +312 -0
  37. package/dist/esm/components/AICommandBar/AICommandBar.js.map +1 -0
  38. package/dist/esm/components/AICommandBar/AICommandBar.types.d.ts +321 -0
  39. package/dist/esm/components/AICommandBar/index.d.ts +3 -0
  40. package/dist/esm/components/AICommandBar/useAICommandBar.d.ts +57 -0
  41. package/dist/esm/components/AICommandBar/useAICommandBar.js +592 -0
  42. package/dist/esm/components/AICommandBar/useAICommandBar.js.map +1 -0
  43. package/dist/esm/components/AutocompleteInput/AutocompleteInput.d.ts +4 -0
  44. package/dist/esm/components/AutocompleteInput/AutocompleteInput.types.d.ts +50 -0
  45. package/dist/esm/components/AutocompleteInput/index.d.ts +4 -0
  46. package/dist/esm/components/AutocompleteInput/useAutocomplete.d.ts +29 -0
  47. package/dist/esm/components/ChatDrawer/ChatDrawer.d.ts +4 -2
  48. package/dist/esm/components/ChatDrawer/ChatDrawer.js +191 -13
  49. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
  50. package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +155 -5
  51. package/dist/esm/components/ChatDrawer/ChatInput.d.ts +2 -1
  52. package/dist/esm/components/ChatDrawer/ChatInput.js +2 -2
  53. package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -1
  54. package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +2 -4
  55. package/dist/esm/components/ChatDrawer/ChatMessages.js +136 -28
  56. package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -1
  57. package/dist/esm/components/ChatDrawer/ConversationSelector.d.ts +2 -0
  58. package/dist/esm/components/ChatDrawer/ConversationSelector.js +91 -0
  59. package/dist/esm/components/ChatDrawer/ConversationSelector.js.map +1 -0
  60. package/dist/esm/components/ChatDrawer/ErrorBoundary.d.ts +16 -0
  61. package/dist/esm/components/ChatDrawer/ErrorBoundary.js +23 -0
  62. package/dist/esm/components/ChatDrawer/ErrorBoundary.js.map +1 -0
  63. package/dist/esm/components/ChatDrawer/index.d.ts +2 -1
  64. package/dist/esm/components/Feedback/Feedback.types.d.ts +50 -0
  65. package/dist/esm/components/Feedback/FeedbackModal.d.ts +5 -0
  66. package/dist/esm/components/Feedback/FeedbackModal.js +85 -0
  67. package/dist/esm/components/Feedback/FeedbackModal.js.map +1 -0
  68. package/dist/esm/components/Feedback/MessageActions.d.ts +5 -0
  69. package/dist/esm/components/Feedback/MessageActions.js +72 -0
  70. package/dist/esm/components/Feedback/MessageActions.js.map +1 -0
  71. package/dist/esm/components/Feedback/index.d.ts +3 -0
  72. package/dist/esm/hooks/useDevicChat.js +37 -10
  73. package/dist/esm/hooks/useDevicChat.js.map +1 -1
  74. package/dist/esm/hooks/usePolling.js +46 -12
  75. package/dist/esm/hooks/usePolling.js.map +1 -1
  76. package/dist/esm/index.d.ts +7 -3
  77. package/dist/esm/index.js +5 -0
  78. package/dist/esm/index.js.map +1 -1
  79. package/dist/esm/styles.css +1 -1
  80. package/package.json +10 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAICommandBar.js","sources":["../../../../../src/components/AICommandBar/useAICommandBar.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from 'react';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { usePolling } from '../../hooks/usePolling';\nimport { useModelInterface } from '../../hooks/useModelInterface';\nimport type {\n ChatMessage,\n ModelInterfaceTool,\n RealtimeChatHistory,\n} from '../../api/types';\nimport type {\n AICommandBarOptions,\n AICommandBarCommand,\n CommandBarResult,\n ToolCallSummary,\n ChatDrawerHandle,\n} from './AICommandBar.types';\n\nexport interface UseAICommandBarOptions {\n assistantId: string;\n apiKey?: string;\n baseUrl?: string;\n tenantId?: string;\n tenantMetadata?: Record<string, any>;\n options?: AICommandBarOptions;\n isVisible?: boolean;\n onVisibilityChange?: (visible: boolean) => void;\n onExecute?: 'openDrawer' | 'callback';\n chatDrawerRef?: React.RefObject<ChatDrawerHandle>;\n onResponse?: (response: CommandBarResult) => void;\n modelInterfaceTools?: ModelInterfaceTool[];\n onSubmit?: (message: string) => void;\n onToolCall?: (toolName: string, params: Record<string, any>) => void;\n onError?: (error: Error) => void;\n onOpen?: () => void;\n onClose?: () => void;\n}\n\nexport interface UseAICommandBarResult {\n // Visibility\n isVisible: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n\n // Input\n inputValue: string;\n setInputValue: (value: string) => void;\n inputRef: React.RefObject<HTMLInputElement>;\n focus: () => void;\n\n // Processing state\n isProcessing: boolean;\n toolCalls: ToolCallSummary[];\n currentToolSummary: string | null;\n\n // Result\n result: CommandBarResult | null;\n chatUid: string | null;\n error: Error | null;\n\n // History\n history: string[];\n historyIndex: number;\n showingHistory: boolean;\n setShowingHistory: (show: boolean) => void;\n\n // Commands\n showingCommands: boolean;\n filteredCommands: AICommandBarCommand[];\n selectedCommandIndex: number;\n selectCommand: (command: AICommandBarCommand) => void;\n\n // Actions\n submit: (message?: string) => Promise<void>;\n reset: () => void;\n handleKeyDown: (e: React.KeyboardEvent) => void;\n clearHistory: () => void;\n}\n\n/**\n * Parse a shortcut string like \"cmd+j\" into its components\n */\nfunction parseShortcut(shortcut: string): { key: string; modifiers: string[] } {\n const parts = shortcut.toLowerCase().split('+');\n const key = parts.pop() || '';\n const modifiers = parts;\n return { key, modifiers };\n}\n\n/**\n * Check if a keyboard event matches a shortcut string\n */\nfunction matchShortcut(event: KeyboardEvent, shortcut: string): boolean {\n const { key, modifiers } = parseShortcut(shortcut);\n\n const keyMatch = event.key.toLowerCase() === key;\n const cmdMatch = modifiers.includes('cmd') === (event.metaKey || event.ctrlKey);\n const shiftMatch = modifiers.includes('shift') === event.shiftKey;\n const altMatch = modifiers.includes('alt') === event.altKey;\n\n return keyMatch && cmdMatch && shiftMatch && altMatch;\n}\n\n/**\n * Format a shortcut string for display\n */\nexport function formatShortcut(shortcut: string): string {\n const isMac = typeof navigator !== 'undefined' && /Mac/.test(navigator.platform);\n return shortcut\n .replace(/cmd/gi, isMac ? '\\u2318' : 'Ctrl')\n .replace(/shift/gi, '\\u21E7')\n .replace(/alt/gi, isMac ? '\\u2325' : 'Alt')\n .replace(/\\+/g, ' ')\n .replace(/([a-z])/gi, (match) => match.toUpperCase());\n}\n\n/**\n * Format tool name to human-readable (fallback when no summary)\n */\nfunction formatToolName(toolName: string): string {\n // Convert snake_case or camelCase to human-readable\n return toolName\n .replace(/_/g, ' ')\n .replace(/([A-Z])/g, ' $1')\n .trim()\n .toLowerCase()\n .replace(/^./, (c) => c.toUpperCase());\n}\n\n/**\n * Hook for managing AICommandBar state and behavior\n */\nexport function useAICommandBar(options: UseAICommandBarOptions): UseAICommandBarResult {\n const {\n assistantId,\n apiKey: propsApiKey,\n baseUrl: propsBaseUrl,\n tenantId,\n tenantMetadata,\n options: barOptions = {},\n isVisible: controlledVisible,\n onVisibilityChange,\n onExecute = 'callback',\n chatDrawerRef,\n onResponse,\n modelInterfaceTools = [],\n onSubmit,\n onToolCall,\n onError,\n onOpen,\n onClose,\n } = options;\n\n const { shortcut } = barOptions;\n\n // Get context\n const context = useOptionalDevicContext();\n const apiKey = propsApiKey || context?.apiKey;\n const baseUrl = propsBaseUrl || context?.baseUrl || 'https://api.devic.ai';\n const resolvedTenantId = tenantId || context?.tenantId;\n const resolvedTenantMetadata = { ...context?.tenantMetadata, ...tenantMetadata };\n\n // Visibility state\n const [internalVisible, setInternalVisible] = useState(false);\n const isVisible = controlledVisible ?? internalVisible;\n\n // Input state\n const [inputValue, setInputValue] = useState('');\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Processing state\n const [isProcessing, setIsProcessing] = useState(false);\n const [toolCalls, setToolCalls] = useState<ToolCallSummary[]>([]);\n const [currentToolSummary, setCurrentToolSummary] = useState<string | null>(null);\n\n // Result state\n const [result, setResult] = useState<CommandBarResult | null>(null);\n const [chatUid, setChatUid] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n // Polling state\n const [shouldPoll, setShouldPoll] = useState(false);\n\n // History state\n const enableHistory = barOptions.enableHistory !== false; // default true\n const maxHistoryItems = barOptions.maxHistoryItems ?? 50;\n const historyStorageKey = barOptions.historyStorageKey ?? 'devic-command-bar-history';\n const showHistoryCommand = barOptions.showHistoryCommand !== false; // default true\n\n const [history, setHistory] = useState<string[]>(() => {\n if (!enableHistory || typeof window === 'undefined') return [];\n try {\n const stored = localStorage.getItem(historyStorageKey);\n return stored ? JSON.parse(stored) : [];\n } catch {\n return [];\n }\n });\n const [historyIndex, setHistoryIndex] = useState(-1);\n const [showingHistory, setShowingHistory] = useState(false);\n const [tempInput, setTempInput] = useState(''); // Store current input when navigating history\n\n // Commands state\n const commands = barOptions.commands ?? [];\n const [selectedCommandIndex, setSelectedCommandIndex] = useState(0);\n\n // Built-in history command\n const historyCommand: AICommandBarCommand = useMemo(() => ({\n keyword: 'history',\n description: 'Show command history',\n message: '', // Special handling\n }), []);\n\n // All available commands (user commands + built-in)\n const allCommands = useMemo(() => {\n const userCommands = commands;\n // Add history command if enabled and not overwritten\n if (showHistoryCommand && !userCommands.some(c => c.keyword === 'history')) {\n return [...userCommands, historyCommand];\n }\n return userCommands;\n }, [commands, showHistoryCommand, historyCommand]);\n\n // Detect if showing command suggestions\n const isCommandMode = inputValue.startsWith('/');\n const commandQuery = isCommandMode ? inputValue.slice(1).toLowerCase() : '';\n const showingCommands = isCommandMode && !isProcessing && !result;\n\n // Filter commands based on query\n const filteredCommands = useMemo(() => {\n if (!showingCommands) return [];\n if (commandQuery === '') return allCommands;\n return allCommands.filter(cmd =>\n cmd.keyword.toLowerCase().includes(commandQuery) ||\n cmd.description.toLowerCase().includes(commandQuery)\n );\n }, [showingCommands, commandQuery, allCommands]);\n\n // Reset command selection when filtered list changes\n useEffect(() => {\n setSelectedCommandIndex(0);\n }, [filteredCommands.length]);\n\n // Callback refs\n const onErrorRef = useRef(onError);\n const onResponseRef = useRef(onResponse);\n const onToolCallRef = useRef(onToolCall);\n const onSubmitRef = useRef(onSubmit);\n const onOpenRef = useRef(onOpen);\n const onCloseRef = useRef(onClose);\n\n useEffect(() => {\n onErrorRef.current = onError;\n onResponseRef.current = onResponse;\n onToolCallRef.current = onToolCall;\n onSubmitRef.current = onSubmit;\n onOpenRef.current = onOpen;\n onCloseRef.current = onClose;\n });\n\n // API client\n const clientRef = useRef<DevicApiClient | null>(null);\n if (!clientRef.current && apiKey) {\n clientRef.current = new DevicApiClient({ apiKey, baseUrl });\n }\n\n useEffect(() => {\n if (clientRef.current && apiKey) {\n clientRef.current.setConfig({ apiKey, baseUrl });\n }\n }, [apiKey, baseUrl]);\n\n // Model interface\n const {\n toolSchemas,\n handleToolCalls: executeToolCalls,\n extractPendingToolCalls,\n } = useModelInterface({\n tools: modelInterfaceTools,\n onToolExecute: onToolCall,\n });\n\n // Visibility controls\n const open = useCallback(() => {\n setInternalVisible(true);\n onVisibilityChange?.(true);\n onOpenRef.current?.();\n // Focus input after visibility change\n setTimeout(() => inputRef.current?.focus(), 50);\n }, [onVisibilityChange]);\n\n const close = useCallback(() => {\n setInternalVisible(false);\n onVisibilityChange?.(false);\n onCloseRef.current?.();\n }, [onVisibilityChange]);\n\n const toggle = useCallback(() => {\n if (isVisible) {\n close();\n } else {\n open();\n }\n }, [isVisible, open, close]);\n\n const focus = useCallback(() => {\n inputRef.current?.focus();\n }, []);\n\n // Save history to localStorage\n const saveHistory = useCallback((newHistory: string[]) => {\n if (!enableHistory || typeof window === 'undefined') return;\n try {\n localStorage.setItem(historyStorageKey, JSON.stringify(newHistory));\n } catch {\n // Ignore localStorage errors\n }\n }, [enableHistory, historyStorageKey]);\n\n // Add item to history\n const addToHistory = useCallback((message: string) => {\n if (!enableHistory || !message.trim() || message.startsWith('/')) return;\n\n setHistory(prev => {\n // Don't add duplicates at the top\n const filtered = prev.filter(item => item !== message);\n const newHistory = [message, ...filtered].slice(0, maxHistoryItems);\n saveHistory(newHistory);\n return newHistory;\n });\n setHistoryIndex(-1);\n }, [enableHistory, maxHistoryItems, saveHistory]);\n\n // Clear history\n const clearHistory = useCallback(() => {\n setHistory([]);\n setHistoryIndex(-1);\n if (enableHistory && typeof window !== 'undefined') {\n try {\n localStorage.removeItem(historyStorageKey);\n } catch {\n // Ignore\n }\n }\n }, [enableHistory, historyStorageKey]);\n\n // Navigate history\n const navigateHistory = useCallback((direction: 'up' | 'down') => {\n if (!enableHistory || history.length === 0) return;\n\n if (direction === 'up') {\n if (historyIndex === -1) {\n // Save current input before navigating\n setTempInput(inputValue);\n setHistoryIndex(0);\n setInputValue(history[0]);\n } else if (historyIndex < history.length - 1) {\n const newIndex = historyIndex + 1;\n setHistoryIndex(newIndex);\n setInputValue(history[newIndex]);\n }\n } else {\n if (historyIndex > 0) {\n const newIndex = historyIndex - 1;\n setHistoryIndex(newIndex);\n setInputValue(history[newIndex]);\n } else if (historyIndex === 0) {\n setHistoryIndex(-1);\n setInputValue(tempInput);\n }\n }\n }, [enableHistory, history, historyIndex, inputValue, tempInput]);\n\n // Ref to hold submit function (to avoid circular dependency)\n const submitRef = useRef<(message?: string) => Promise<void>>();\n\n // Select a command\n const selectCommand = useCallback((command: AICommandBarCommand) => {\n if (command.keyword === 'history') {\n // Special handling for history command\n setShowingHistory(true);\n setInputValue('');\n } else {\n // Send the command's message\n setInputValue('');\n submitRef.current?.(command.message);\n }\n }, []);\n\n // Navigate commands\n const navigateCommands = useCallback((direction: 'up' | 'down') => {\n if (filteredCommands.length === 0) return;\n\n if (direction === 'down') {\n setSelectedCommandIndex(prev =>\n prev < filteredCommands.length - 1 ? prev + 1 : 0\n );\n } else {\n setSelectedCommandIndex(prev =>\n prev > 0 ? prev - 1 : filteredCommands.length - 1\n );\n }\n }, [filteredCommands.length]);\n\n // Register keyboard shortcut\n useEffect(() => {\n if (!shortcut) return;\n\n const handler = (e: KeyboardEvent) => {\n if (matchShortcut(e, shortcut)) {\n e.preventDefault();\n toggle();\n }\n };\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [shortcut, toggle]);\n\n // Process tool calls from realtime data\n const processToolCalls = useCallback((messages: ChatMessage[]): ToolCallSummary[] => {\n const summaries: ToolCallSummary[] = [];\n const toolResponseMap = new Map<string, any>();\n\n // Collect tool responses\n for (const msg of messages) {\n if (msg.role === 'tool' && msg.tool_call_id) {\n toolResponseMap.set(msg.tool_call_id, msg.content);\n }\n }\n\n // Collect tool calls from assistant messages\n for (const msg of messages) {\n if (msg.role === 'assistant' && msg.tool_calls?.length) {\n for (const tc of msg.tool_calls) {\n const hasResponse = toolResponseMap.has(tc.id);\n let input: any;\n try {\n input = JSON.parse(tc.function.arguments || '{}');\n } catch {\n input = {};\n }\n\n // Use message summary if available, otherwise format tool name\n const summaryText = msg.summary || formatToolName(tc.function.name);\n\n summaries.push({\n id: tc.id,\n name: tc.function.name,\n status: hasResponse ? 'completed' : 'executing',\n summary: summaryText,\n input,\n output: toolResponseMap.get(tc.id),\n });\n }\n }\n }\n\n return summaries;\n }, []);\n\n // Handle pending client-side tool calls\n const handlePendingToolCalls = useCallback(\n async (data: RealtimeChatHistory) => {\n if (!clientRef.current || !chatUid) return;\n\n const pendingCalls = data.pendingToolCalls || extractPendingToolCalls(data.chatHistory);\n if (pendingCalls.length === 0) return;\n\n try {\n const responses = await executeToolCalls(pendingCalls);\n if (responses.length > 0) {\n await clientRef.current.sendToolResponses(assistantId, chatUid, responses);\n setShouldPoll(true);\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n onErrorRef.current?.(error);\n }\n },\n [chatUid, assistantId, executeToolCalls, extractPendingToolCalls]\n );\n\n // Polling\n usePolling(\n shouldPoll ? chatUid : null,\n async () => {\n if (!clientRef.current || !chatUid) {\n throw new Error('Cannot poll without client or chatUid');\n }\n return clientRef.current.getRealtimeHistory(assistantId, chatUid);\n },\n {\n interval: 1000,\n enabled: shouldPoll,\n stopStatuses: ['completed', 'error', 'waiting_for_tool_response'],\n onUpdate: async (data: RealtimeChatHistory) => {\n // Update tool calls display\n const summaries = processToolCalls(data.chatHistory);\n setToolCalls(summaries);\n\n // Update current tool summary\n // Prefer showing an executing tool, but fall back to the last tool (completed or not)\n if (summaries.length > 0) {\n const lastExecuting = summaries.filter(s => s.status === 'executing').pop();\n const lastTool = summaries[summaries.length - 1];\n setCurrentToolSummary(lastExecuting?.summary || lastTool?.summary || null);\n }\n\n // Handle client-side tool calls\n if (data.status === 'waiting_for_tool_response' || data.pendingToolCalls?.length) {\n await handlePendingToolCalls(data);\n }\n },\n onStop: (data) => {\n setShouldPoll(false);\n\n if (data?.status === 'error') {\n setIsProcessing(false);\n const err = new Error('Processing failed');\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n if (data?.status === 'completed') {\n setIsProcessing(false);\n\n // Extract final assistant message\n const assistantMessages = data.chatHistory.filter(m => m.role === 'assistant');\n const lastAssistantMessage = assistantMessages[assistantMessages.length - 1];\n\n if (lastAssistantMessage && chatUid) {\n const commandResult: CommandBarResult = {\n chatUid,\n message: lastAssistantMessage,\n toolCalls: processToolCalls(data.chatHistory),\n };\n\n setResult(commandResult);\n\n // Handle execution mode\n if (onExecute === 'openDrawer' && chatDrawerRef?.current) {\n chatDrawerRef.current.setChatUid(chatUid);\n chatDrawerRef.current.open();\n // Close and reset the command bar when handing off to drawer\n setResult(null);\n setToolCalls([]);\n setCurrentToolSummary(null);\n setInternalVisible(false);\n onVisibilityChange?.(false);\n onCloseRef.current?.();\n } else {\n onResponseRef.current?.(commandResult);\n }\n }\n }\n },\n onError: (err) => {\n setError(err);\n setIsProcessing(false);\n setShouldPoll(false);\n onErrorRef.current?.(err);\n },\n }\n );\n\n // Submit message\n const submit = useCallback(\n async (message?: string) => {\n const msg = message ?? inputValue;\n if (!msg.trim()) return;\n\n if (!clientRef.current) {\n const err = new Error('API client not configured. Please provide an API key.');\n setError(err);\n onErrorRef.current?.(err);\n return;\n }\n\n // Add to history before processing\n addToHistory(msg);\n\n // Clear input and start processing\n setInputValue('');\n setIsProcessing(true);\n setError(null);\n setResult(null);\n setToolCalls([]);\n setCurrentToolSummary(null);\n setShowingHistory(false);\n setHistoryIndex(-1);\n\n onSubmitRef.current?.(msg);\n\n try {\n const dto = {\n message: msg,\n chatUid: chatUid || undefined,\n metadata: resolvedTenantMetadata,\n tenantId: resolvedTenantId,\n ...(toolSchemas.length > 0 && { tools: toolSchemas }),\n };\n\n const response = await clientRef.current.sendMessageAsync(assistantId, dto);\n\n if (response.chatUid && response.chatUid !== chatUid) {\n setChatUid(response.chatUid);\n }\n\n setShouldPoll(true);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n setIsProcessing(false);\n onErrorRef.current?.(error);\n }\n },\n [inputValue, chatUid, assistantId, resolvedTenantId, resolvedTenantMetadata, toolSchemas, addToHistory]\n );\n\n // Update submit ref for use in selectCommand\n submitRef.current = submit;\n\n // Reset state\n const reset = useCallback(() => {\n setInputValue('');\n setIsProcessing(false);\n setToolCalls([]);\n setCurrentToolSummary(null);\n setResult(null);\n setChatUid(null);\n setError(null);\n setShouldPoll(false);\n }, []);\n\n // Handle keyboard events\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n // Handle Escape\n if (e.key === 'Escape') {\n e.preventDefault();\n if (showingHistory) {\n setShowingHistory(false);\n return;\n }\n if (showingCommands) {\n setInputValue('');\n return;\n }\n // Reset if there's a result or if processing\n if (result || isProcessing) {\n reset();\n }\n close();\n return;\n }\n\n // Handle arrow keys for commands\n if (showingCommands && filteredCommands.length > 0) {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n navigateCommands('down');\n return;\n }\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n navigateCommands('up');\n return;\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n const selectedCommand = filteredCommands[selectedCommandIndex];\n if (selectedCommand) {\n selectCommand(selectedCommand);\n }\n return;\n }\n if (e.key === 'Tab') {\n e.preventDefault();\n const selectedCommand = filteredCommands[selectedCommandIndex];\n if (selectedCommand) {\n setInputValue('/' + selectedCommand.keyword + ' ');\n }\n return;\n }\n }\n\n // Handle arrow keys for history (only when not in command mode)\n if (!showingCommands && !isProcessing) {\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n navigateHistory('up');\n return;\n }\n if (e.key === 'ArrowDown' && historyIndex >= 0) {\n e.preventDefault();\n navigateHistory('down');\n return;\n }\n }\n\n // Handle Enter to submit\n if (e.key === 'Enter' && !e.shiftKey && !isProcessing) {\n e.preventDefault();\n submit();\n }\n },\n [\n isProcessing,\n result,\n showingCommands,\n showingHistory,\n filteredCommands,\n selectedCommandIndex,\n historyIndex,\n submit,\n reset,\n close,\n navigateCommands,\n navigateHistory,\n selectCommand,\n ]\n );\n\n return {\n isVisible,\n open,\n close,\n toggle,\n inputValue,\n setInputValue,\n inputRef,\n focus,\n isProcessing,\n toolCalls,\n currentToolSummary,\n result,\n chatUid,\n error,\n history,\n historyIndex,\n showingHistory,\n setShowingHistory,\n showingCommands,\n filteredCommands,\n selectedCommandIndex,\n selectCommand,\n submit,\n reset,\n handleKeyDown,\n clearHistory,\n };\n}\n"],"names":["useOptionalDevicContext","useState","useRef","useMemo","useEffect","DevicApiClient","useModelInterface","useCallback","usePolling"],"mappings":"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"}
@@ -1,14 +1,18 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
4
+ var React = require('react');
5
5
  var useDevicChat = require('../../hooks/useDevicChat.js');
6
+ var DevicContext = require('../../provider/DevicContext.js');
7
+ var client = require('../../api/client.js');
6
8
  var ChatMessages = require('./ChatMessages.js');
7
9
  var ChatInput = require('./ChatInput.js');
10
+ var ConversationSelector = require('./ConversationSelector.js');
11
+ var ErrorBoundary = require('./ErrorBoundary.js');
8
12
 
9
13
  const DEFAULT_OPTIONS = {
10
14
  position: 'right',
11
- width: 400,
15
+ width: '100%',
12
16
  defaultOpen: false,
13
17
  color: '#1890ff',
14
18
  welcomeMessage: '',
@@ -18,8 +22,29 @@ const DEFAULT_OPTIONS = {
18
22
  maxFileSize: 10 * 1024 * 1024,
19
23
  inputPlaceholder: 'Type a message...',
20
24
  title: 'Chat',
25
+ showAvatar: false,
21
26
  showToolTimeline: true,
22
27
  zIndex: 1000,
28
+ borderRadius: 0,
29
+ resizable: false,
30
+ minWidth: 300,
31
+ maxWidth: 800,
32
+ style: {},
33
+ fontFamily: undefined,
34
+ backgroundColor: undefined,
35
+ textColor: undefined,
36
+ secondaryBackgroundColor: undefined,
37
+ borderColor: undefined,
38
+ userBubbleColor: undefined,
39
+ userBubbleTextColor: undefined,
40
+ assistantBubbleColor: undefined,
41
+ assistantBubbleTextColor: undefined,
42
+ sendButtonColor: undefined,
43
+ loadingIndicator: undefined,
44
+ sendButtonContent: undefined,
45
+ toolRenderers: undefined,
46
+ toolIcons: undefined,
47
+ showFeedback: true,
23
48
  };
24
49
  /**
25
50
  * Chat drawer component for Devic assistants
@@ -27,6 +52,7 @@ const DEFAULT_OPTIONS = {
27
52
  * @example
28
53
  * ```tsx
29
54
  * <ChatDrawer
55
+ * ref={drawerRef}
30
56
  * assistantId="my-assistant"
31
57
  * options={{
32
58
  * position: 'right',
@@ -45,12 +71,16 @@ const DEFAULT_OPTIONS = {
45
71
  * />
46
72
  * ```
47
73
  */
48
- function ChatDrawer({ assistantId, chatUid: initialChatUid, options = {}, enabledTools, modelInterfaceTools, tenantId, tenantMetadata, apiKey, baseUrl, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, onOpen, onClose, isOpen: controlledIsOpen, className, }) {
74
+ const ChatDrawer = React.forwardRef(function ChatDrawer(props, ref) {
75
+ return (jsxRuntime.jsx(ErrorBoundary.ChatDrawerErrorBoundary, { children: jsxRuntime.jsx(ChatDrawerInner, { ...props, forwardedRef: ref }) }));
76
+ });
77
+ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, enabledTools, modelInterfaceTools, tenantId, tenantMetadata, apiKey, baseUrl, onMessageSent, onMessageReceived, onToolCall, onError, onChatCreated, onOpen, onClose, isOpen: controlledIsOpen, className, mode = 'drawer', onConversationChange, forwardedRef, }) {
49
78
  // Merge options with defaults
50
- const mergedOptions = react.useMemo(() => ({ ...DEFAULT_OPTIONS, ...options }), [options]);
51
- // Drawer open state (can be controlled or uncontrolled)
52
- const [internalIsOpen, setInternalIsOpen] = react.useState(mergedOptions.defaultOpen);
53
- const isOpen = controlledIsOpen ?? internalIsOpen;
79
+ const mergedOptions = React.useMemo(() => ({ ...DEFAULT_OPTIONS, ...options }), [options]);
80
+ // Drawer open state (can be controlled or uncontrolled; inline mode is always open)
81
+ const [internalIsOpen, setInternalIsOpen] = React.useState(mergedOptions.defaultOpen);
82
+ const isInline = mode === 'inline';
83
+ const isOpen = isInline ? true : (controlledIsOpen ?? internalIsOpen);
54
84
  // Use chat hook
55
85
  const chat = useDevicChat.useDevicChat({
56
86
  assistantId,
@@ -67,43 +97,185 @@ function ChatDrawer({ assistantId, chatUid: initialChatUid, options = {}, enable
67
97
  onError,
68
98
  onChatCreated,
69
99
  });
100
+ // Fetch assistant avatar when showAvatar is enabled
101
+ const context = DevicContext.useOptionalDevicContext();
102
+ const resolvedApiKey = apiKey || context?.apiKey;
103
+ const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';
104
+ const [avatarUrl, setAvatarUrl] = React.useState(null);
105
+ const avatarFetchedRef = React.useRef(null);
106
+ React.useEffect(() => {
107
+ if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId)
108
+ return;
109
+ avatarFetchedRef.current = assistantId;
110
+ const client$1 = new client.DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });
111
+ client$1.getAssistant(assistantId).then((a) => {
112
+ if (a.imgUrl)
113
+ setAvatarUrl(a.imgUrl);
114
+ }).catch(() => { });
115
+ }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);
70
116
  // Handle open/close
71
- const handleOpen = react.useCallback(() => {
117
+ const handleOpen = React.useCallback(() => {
72
118
  setInternalIsOpen(true);
73
119
  onOpen?.();
74
120
  }, [onOpen]);
75
- const handleClose = react.useCallback(() => {
121
+ const handleClose = React.useCallback(() => {
76
122
  setInternalIsOpen(false);
77
123
  onClose?.();
78
124
  }, [onClose]);
125
+ const handleToggle = React.useCallback(() => {
126
+ setInternalIsOpen((prev) => !prev);
127
+ }, []);
128
+ // Expose handle for programmatic control
129
+ React.useImperativeHandle(forwardedRef, () => ({
130
+ open: handleOpen,
131
+ close: handleClose,
132
+ toggle: handleToggle,
133
+ setChatUid: (chatUid) => {
134
+ chat.loadChat(chatUid);
135
+ },
136
+ sendMessage: (message) => {
137
+ chat.sendMessage(message);
138
+ },
139
+ }), [handleOpen, handleClose, handleToggle, chat]);
79
140
  // Handle send message
80
- const handleSend = react.useCallback((message, files) => {
141
+ const handleSend = React.useCallback((message, files) => {
81
142
  chat.sendMessage(message, { files });
82
143
  }, [chat]);
144
+ // Handle conversation selection
145
+ const handleConversationSelect = React.useCallback((chatUid) => {
146
+ chat.loadChat(chatUid);
147
+ onConversationChange?.(chatUid);
148
+ }, [chat, onConversationChange]);
149
+ const handleNewChat = React.useCallback(() => {
150
+ chat.clearChat();
151
+ }, [chat]);
83
152
  // Handle suggested message click
84
- const handleSuggestedClick = react.useCallback((message) => {
153
+ const handleSuggestedClick = React.useCallback((message) => {
85
154
  chat.sendMessage(message);
86
155
  }, [chat]);
87
- // Apply CSS variable for primary color
88
- react.useEffect(() => {
89
- if (mergedOptions.color !== DEFAULT_OPTIONS.color) {
90
- document.documentElement.style.setProperty('--devic-primary', mergedOptions.color);
156
+ // Feedback state
157
+ const [feedbackMap, setFeedbackMap] = React.useState(new Map());
158
+ const feedbackClientRef = React.useRef(null);
159
+ // Initialize feedback client
160
+ React.useEffect(() => {
161
+ if (resolvedApiKey && !feedbackClientRef.current) {
162
+ feedbackClientRef.current = new client.DevicApiClient({
163
+ apiKey: resolvedApiKey,
164
+ baseUrl: resolvedBaseUrl,
165
+ });
166
+ }
167
+ }, [resolvedApiKey, resolvedBaseUrl]);
168
+ // Load existing feedback when chat changes
169
+ React.useEffect(() => {
170
+ if (!chat.chatUid || !feedbackClientRef.current || !mergedOptions.showFeedback)
171
+ return;
172
+ feedbackClientRef.current.getChatFeedback(assistantId, chat.chatUid)
173
+ .then((entries) => {
174
+ const newMap = new Map();
175
+ for (const entry of entries) {
176
+ if (entry.feedback !== undefined) {
177
+ newMap.set(entry.requestId, entry.feedback ? 'positive' : 'negative');
178
+ }
179
+ }
180
+ setFeedbackMap(newMap);
181
+ })
182
+ .catch(() => {
183
+ // Silently ignore feedback loading errors
184
+ });
185
+ }, [chat.chatUid, assistantId, mergedOptions.showFeedback]);
186
+ // Handle feedback submission
187
+ const handleFeedback = React.useCallback(async (messageId, positive, comment) => {
188
+ if (!chat.chatUid || !feedbackClientRef.current)
189
+ return;
190
+ try {
191
+ await feedbackClientRef.current.submitChatFeedback(assistantId, chat.chatUid, {
192
+ messageId,
193
+ feedback: positive,
194
+ feedbackComment: comment,
195
+ });
196
+ setFeedbackMap((prev) => {
197
+ const newMap = new Map(prev);
198
+ newMap.set(messageId, positive ? 'positive' : 'negative');
199
+ return newMap;
200
+ });
201
+ }
202
+ catch (err) {
203
+ console.error('Failed to submit feedback:', err);
204
+ throw err;
205
+ }
206
+ }, [chat.chatUid, assistantId]);
207
+ // Apply CSS variables for theming on the drawer element itself
208
+ // (must target the component root so they override the defaults defined on .devic-chat-drawer)
209
+ const drawerRef = React.useRef(null);
210
+ React.useEffect(() => {
211
+ const el = drawerRef.current;
212
+ if (!el)
213
+ return;
214
+ const vars = [
215
+ ['--devic-primary', mergedOptions.color !== DEFAULT_OPTIONS.color ? mergedOptions.color : undefined],
216
+ ['--devic-font-family', mergedOptions.fontFamily],
217
+ ['--devic-bg', mergedOptions.backgroundColor],
218
+ ['--devic-text', mergedOptions.textColor],
219
+ ['--devic-bg-secondary', mergedOptions.secondaryBackgroundColor],
220
+ ['--devic-border', mergedOptions.borderColor],
221
+ ['--devic-user-bubble', mergedOptions.userBubbleColor],
222
+ ['--devic-user-bubble-text', mergedOptions.userBubbleTextColor],
223
+ ['--devic-assistant-bubble', mergedOptions.assistantBubbleColor],
224
+ ['--devic-assistant-bubble-text', mergedOptions.assistantBubbleTextColor],
225
+ ['--devic-send-btn', mergedOptions.sendButtonColor],
226
+ ];
227
+ for (const [name, value] of vars) {
228
+ if (value) {
229
+ el.style.setProperty(name, value);
230
+ }
231
+ else {
232
+ el.style.removeProperty(name);
233
+ }
91
234
  }
92
- }, [mergedOptions.color]);
235
+ }, [mergedOptions.color, mergedOptions.fontFamily, mergedOptions.backgroundColor, mergedOptions.textColor, mergedOptions.secondaryBackgroundColor, mergedOptions.borderColor, mergedOptions.userBubbleColor, mergedOptions.userBubbleTextColor, mergedOptions.assistantBubbleColor, mergedOptions.assistantBubbleTextColor, mergedOptions.sendButtonColor]);
236
+ // Resizable drawer
237
+ const [resizedWidth, setResizedWidth] = React.useState(null);
238
+ const handleResizeStart = React.useCallback((e) => {
239
+ e.preventDefault();
240
+ const startX = e.clientX;
241
+ const startWidth = drawerRef.current?.offsetWidth ?? 0;
242
+ const isLeft = mergedOptions.position === 'left';
243
+ const onMove = (ev) => {
244
+ const delta = ev.clientX - startX;
245
+ const newWidth = startWidth + (isLeft ? delta : -delta);
246
+ const clamped = Math.min(mergedOptions.maxWidth, Math.max(mergedOptions.minWidth, newWidth));
247
+ setResizedWidth(clamped);
248
+ };
249
+ const onUp = () => {
250
+ document.removeEventListener('mousemove', onMove);
251
+ document.removeEventListener('mouseup', onUp);
252
+ };
253
+ document.addEventListener('mousemove', onMove);
254
+ document.addEventListener('mouseup', onUp);
255
+ }, [mergedOptions.position, mergedOptions.minWidth, mergedOptions.maxWidth]);
93
256
  // Build style object
94
- const drawerStyle = react.useMemo(() => ({
95
- width: mergedOptions.width,
257
+ const baseWidth = resizedWidth
258
+ ? `${resizedWidth}px`
259
+ : typeof mergedOptions.width === 'number'
260
+ ? `${mergedOptions.width}px`
261
+ : mergedOptions.width;
262
+ const drawerStyle = React.useMemo(() => ({
263
+ width: baseWidth,
96
264
  zIndex: mergedOptions.zIndex,
97
- }), [mergedOptions.width, mergedOptions.zIndex]);
98
- const overlayStyle = react.useMemo(() => ({
265
+ borderRadius: typeof mergedOptions.borderRadius === 'number'
266
+ ? `${mergedOptions.borderRadius}px`
267
+ : mergedOptions.borderRadius,
268
+ ...mergedOptions.style,
269
+ }), [baseWidth, mergedOptions.zIndex, mergedOptions.borderRadius, mergedOptions.style]);
270
+ const overlayStyle = React.useMemo(() => ({
99
271
  zIndex: mergedOptions.zIndex - 1,
100
272
  }), [mergedOptions.zIndex]);
101
- const triggerStyle = react.useMemo(() => ({
273
+ const triggerStyle = React.useMemo(() => ({
102
274
  zIndex: mergedOptions.zIndex - 1,
103
275
  [mergedOptions.position]: 20,
104
276
  bottom: 20,
105
277
  }), [mergedOptions.zIndex, mergedOptions.position]);
106
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "devic-drawer-overlay", "data-open": isOpen, style: overlayStyle, onClick: handleClose }), jsxRuntime.jsxs("div", { className: `devic-chat-drawer ${className || ''}`, "data-position": mergedOptions.position, "data-open": isOpen, style: drawerStyle, children: [jsxRuntime.jsxs("div", { className: "devic-drawer-header", children: [jsxRuntime.jsx("h2", { className: "devic-drawer-title", children: mergedOptions.title }), jsxRuntime.jsx("button", { className: "devic-drawer-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) })] }), chat.error && (jsxRuntime.jsx("div", { className: "devic-error", children: chat.error.message })), jsxRuntime.jsx(ChatMessages.ChatMessages, { messages: chat.messages, isLoading: chat.isLoading, welcomeMessage: mergedOptions.welcomeMessage, suggestedMessages: mergedOptions.suggestedMessages, onSuggestedClick: handleSuggestedClick, showToolTimeline: mergedOptions.showToolTimeline }), jsxRuntime.jsx(ChatInput.ChatInput, { onSend: handleSend, disabled: chat.isLoading, placeholder: mergedOptions.inputPlaceholder, enableFileUploads: mergedOptions.enableFileUploads, allowedFileTypes: mergedOptions.allowedFileTypes, maxFileSize: mergedOptions.maxFileSize })] }), !isOpen && (jsxRuntime.jsx("button", { className: "devic-trigger", onClick: handleOpen, style: triggerStyle, type: "button", "aria-label": "Open chat", children: jsxRuntime.jsx(ChatIcon, {}) }))] }));
278
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!isInline && (jsxRuntime.jsx("div", { className: "devic-drawer-overlay", "data-open": isOpen, style: overlayStyle, onClick: handleClose })), jsxRuntime.jsxs("div", { ref: drawerRef, className: `devic-chat-drawer ${className || ''}`, "data-position": mergedOptions.position, "data-open": isOpen, "data-mode": mode, style: drawerStyle, children: [mergedOptions.resizable && (jsxRuntime.jsx("div", { className: "devic-resize-handle", "data-position": mergedOptions.position, onMouseDown: handleResizeStart })), jsxRuntime.jsxs("div", { className: "devic-drawer-header", children: [avatarUrl && (jsxRuntime.jsx("img", { className: "devic-drawer-avatar", src: avatarUrl, alt: "", "aria-hidden": "true" })), jsxRuntime.jsx("h2", { className: "devic-drawer-title", children: mergedOptions.title }), jsxRuntime.jsx(ConversationSelector.ConversationSelector, { assistantId: assistantId, currentChatUid: chat.chatUid, onSelect: handleConversationSelect, onNewChat: handleNewChat, apiKey: apiKey, baseUrl: baseUrl, tenantId: tenantId }), jsxRuntime.jsxs("div", { className: "devic-drawer-header-actions", children: [jsxRuntime.jsx("button", { className: "devic-new-chat-btn", onClick: handleNewChat, type: "button", "aria-label": "New chat", title: "New chat", children: jsxRuntime.jsx(PlusIcon, {}) }), !isInline && (jsxRuntime.jsx("button", { className: "devic-drawer-close", onClick: handleClose, type: "button", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) }))] })] }), chat.error && (jsxRuntime.jsx("div", { className: "devic-error", children: chat.error.message })), jsxRuntime.jsx(ChatMessages.ChatMessages, { messages: chat.messages, allMessages: chat.messages, isLoading: chat.isLoading, welcomeMessage: mergedOptions.welcomeMessage, suggestedMessages: mergedOptions.suggestedMessages, onSuggestedClick: handleSuggestedClick, showToolTimeline: mergedOptions.showToolTimeline, toolRenderers: mergedOptions.toolRenderers, toolIcons: mergedOptions.toolIcons, loadingIndicator: mergedOptions.loadingIndicator, showFeedback: mergedOptions.showFeedback, feedbackMap: feedbackMap, onFeedback: handleFeedback }), jsxRuntime.jsx(ChatInput.ChatInput, { onSend: handleSend, disabled: chat.isLoading, placeholder: mergedOptions.inputPlaceholder, enableFileUploads: mergedOptions.enableFileUploads, allowedFileTypes: mergedOptions.allowedFileTypes, maxFileSize: mergedOptions.maxFileSize, sendButtonContent: mergedOptions.sendButtonContent })] }), !isInline && !isOpen && (jsxRuntime.jsx("button", { className: "devic-trigger", onClick: handleOpen, style: triggerStyle, type: "button", "aria-label": "Open chat", children: jsxRuntime.jsx(ChatIcon, {}) }))] }));
107
279
  }
108
280
  /**
109
281
  * Close icon
@@ -111,6 +283,12 @@ function ChatDrawer({ assistantId, chatUid: initialChatUid, options = {}, enable
111
283
  function CloseIcon() {
112
284
  return (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
113
285
  }
286
+ /**
287
+ * Plus icon for new chat button
288
+ */
289
+ function PlusIcon() {
290
+ return (jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), jsxRuntime.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
291
+ }
114
292
  /**
115
293
  * Chat icon for trigger button
116
294
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ChatDrawer.js","sources":["../../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport type { ChatDrawerProps, ChatDrawerOptions } from './ChatDrawer.types';\nimport './styles.css';\n\nconst DEFAULT_OPTIONS: Required<ChatDrawerOptions> = {\n position: 'right',\n width: 400,\n defaultOpen: false,\n color: '#1890ff',\n welcomeMessage: '',\n suggestedMessages: [],\n enableFileUploads: false,\n allowedFileTypes: { images: true, documents: true },\n maxFileSize: 10 * 1024 * 1024,\n inputPlaceholder: 'Type a message...',\n title: 'Chat',\n showToolTimeline: true,\n zIndex: 1000,\n};\n\n/**\n * Chat drawer component for Devic assistants\n *\n * @example\n * ```tsx\n * <ChatDrawer\n * assistantId=\"my-assistant\"\n * options={{\n * position: 'right',\n * width: 400,\n * welcomeMessage: 'Hello! How can I help you?',\n * suggestedMessages: ['Help me with...', 'Tell me about...'],\n * }}\n * modelInterfaceTools={[\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ]}\n * onMessageReceived={(msg) => console.log('Received:', msg)}\n * />\n * ```\n */\nexport function ChatDrawer({\n assistantId,\n chatUid: initialChatUid,\n options = {},\n enabledTools,\n modelInterfaceTools,\n tenantId,\n tenantMetadata,\n apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onOpen,\n onClose,\n isOpen: controlledIsOpen,\n className,\n}: ChatDrawerProps): JSX.Element {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({ ...DEFAULT_OPTIONS, ...options }),\n [options]\n );\n\n // Drawer open state (can be controlled or uncontrolled)\n const [internalIsOpen, setInternalIsOpen] = useState(mergedOptions.defaultOpen);\n const isOpen = controlledIsOpen ?? internalIsOpen;\n\n // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: initialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n });\n\n // Handle open/close\n const handleOpen = useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n // Handle send message\n const handleSend = useCallback(\n (message: string, files?: any[]) => {\n chat.sendMessage(message, { files });\n },\n [chat]\n );\n\n // Handle suggested message click\n const handleSuggestedClick = useCallback(\n (message: string) => {\n chat.sendMessage(message);\n },\n [chat]\n );\n\n // Apply CSS variable for primary color\n useEffect(() => {\n if (mergedOptions.color !== DEFAULT_OPTIONS.color) {\n document.documentElement.style.setProperty(\n '--devic-primary',\n mergedOptions.color\n );\n }\n }, [mergedOptions.color]);\n\n // Build style object\n const drawerStyle = useMemo(\n () => ({\n width: mergedOptions.width,\n zIndex: mergedOptions.zIndex,\n }),\n [mergedOptions.width, mergedOptions.zIndex]\n );\n\n const overlayStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n }),\n [mergedOptions.zIndex]\n );\n\n const triggerStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n [mergedOptions.position]: 20,\n bottom: 20,\n }),\n [mergedOptions.zIndex, mergedOptions.position]\n );\n\n return (\n <>\n {/* Overlay */}\n <div\n className=\"devic-drawer-overlay\"\n data-open={isOpen}\n style={overlayStyle}\n onClick={handleClose}\n />\n\n {/* Drawer */}\n <div\n className={`devic-chat-drawer ${className || ''}`}\n data-position={mergedOptions.position}\n data-open={isOpen}\n style={drawerStyle}\n >\n {/* Header */}\n <div className=\"devic-drawer-header\">\n <h2 className=\"devic-drawer-title\">{mergedOptions.title}</h2>\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n />\n\n {/* Input */}\n <ChatInput\n onSend={handleSend}\n disabled={chat.isLoading}\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n />\n </div>\n\n {/* Trigger button (when drawer is closed) */}\n {!isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["useMemo","useState","useDevicChat","useCallback","useEffect","_jsxs","_jsx","ChatMessages","ChatInput"],"mappings":";;;;;;;;AAOA,MAAM,eAAe,GAAgC;AACnD,IAAA,QAAQ,EAAE,OAAO;AACjB,IAAA,KAAK,EAAE,GAAG;AACV,IAAA,WAAW,EAAE,KAAK;AAClB,IAAA,KAAK,EAAE,SAAS;AAChB,IAAA,cAAc,EAAE,EAAE;AAClB,IAAA,iBAAiB,EAAE,EAAE;AACrB,IAAA,iBAAiB,EAAE,KAAK;IACxB,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;AACnD,IAAA,WAAW,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;AAC7B,IAAA,gBAAgB,EAAE,mBAAmB;AACrC,IAAA,KAAK,EAAE,MAAM;AACb,IAAA,gBAAgB,EAAE,IAAI;AACtB,IAAA,MAAM,EAAE,IAAI;CACb;AAED;;;;;;;;;;;;;;;;;;;;;;;AAuBG;AACG,SAAU,UAAU,CAAC,EACzB,WAAW,EACX,OAAO,EAAE,cAAc,EACvB,OAAO,GAAG,EAAE,EACZ,YAAY,EACZ,mBAAmB,EACnB,QAAQ,EACR,cAAc,EACd,MAAM,EACN,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,OAAO,EACP,aAAa,EACb,MAAM,EACN,OAAO,EACP,MAAM,EAAE,gBAAgB,EACxB,SAAS,GACO,EAAA;;IAEhB,MAAM,aAAa,GAAGA,aAAO,CAC3B,OAAO,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAC,EAC1C,CAAC,OAAO,CAAC,CACV;;AAGD,IAAA,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAGC,cAAQ,CAAC,aAAa,CAAC,WAAW,CAAC;AAC/E,IAAA,MAAM,MAAM,GAAG,gBAAgB,IAAI,cAAc;;IAGjD,MAAM,IAAI,GAAGC,yBAAY,CAAC;QACxB,WAAW;AACX,QAAA,OAAO,EAAE,cAAc;QACvB,MAAM;QACN,OAAO;QACP,QAAQ;QACR,cAAc;QACd,YAAY;QACZ,mBAAmB;QACnB,aAAa;QACb,iBAAiB;QACjB,UAAU;QACV,OAAO;QACP,aAAa;AACd,KAAA,CAAC;;AAGF,IAAA,MAAM,UAAU,GAAGC,iBAAW,CAAC,MAAK;QAClC,iBAAiB,CAAC,IAAI,CAAC;QACvB,MAAM,IAAI;AACZ,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;AAEZ,IAAA,MAAM,WAAW,GAAGA,iBAAW,CAAC,MAAK;QACnC,iBAAiB,CAAC,KAAK,CAAC;QACxB,OAAO,IAAI;AACb,IAAA,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;;IAGb,MAAM,UAAU,GAAGA,iBAAW,CAC5B,CAAC,OAAe,EAAE,KAAa,KAAI;QACjC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC;AACtC,IAAA,CAAC,EACD,CAAC,IAAI,CAAC,CACP;;AAGD,IAAA,MAAM,oBAAoB,GAAGA,iBAAW,CACtC,CAAC,OAAe,KAAI;AAClB,QAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AAC3B,IAAA,CAAC,EACD,CAAC,IAAI,CAAC,CACP;;IAGDC,eAAS,CAAC,MAAK;QACb,IAAI,aAAa,CAAC,KAAK,KAAK,eAAe,CAAC,KAAK,EAAE;AACjD,YAAA,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CACxC,iBAAiB,EACjB,aAAa,CAAC,KAAK,CACpB;QACH;AACF,IAAA,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;;AAGzB,IAAA,MAAM,WAAW,GAAGJ,aAAO,CACzB,OAAO;QACL,KAAK,EAAE,aAAa,CAAC,KAAK;QAC1B,MAAM,EAAE,aAAa,CAAC,MAAM;KAC7B,CAAC,EACF,CAAC,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAC5C;AAED,IAAA,MAAM,YAAY,GAAGA,aAAO,CAC1B,OAAO;AACL,QAAA,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC;AACjC,KAAA,CAAC,EACF,CAAC,aAAa,CAAC,MAAM,CAAC,CACvB;AAED,IAAA,MAAM,YAAY,GAAGA,aAAO,CAC1B,OAAO;AACL,QAAA,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC;AAChC,QAAA,CAAC,aAAa,CAAC,QAAQ,GAAG,EAAE;AAC5B,QAAA,MAAM,EAAE,EAAE;KACX,CAAC,EACF,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAC/C;IAED,QACEK,kDAEEC,cAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,sBAAsB,EAAA,WAAA,EACrB,MAAM,EACjB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,WAAW,GACpB,EAGFD,eAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,CAAA,kBAAA,EAAqB,SAAS,IAAI,EAAE,CAAA,CAAE,mBAClC,aAAa,CAAC,QAAQ,EAAA,WAAA,EAC1B,MAAM,EACjB,KAAK,EAAE,WAAW,EAAA,QAAA,EAAA,CAGlBA,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,qBAAqB,aAClCC,cAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAC,oBAAoB,EAAA,QAAA,EAAE,aAAa,CAAC,KAAK,EAAA,CAAM,EAC7DA,cAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,oBAAoB,EAC9B,OAAO,EAAE,WAAW,EACpB,IAAI,EAAC,QAAQ,EAAA,YAAA,EACF,YAAY,YAEvBA,cAAA,CAAC,SAAS,EAAA,EAAA,CAAG,EAAA,CACN,CAAA,EAAA,CACL,EAGL,IAAI,CAAC,KAAK,KACTA,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,aAAa,EAAA,QAAA,EACzB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAA,CACf,CACP,EAGDA,cAAA,CAACC,yBAAY,EAAA,EACX,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,SAAS,EAAE,IAAI,CAAC,SAAS,EACzB,cAAc,EAAE,aAAa,CAAC,cAAc,EAC5C,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,EAClD,gBAAgB,EAAE,oBAAoB,EACtC,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,GAChD,EAGFD,cAAA,CAACE,mBAAS,EAAA,EACR,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,IAAI,CAAC,SAAS,EACxB,WAAW,EAAE,aAAa,CAAC,gBAAgB,EAC3C,iBAAiB,EAAE,aAAa,CAAC,iBAAiB,EAClD,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,EAChD,WAAW,EAAE,aAAa,CAAC,WAAW,EAAA,CACtC,CAAA,EAAA,CACE,EAGL,CAAC,MAAM,KACNF,cAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAC,eAAe,EACzB,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,YAAY,EACnB,IAAI,EAAC,QAAQ,EAAA,YAAA,EACF,WAAW,YAEtBA,cAAA,CAAC,QAAQ,KAAG,EAAA,CACL,CACV,CAAA,EAAA,CACA;AAEP;AAEA;;AAEG;AACH,SAAS,SAAS,GAAA;AAChB,IAAA,QACED,eAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EAAA,QAAA,EAAA,CAEtBC,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EACtCA,cAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,CAAA,EAAA,CAClC;AAEV;AAEA;;AAEG;AACH,SAAS,QAAQ,GAAA;IACf,QACEA,cAAA,CAAA,KAAA,EAAA,EACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,cAAc,EAAA,QAAA,EAEnBA,cAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,yFAAyF,EAAA,CAAG,EAAA,CAChG;AAEV;;;;"}
1
+ {"version":3,"file":"ChatDrawer.js","sources":["../../../../../src/components/ChatDrawer/ChatDrawer.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { useDevicChat } from '../../hooks/useDevicChat';\nimport { useOptionalDevicContext } from '../../provider';\nimport { DevicApiClient } from '../../api/client';\nimport { ChatMessages } from './ChatMessages';\nimport { ChatInput } from './ChatInput';\nimport { ConversationSelector } from './ConversationSelector';\nimport { ChatDrawerErrorBoundary } from './ErrorBoundary';\nimport type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle } from './ChatDrawer.types';\nimport './styles.css';\n\nconst DEFAULT_OPTIONS: Required<ChatDrawerOptions> = {\n position: 'right',\n width: '100%',\n defaultOpen: false,\n color: '#1890ff',\n welcomeMessage: '',\n suggestedMessages: [],\n enableFileUploads: false,\n allowedFileTypes: { images: true, documents: true },\n maxFileSize: 10 * 1024 * 1024,\n inputPlaceholder: 'Type a message...',\n title: 'Chat',\n showAvatar: false,\n showToolTimeline: true,\n zIndex: 1000,\n borderRadius: 0,\n resizable: false,\n minWidth: 300,\n maxWidth: 800,\n style: {},\n fontFamily: undefined as any,\n backgroundColor: undefined as any,\n textColor: undefined as any,\n secondaryBackgroundColor: undefined as any,\n borderColor: undefined as any,\n userBubbleColor: undefined as any,\n userBubbleTextColor: undefined as any,\n assistantBubbleColor: undefined as any,\n assistantBubbleTextColor: undefined as any,\n sendButtonColor: undefined as any,\n loadingIndicator: undefined as any,\n sendButtonContent: undefined as any,\n toolRenderers: undefined as any,\n toolIcons: undefined as any,\n showFeedback: true,\n};\n\n/**\n * Chat drawer component for Devic assistants\n *\n * @example\n * ```tsx\n * <ChatDrawer\n * ref={drawerRef}\n * assistantId=\"my-assistant\"\n * options={{\n * position: 'right',\n * width: 400,\n * welcomeMessage: 'Hello! How can I help you?',\n * suggestedMessages: ['Help me with...', 'Tell me about...'],\n * }}\n * modelInterfaceTools={[\n * {\n * toolName: 'get_user_location',\n * schema: { ... },\n * callback: async () => ({ lat: 40.7, lng: -74.0 })\n * }\n * ]}\n * onMessageReceived={(msg) => console.log('Received:', msg)}\n * />\n * ```\n */\nexport const ChatDrawer = forwardRef<ChatDrawerHandle, ChatDrawerProps>(\n function ChatDrawer(props, ref) {\n return (\n <ChatDrawerErrorBoundary>\n <ChatDrawerInner {...props} forwardedRef={ref} />\n </ChatDrawerErrorBoundary>\n );\n }\n);\n\ninterface ChatDrawerInnerProps extends ChatDrawerProps {\n forwardedRef?: React.Ref<ChatDrawerHandle>;\n}\n\nfunction ChatDrawerInner({\n assistantId,\n chatUid: initialChatUid,\n options = {},\n enabledTools,\n modelInterfaceTools,\n tenantId,\n tenantMetadata,\n apiKey,\n baseUrl,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n onOpen,\n onClose,\n isOpen: controlledIsOpen,\n className,\n mode = 'drawer',\n onConversationChange,\n forwardedRef,\n}: ChatDrawerInnerProps): JSX.Element {\n // Merge options with defaults\n const mergedOptions = useMemo(\n () => ({ ...DEFAULT_OPTIONS, ...options }),\n [options]\n );\n\n // Drawer open state (can be controlled or uncontrolled; inline mode is always open)\n const [internalIsOpen, setInternalIsOpen] = useState(mergedOptions.defaultOpen);\n const isInline = mode === 'inline';\n const isOpen = isInline ? true : (controlledIsOpen ?? internalIsOpen);\n\n // Use chat hook\n const chat = useDevicChat({\n assistantId,\n chatUid: initialChatUid,\n apiKey,\n baseUrl,\n tenantId,\n tenantMetadata,\n enabledTools,\n modelInterfaceTools,\n onMessageSent,\n onMessageReceived,\n onToolCall,\n onError,\n onChatCreated,\n });\n\n // Fetch assistant avatar when showAvatar is enabled\n const context = useOptionalDevicContext();\n const resolvedApiKey = apiKey || context?.apiKey;\n const resolvedBaseUrl = baseUrl || context?.baseUrl || 'https://api.devic.ai';\n const [avatarUrl, setAvatarUrl] = useState<string | null>(null);\n const avatarFetchedRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!mergedOptions.showAvatar || !resolvedApiKey || avatarFetchedRef.current === assistantId) return;\n avatarFetchedRef.current = assistantId;\n const client = new DevicApiClient({ apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl });\n client.getAssistant(assistantId).then((a) => {\n if (a.imgUrl) setAvatarUrl(a.imgUrl);\n }).catch(() => {});\n }, [mergedOptions.showAvatar, assistantId, resolvedApiKey, resolvedBaseUrl]);\n\n // Handle open/close\n const handleOpen = useCallback(() => {\n setInternalIsOpen(true);\n onOpen?.();\n }, [onOpen]);\n\n const handleClose = useCallback(() => {\n setInternalIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleToggle = useCallback(() => {\n setInternalIsOpen((prev) => !prev);\n }, []);\n\n // Expose handle for programmatic control\n useImperativeHandle(forwardedRef, () => ({\n open: handleOpen,\n close: handleClose,\n toggle: handleToggle,\n setChatUid: (chatUid: string) => {\n chat.loadChat(chatUid);\n },\n sendMessage: (message: string) => {\n chat.sendMessage(message);\n },\n }), [handleOpen, handleClose, handleToggle, chat]);\n\n // Handle send message\n const handleSend = useCallback(\n (message: string, files?: any[]) => {\n chat.sendMessage(message, { files });\n },\n [chat]\n );\n\n // Handle conversation selection\n const handleConversationSelect = useCallback(\n (chatUid: string) => {\n chat.loadChat(chatUid);\n onConversationChange?.(chatUid);\n },\n [chat, onConversationChange]\n );\n\n const handleNewChat = useCallback(() => {\n chat.clearChat();\n }, [chat]);\n\n // Handle suggested message click\n const handleSuggestedClick = useCallback(\n (message: string) => {\n chat.sendMessage(message);\n },\n [chat]\n );\n\n // Feedback state\n const [feedbackMap, setFeedbackMap] = useState<Map<string, 'positive' | 'negative'>>(new Map());\n const feedbackClientRef = useRef<DevicApiClient | null>(null);\n\n // Initialize feedback client\n useEffect(() => {\n if (resolvedApiKey && !feedbackClientRef.current) {\n feedbackClientRef.current = new DevicApiClient({\n apiKey: resolvedApiKey,\n baseUrl: resolvedBaseUrl,\n });\n }\n }, [resolvedApiKey, resolvedBaseUrl]);\n\n // Load existing feedback when chat changes\n useEffect(() => {\n if (!chat.chatUid || !feedbackClientRef.current || !mergedOptions.showFeedback) return;\n\n feedbackClientRef.current.getChatFeedback(assistantId, chat.chatUid)\n .then((entries) => {\n const newMap = new Map<string, 'positive' | 'negative'>();\n for (const entry of entries) {\n if (entry.feedback !== undefined) {\n newMap.set(entry.requestId, entry.feedback ? 'positive' : 'negative');\n }\n }\n setFeedbackMap(newMap);\n })\n .catch(() => {\n // Silently ignore feedback loading errors\n });\n }, [chat.chatUid, assistantId, mergedOptions.showFeedback]);\n\n // Handle feedback submission\n const handleFeedback = useCallback(\n async (messageId: string, positive: boolean, comment?: string) => {\n if (!chat.chatUid || !feedbackClientRef.current) return;\n\n try {\n await feedbackClientRef.current.submitChatFeedback(assistantId, chat.chatUid, {\n messageId,\n feedback: positive,\n feedbackComment: comment,\n });\n\n setFeedbackMap((prev) => {\n const newMap = new Map(prev);\n newMap.set(messageId, positive ? 'positive' : 'negative');\n return newMap;\n });\n } catch (err) {\n console.error('Failed to submit feedback:', err);\n throw err;\n }\n },\n [chat.chatUid, assistantId]\n );\n\n // Apply CSS variables for theming on the drawer element itself\n // (must target the component root so they override the defaults defined on .devic-chat-drawer)\n const drawerRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = drawerRef.current;\n if (!el) return;\n const vars: [string, string | undefined][] = [\n ['--devic-primary', mergedOptions.color !== DEFAULT_OPTIONS.color ? mergedOptions.color : undefined],\n ['--devic-font-family', mergedOptions.fontFamily],\n ['--devic-bg', mergedOptions.backgroundColor],\n ['--devic-text', mergedOptions.textColor],\n ['--devic-bg-secondary', mergedOptions.secondaryBackgroundColor],\n ['--devic-border', mergedOptions.borderColor],\n ['--devic-user-bubble', mergedOptions.userBubbleColor],\n ['--devic-user-bubble-text', mergedOptions.userBubbleTextColor],\n ['--devic-assistant-bubble', mergedOptions.assistantBubbleColor],\n ['--devic-assistant-bubble-text', mergedOptions.assistantBubbleTextColor],\n ['--devic-send-btn', mergedOptions.sendButtonColor],\n ];\n for (const [name, value] of vars) {\n if (value) {\n el.style.setProperty(name, value);\n } else {\n el.style.removeProperty(name);\n }\n }\n }, [mergedOptions.color, mergedOptions.fontFamily, mergedOptions.backgroundColor, mergedOptions.textColor, mergedOptions.secondaryBackgroundColor, mergedOptions.borderColor, mergedOptions.userBubbleColor, mergedOptions.userBubbleTextColor, mergedOptions.assistantBubbleColor, mergedOptions.assistantBubbleTextColor, mergedOptions.sendButtonColor]);\n\n // Resizable drawer\n const [resizedWidth, setResizedWidth] = useState<number | null>(null);\n\n const handleResizeStart = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const startX = e.clientX;\n const startWidth = drawerRef.current?.offsetWidth ?? 0;\n const isLeft = mergedOptions.position === 'left';\n\n const onMove = (ev: MouseEvent) => {\n const delta = ev.clientX - startX;\n const newWidth = startWidth + (isLeft ? delta : -delta);\n const clamped = Math.min(\n mergedOptions.maxWidth,\n Math.max(mergedOptions.minWidth, newWidth)\n );\n setResizedWidth(clamped);\n };\n\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n },\n [mergedOptions.position, mergedOptions.minWidth, mergedOptions.maxWidth]\n );\n\n // Build style object\n const baseWidth = resizedWidth\n ? `${resizedWidth}px`\n : typeof mergedOptions.width === 'number'\n ? `${mergedOptions.width}px`\n : mergedOptions.width;\n\n const drawerStyle = useMemo(\n () => ({\n width: baseWidth,\n zIndex: mergedOptions.zIndex,\n borderRadius: typeof mergedOptions.borderRadius === 'number'\n ? `${mergedOptions.borderRadius}px`\n : mergedOptions.borderRadius,\n ...mergedOptions.style,\n }),\n [baseWidth, mergedOptions.zIndex, mergedOptions.borderRadius, mergedOptions.style]\n );\n\n const overlayStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n }),\n [mergedOptions.zIndex]\n );\n\n const triggerStyle = useMemo(\n () => ({\n zIndex: mergedOptions.zIndex - 1,\n [mergedOptions.position]: 20,\n bottom: 20,\n }),\n [mergedOptions.zIndex, mergedOptions.position]\n );\n\n return (\n <>\n {/* Overlay (drawer mode only) */}\n {!isInline && (\n <div\n className=\"devic-drawer-overlay\"\n data-open={isOpen}\n style={overlayStyle}\n onClick={handleClose}\n />\n )}\n\n {/* Drawer */}\n <div\n ref={drawerRef}\n className={`devic-chat-drawer ${className || ''}`}\n data-position={mergedOptions.position}\n data-open={isOpen}\n data-mode={mode}\n style={drawerStyle}\n >\n {/* Resize handle */}\n {mergedOptions.resizable && (\n <div\n className=\"devic-resize-handle\"\n data-position={mergedOptions.position}\n onMouseDown={handleResizeStart}\n />\n )}\n\n {/* Header */}\n <div className=\"devic-drawer-header\">\n {avatarUrl && (\n <img\n className=\"devic-drawer-avatar\"\n src={avatarUrl}\n alt=\"\"\n aria-hidden=\"true\"\n />\n )}\n <h2 className=\"devic-drawer-title\">{mergedOptions.title}</h2>\n <ConversationSelector\n assistantId={assistantId}\n currentChatUid={chat.chatUid}\n onSelect={handleConversationSelect}\n onNewChat={handleNewChat}\n apiKey={apiKey}\n baseUrl={baseUrl}\n tenantId={tenantId}\n />\n <div className=\"devic-drawer-header-actions\">\n <button\n className=\"devic-new-chat-btn\"\n onClick={handleNewChat}\n type=\"button\"\n aria-label=\"New chat\"\n title=\"New chat\"\n >\n <PlusIcon />\n </button>\n {!isInline && (\n <button\n className=\"devic-drawer-close\"\n onClick={handleClose}\n type=\"button\"\n aria-label=\"Close chat\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n\n {/* Error display */}\n {chat.error && (\n <div className=\"devic-error\">\n {chat.error.message}\n </div>\n )}\n\n {/* Messages */}\n <ChatMessages\n messages={chat.messages}\n allMessages={chat.messages}\n isLoading={chat.isLoading}\n welcomeMessage={mergedOptions.welcomeMessage}\n suggestedMessages={mergedOptions.suggestedMessages}\n onSuggestedClick={handleSuggestedClick}\n showToolTimeline={mergedOptions.showToolTimeline}\n toolRenderers={mergedOptions.toolRenderers}\n toolIcons={mergedOptions.toolIcons}\n loadingIndicator={mergedOptions.loadingIndicator}\n showFeedback={mergedOptions.showFeedback}\n feedbackMap={feedbackMap}\n onFeedback={handleFeedback}\n />\n\n {/* Input */}\n <ChatInput\n onSend={handleSend}\n disabled={chat.isLoading}\n placeholder={mergedOptions.inputPlaceholder}\n enableFileUploads={mergedOptions.enableFileUploads}\n allowedFileTypes={mergedOptions.allowedFileTypes}\n maxFileSize={mergedOptions.maxFileSize}\n sendButtonContent={mergedOptions.sendButtonContent}\n />\n </div>\n\n {/* Trigger button (drawer mode only, when closed) */}\n {!isInline && !isOpen && (\n <button\n className=\"devic-trigger\"\n onClick={handleOpen}\n style={triggerStyle}\n type=\"button\"\n aria-label=\"Open chat\"\n >\n <ChatIcon />\n </button>\n )}\n </>\n );\n}\n\n/**\n * Close icon\n */\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\n/**\n * Plus icon for new chat button\n */\nfunction PlusIcon(): JSX.Element {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n );\n}\n\n/**\n * Chat icon for trigger button\n */\nfunction ChatIcon(): JSX.Element {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z\" />\n </svg>\n );\n}\n"],"names":["forwardRef","_jsx","ChatDrawerErrorBoundary","useMemo","useState","useDevicChat","useOptionalDevicContext","useRef","useEffect","client","DevicApiClient","useCallback","useImperativeHandle","_jsxs","_Fragment","ConversationSelector","ChatMessages","ChatInput"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
4
+ var React = require('react');
5
5
 
6
6
  const FILE_TYPE_ACCEPT = {
7
7
  images: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
@@ -19,18 +19,18 @@ const FILE_TYPE_ACCEPT = {
19
19
  * Chat input component with file upload support
20
20
  */
21
21
  function ChatInput({ onSend, disabled = false, placeholder = 'Type a message...', enableFileUploads = false, allowedFileTypes = { images: true, documents: true }, maxFileSize = 10 * 1024 * 1024, // 10MB
22
- }) {
23
- const [message, setMessage] = react.useState('');
24
- const [files, setFiles] = react.useState([]);
25
- const textareaRef = react.useRef(null);
26
- const fileInputRef = react.useRef(null);
22
+ sendButtonContent, }) {
23
+ const [message, setMessage] = React.useState('');
24
+ const [files, setFiles] = React.useState([]);
25
+ const textareaRef = React.useRef(null);
26
+ const fileInputRef = React.useRef(null);
27
27
  // Calculate accepted file types
28
28
  const acceptedTypes = Object.entries(allowedFileTypes)
29
29
  .filter(([, enabled]) => enabled)
30
30
  .flatMap(([type]) => FILE_TYPE_ACCEPT[type] || [])
31
31
  .join(',');
32
32
  // Auto-resize textarea
33
- const handleInput = react.useCallback(() => {
33
+ const handleInput = React.useCallback(() => {
34
34
  const textarea = textareaRef.current;
35
35
  if (textarea) {
36
36
  textarea.style.height = 'auto';
@@ -38,7 +38,7 @@ function ChatInput({ onSend, disabled = false, placeholder = 'Type a message...'
38
38
  }
39
39
  }, []);
40
40
  // Handle send
41
- const handleSend = react.useCallback(() => {
41
+ const handleSend = React.useCallback(() => {
42
42
  const trimmedMessage = message.trim();
43
43
  if (!trimmedMessage && files.length === 0)
44
44
  return;
@@ -56,14 +56,14 @@ function ChatInput({ onSend, disabled = false, placeholder = 'Type a message...'
56
56
  }
57
57
  }, [message, files, onSend]);
58
58
  // Handle key press
59
- const handleKeyDown = react.useCallback((e) => {
59
+ const handleKeyDown = React.useCallback((e) => {
60
60
  if (e.key === 'Enter' && !e.shiftKey) {
61
61
  e.preventDefault();
62
62
  handleSend();
63
63
  }
64
64
  }, [handleSend]);
65
65
  // Handle file selection
66
- const handleFileSelect = react.useCallback((e) => {
66
+ const handleFileSelect = React.useCallback((e) => {
67
67
  const selectedFiles = Array.from(e.target.files || []);
68
68
  // Filter valid files
69
69
  const validFiles = selectedFiles.filter((file) => {
@@ -80,13 +80,13 @@ function ChatInput({ onSend, disabled = false, placeholder = 'Type a message...'
80
80
  }
81
81
  }, [maxFileSize]);
82
82
  // Remove file
83
- const removeFile = react.useCallback((index) => {
83
+ const removeFile = React.useCallback((index) => {
84
84
  setFiles((prev) => prev.filter((_, i) => i !== index));
85
85
  }, []);
86
86
  return (jsxRuntime.jsxs("div", { className: "devic-input-area", children: [files.length > 0 && (jsxRuntime.jsx("div", { className: "devic-file-preview", children: files.map((file, idx) => (jsxRuntime.jsxs("div", { className: "devic-file-preview-item", children: [jsxRuntime.jsx(FileIcon, {}), jsxRuntime.jsx("span", { children: file.name }), jsxRuntime.jsx("button", { className: "devic-file-remove", onClick: () => removeFile(idx), type: "button", children: "\u00D7" })] }, idx))) })), jsxRuntime.jsxs("div", { className: "devic-input-wrapper", children: [enableFileUploads && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: acceptedTypes, multiple: true, onChange: handleFileSelect, style: { display: 'none' } }), jsxRuntime.jsx("button", { className: "devic-input-btn", onClick: () => fileInputRef.current?.click(), disabled: disabled, type: "button", title: "Attach file", children: jsxRuntime.jsx(AttachIcon, {}) })] })), jsxRuntime.jsx("textarea", { ref: textareaRef, className: "devic-input", value: message, onChange: (e) => {
87
87
  setMessage(e.target.value);
88
88
  handleInput();
89
- }, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 1 }), jsxRuntime.jsx("button", { className: "devic-input-btn devic-send-btn", onClick: handleSend, disabled: disabled || (!message.trim() && files.length === 0), type: "button", title: "Send message", children: jsxRuntime.jsx(SendIcon, {}) })] })] }));
89
+ }, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 1 }), sendButtonContent ? (jsxRuntime.jsxs("div", { className: "devic-send-btn-wrapper", children: [jsxRuntime.jsx("div", { className: "devic-send-btn-custom", "aria-hidden": "true", children: sendButtonContent }), jsxRuntime.jsx("button", { className: "devic-send-btn-overlay", onClick: handleSend, disabled: disabled || (!message.trim() && files.length === 0), type: "button", title: "Send message" })] })) : (jsxRuntime.jsx("button", { className: "devic-input-btn devic-send-btn", onClick: handleSend, disabled: disabled || (!message.trim() && files.length === 0), type: "button", title: "Send message", children: jsxRuntime.jsx(SendIcon, {}) }))] })] }));
90
90
  }
91
91
  /**
92
92
  * Get file type category from MIME type