@devicai/ui 0.2.0 → 0.4.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 (54) hide show
  1. package/dist/cjs/api/client.js +31 -15
  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 +73 -5
  8. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
  9. package/dist/cjs/components/ChatDrawer/ChatMessages.js +5 -2
  10. package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -1
  11. package/dist/cjs/components/Feedback/FeedbackModal.js +87 -0
  12. package/dist/cjs/components/Feedback/FeedbackModal.js.map +1 -0
  13. package/dist/cjs/components/Feedback/MessageActions.js +74 -0
  14. package/dist/cjs/components/Feedback/MessageActions.js.map +1 -0
  15. package/dist/cjs/index.js +9 -0
  16. package/dist/cjs/index.js.map +1 -1
  17. package/dist/cjs/styles.css +1 -1
  18. package/dist/esm/api/client.d.ts +10 -2
  19. package/dist/esm/api/client.js +31 -15
  20. package/dist/esm/api/client.js.map +1 -1
  21. package/dist/esm/api/types.d.ts +25 -0
  22. package/dist/esm/components/AICommandBar/AICommandBar.d.ts +22 -0
  23. package/dist/esm/components/AICommandBar/AICommandBar.js +312 -0
  24. package/dist/esm/components/AICommandBar/AICommandBar.js.map +1 -0
  25. package/dist/esm/components/AICommandBar/AICommandBar.types.d.ts +321 -0
  26. package/dist/esm/components/AICommandBar/index.d.ts +3 -0
  27. package/dist/esm/components/AICommandBar/useAICommandBar.d.ts +57 -0
  28. package/dist/esm/components/AICommandBar/useAICommandBar.js +592 -0
  29. package/dist/esm/components/AICommandBar/useAICommandBar.js.map +1 -0
  30. package/dist/esm/components/AutocompleteInput/AutocompleteInput.d.ts +4 -0
  31. package/dist/esm/components/AutocompleteInput/AutocompleteInput.types.d.ts +50 -0
  32. package/dist/esm/components/AutocompleteInput/index.d.ts +4 -0
  33. package/dist/esm/components/AutocompleteInput/useAutocomplete.d.ts +29 -0
  34. package/dist/esm/components/ChatDrawer/ChatDrawer.d.ts +4 -2
  35. package/dist/esm/components/ChatDrawer/ChatDrawer.js +74 -6
  36. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
  37. package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +36 -0
  38. package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +2 -1
  39. package/dist/esm/components/ChatDrawer/ChatMessages.js +5 -2
  40. package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -1
  41. package/dist/esm/components/ChatDrawer/index.d.ts +1 -1
  42. package/dist/esm/components/Feedback/Feedback.types.d.ts +50 -0
  43. package/dist/esm/components/Feedback/FeedbackModal.d.ts +5 -0
  44. package/dist/esm/components/Feedback/FeedbackModal.js +85 -0
  45. package/dist/esm/components/Feedback/FeedbackModal.js.map +1 -0
  46. package/dist/esm/components/Feedback/MessageActions.d.ts +5 -0
  47. package/dist/esm/components/Feedback/MessageActions.js +72 -0
  48. package/dist/esm/components/Feedback/MessageActions.js.map +1 -0
  49. package/dist/esm/components/Feedback/index.d.ts +3 -0
  50. package/dist/esm/index.d.ts +6 -2
  51. package/dist/esm/index.js +4 -0
  52. package/dist/esm/index.js.map +1 -1
  53. package/dist/esm/styles.css +1 -1
  54. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ChatMessages.js","sources":["../../../../src/components/ChatDrawer/ChatMessages.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport Markdown from 'markdown-to-jsx';\nimport type { ChatMessagesProps } from './ChatDrawer.types';\nimport type { ChatMessage } from '../../api/types';\n\nconsole.log('[devic-ui] ChatMessages: DEV-BUILD-005');\n\n/**\n * Format timestamp to readable time\n */\nfunction formatTime(timestamp: number): string {\n return new Date(timestamp).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\n/**\n * Groups consecutive tool-call assistant messages (no text content)\n * into { toolMessages, isActive } groups, interleaved with regular messages.\n */\nfunction groupMessages(\n messages: ChatMessage[],\n isLoading: boolean\n): Array<\n | { type: 'message'; message: ChatMessage }\n | { type: 'toolGroup'; toolMessages: ChatMessage[]; isActive: boolean }\n> {\n const result: Array<\n | { type: 'message'; message: ChatMessage }\n | { type: 'toolGroup'; toolMessages: ChatMessage[]; isActive: boolean }\n > = [];\n\n let currentToolGroup: ChatMessage[] = [];\n\n const flushToolGroup = (isActive: boolean) => {\n if (currentToolGroup.length > 0) {\n result.push({ type: 'toolGroup', toolMessages: [...currentToolGroup], isActive });\n currentToolGroup = [];\n }\n };\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n\n // Skip developer and tool response messages\n if (msg.role === 'developer' || msg.role === 'tool') {\n continue;\n }\n\n const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;\n const hasText = !!msg.content?.message;\n const hasFiles = msg.content?.files && msg.content.files.length > 0;\n\n if (hasToolCalls) {\n // If message has both text and tool_calls, show text first\n if (hasText || hasFiles) {\n // Flush any prior tool group before inserting the text message\n const remainingMeaningful = messages.slice(i + 1).some(\n (m) => (m.role === 'assistant' && m.content?.message) || m.role === 'user'\n );\n flushToolGroup(isLoading && !remainingMeaningful);\n result.push({ type: 'message', message: msg });\n }\n // Always accumulate the tool call\n currentToolGroup.push(msg);\n } else {\n // Regular message → flush any accumulated tool group first\n const remainingMeaningful = messages.slice(i).some(\n (m) => (m.role === 'assistant' && m.content?.message) || m.role === 'user'\n );\n flushToolGroup(isLoading && !remainingMeaningful);\n\n if (hasText || hasFiles) {\n result.push({ type: 'message', message: msg });\n }\n }\n }\n\n // Flush remaining tool group (is active if still loading)\n flushToolGroup(isLoading);\n\n return result;\n}\n\n/**\n * Collapsible tool actions group\n */\nfunction ToolGroup({\n toolMessages,\n isActive,\n allMessages,\n toolRenderers,\n toolIcons,\n}: {\n toolMessages: ChatMessage[];\n isActive: boolean;\n allMessages?: ChatMessage[];\n toolRenderers?: Record<string, (input: any, output: any) => React.ReactNode>;\n toolIcons?: Record<string, React.ReactNode>;\n}): JSX.Element {\n const [isCollapsed, setIsCollapsed] = useState(false);\n const shouldCollapse = toolMessages.length > 3 && !isActive;\n\n // Auto-collapse when transitioning from active to completed\n const wasActiveRef = useRef(isActive);\n useEffect(() => {\n if (wasActiveRef.current && !isActive && toolMessages.length > 3) {\n setIsCollapsed(true);\n }\n wasActiveRef.current = isActive;\n }, [isActive, toolMessages.length]);\n\n const lastIndex = toolMessages.length - 1;\n\n const renderToolItem = (msg: ChatMessage, opts: { active?: boolean; showSpinner?: boolean }) => {\n const toolCall = msg.tool_calls?.[0];\n const toolName = toolCall?.function?.name;\n const summaryText = msg.summary || toolName || (opts.active ? 'Processing...' : 'Completed');\n\n // Custom renderer for completed tools\n if (!opts.active && toolName && toolRenderers?.[toolName] && allMessages) {\n const toolResponse = allMessages.find(\n (m) => m.role === 'tool' && m.tool_call_id === toolCall!.id\n );\n let input: any = {};\n try { input = JSON.parse(toolCall!.function.arguments); } catch {}\n const output = toolResponse?.content?.data ?? toolResponse?.content?.message;\n return toolRenderers[toolName](input, output);\n }\n\n const icon = opts.showSpinner\n ? <SpinnerIcon />\n : (toolName && toolIcons?.[toolName]) || <ToolDoneIcon />;\n\n return (\n <>\n <span className=\"devic-tool-activity-icon\">{icon}</span>\n <span className={`devic-tool-activity-text ${opts.active ? 'devic-glow-text' : ''}`}>\n {summaryText}\n </span>\n </>\n );\n };\n\n // If active, show all items; last one gets the glow treatment\n if (isActive) {\n return (\n <div className=\"devic-tool-group\">\n {toolMessages.map((msg, idx) => {\n const isLast = idx === lastIndex;\n return (\n <div\n key={msg.uid}\n className={`devic-tool-activity ${isLast ? 'devic-tool-activity--active' : ''}`}\n >\n {renderToolItem(msg, { active: isLast, showSpinner: isLast })}\n </div>\n );\n })}\n </div>\n );\n }\n\n // Completed: collapse if > 3 actions\n if (shouldCollapse && isCollapsed) {\n return (\n <div className=\"devic-tool-group\">\n <button\n className=\"devic-tool-collapse-btn\"\n onClick={() => setIsCollapsed(false)}\n type=\"button\"\n >\n <ToolDoneIcon />\n <span>{toolMessages.length} actions</span>\n <ChevronDownIcon />\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"devic-tool-group\">\n {shouldCollapse && (\n <button\n className=\"devic-tool-collapse-btn\"\n onClick={() => setIsCollapsed(true)}\n type=\"button\"\n >\n <span>{toolMessages.length} actions</span>\n <ChevronUpIcon />\n </button>\n )}\n <div className=\"devic-tool-group-items\" data-expanded=\"true\">\n {toolMessages.map((msg) => (\n <div key={msg.uid} className=\"devic-tool-activity\">\n {renderToolItem(msg, {})}\n </div>\n ))}\n </div>\n </div>\n );\n}\n\n/**\n * Messages list component\n */\nconst markdownOverrides = {\n table: {\n component: ({ children, ...props }: any) =>\n React.createElement('div', { className: 'markdown-table' },\n React.createElement('table', props, children)\n ),\n },\n};\n\nexport function ChatMessages({\n messages,\n allMessages,\n isLoading,\n welcomeMessage,\n suggestedMessages,\n onSuggestedClick,\n toolRenderers,\n toolIcons,\n loadingIndicator,\n}: ChatMessagesProps): JSX.Element {\n const containerRef = useRef<HTMLDivElement>(null);\n const prevLengthRef = useRef(messages.length);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n if (containerRef.current) {\n containerRef.current.scrollTop = containerRef.current.scrollHeight;\n }\n prevLengthRef.current = messages.length;\n }, [messages.length, isLoading]);\n\n const grouped = groupMessages(messages, isLoading);\n\n // Show loading dots only if there's no active tool group at the end\n const lastGroup = grouped[grouped.length - 1];\n const showLoadingDots = isLoading && !(lastGroup?.type === 'toolGroup' && lastGroup.isActive);\n\n return (\n <div className=\"devic-messages-container\" ref={containerRef}>\n {messages.length === 0 && !isLoading && (welcomeMessage || suggestedMessages?.length) && (\n <div className=\"devic-welcome\">\n {welcomeMessage && (\n <p className=\"devic-welcome-text\">{welcomeMessage}</p>\n )}\n {suggestedMessages && suggestedMessages.length > 0 && (\n <div className=\"devic-suggested-messages\">\n {suggestedMessages.map((msg, idx) => (\n <button\n key={idx}\n className=\"devic-suggested-btn\"\n onClick={() => onSuggestedClick?.(msg)}\n >\n {msg}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {grouped.map((item) => {\n if (item.type === 'toolGroup') {\n return (\n <ToolGroup\n key={`tg-${item.toolMessages[0].uid}`}\n toolMessages={item.toolMessages}\n isActive={item.isActive}\n allMessages={allMessages}\n toolRenderers={toolRenderers}\n toolIcons={toolIcons}\n />\n );\n }\n\n const message = item.message;\n const messageText = message.content?.message;\n const hasFiles = message.content?.files && message.content.files.length > 0;\n\n return (\n <div\n key={message.uid}\n className=\"devic-message\"\n data-role={message.role}\n >\n <div className=\"devic-message-bubble\">\n {messageText && message.role === 'assistant' ? (\n <Markdown options={{ overrides: markdownOverrides }}>{messageText}</Markdown>\n ) : (\n messageText\n )}\n {hasFiles && (\n <div className=\"devic-message-files\">\n {message.content!.files!.map((file, fileIdx) => (\n <div key={fileIdx} className=\"devic-message-file\">\n <FileIcon />\n <span>{file.name}</span>\n </div>\n ))}\n </div>\n )}\n </div>\n <span className=\"devic-message-time\">\n {formatTime(message.timestamp)}\n </span>\n </div>\n );\n })}\n\n {showLoadingDots && (\n loadingIndicator ? (\n <div className=\"devic-loading\">{loadingIndicator}</div>\n ) : (\n <div className=\"devic-loading\">\n <span className=\"devic-loading-dot\"></span>\n <span className=\"devic-loading-dot\"></span>\n <span className=\"devic-loading-dot\"></span>\n </div>\n )\n )}\n </div>\n );\n}\n\n/* ── Icons ── */\n\nfunction SpinnerIcon(): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n className=\"devic-spinner\"\n >\n <path d=\"M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83\" />\n </svg>\n );\n}\n\nfunction ToolDoneIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20,6 9,17 4,12\" />\n </svg>\n );\n}\n\nfunction ChevronDownIcon(): JSX.Element {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6,9 12,15 18,9\" />\n </svg>\n );\n}\n\nfunction ChevronUpIcon(): JSX.Element {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6,15 12,9 18,15\" />\n </svg>\n );\n}\n\nfunction FileIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14,2 14,8 20,8\" />\n </svg>\n );\n}\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"ChatMessages.js","sources":["../../../../src/components/ChatDrawer/ChatMessages.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport Markdown from 'markdown-to-jsx';\nimport { MessageActions } from '../Feedback';\nimport type { ChatMessagesProps } from './ChatDrawer.types';\nimport type { ChatMessage } from '../../api/types';\nimport type { FeedbackState } from '../Feedback';\nimport '../Feedback/Feedback.css';\n\nconsole.log('[devic-ui] ChatMessages: DEV-BUILD-005');\n\n/**\n * Format timestamp to readable time\n */\nfunction formatTime(timestamp: number): string {\n return new Date(timestamp).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\n/**\n * Groups consecutive tool-call assistant messages (no text content)\n * into { toolMessages, isActive } groups, interleaved with regular messages.\n */\nfunction groupMessages(\n messages: ChatMessage[],\n isLoading: boolean\n): Array<\n | { type: 'message'; message: ChatMessage }\n | { type: 'toolGroup'; toolMessages: ChatMessage[]; isActive: boolean }\n> {\n const result: Array<\n | { type: 'message'; message: ChatMessage }\n | { type: 'toolGroup'; toolMessages: ChatMessage[]; isActive: boolean }\n > = [];\n\n let currentToolGroup: ChatMessage[] = [];\n\n const flushToolGroup = (isActive: boolean) => {\n if (currentToolGroup.length > 0) {\n result.push({ type: 'toolGroup', toolMessages: [...currentToolGroup], isActive });\n currentToolGroup = [];\n }\n };\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n\n // Skip developer and tool response messages\n if (msg.role === 'developer' || msg.role === 'tool') {\n continue;\n }\n\n const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;\n const hasText = !!msg.content?.message;\n const hasFiles = msg.content?.files && msg.content.files.length > 0;\n\n if (hasToolCalls) {\n // If message has both text and tool_calls, show text first\n if (hasText || hasFiles) {\n // Flush any prior tool group before inserting the text message\n const remainingMeaningful = messages.slice(i + 1).some(\n (m) => (m.role === 'assistant' && m.content?.message) || m.role === 'user'\n );\n flushToolGroup(isLoading && !remainingMeaningful);\n result.push({ type: 'message', message: msg });\n }\n // Always accumulate the tool call\n currentToolGroup.push(msg);\n } else {\n // Regular message → flush any accumulated tool group first\n const remainingMeaningful = messages.slice(i).some(\n (m) => (m.role === 'assistant' && m.content?.message) || m.role === 'user'\n );\n flushToolGroup(isLoading && !remainingMeaningful);\n\n if (hasText || hasFiles) {\n result.push({ type: 'message', message: msg });\n }\n }\n }\n\n // Flush remaining tool group (is active if still loading)\n flushToolGroup(isLoading);\n\n return result;\n}\n\n/**\n * Collapsible tool actions group\n */\nfunction ToolGroup({\n toolMessages,\n isActive,\n allMessages,\n toolRenderers,\n toolIcons,\n}: {\n toolMessages: ChatMessage[];\n isActive: boolean;\n allMessages?: ChatMessage[];\n toolRenderers?: Record<string, (input: any, output: any) => React.ReactNode>;\n toolIcons?: Record<string, React.ReactNode>;\n}): JSX.Element {\n const [isCollapsed, setIsCollapsed] = useState(false);\n const shouldCollapse = toolMessages.length > 3 && !isActive;\n\n // Auto-collapse when transitioning from active to completed\n const wasActiveRef = useRef(isActive);\n useEffect(() => {\n if (wasActiveRef.current && !isActive && toolMessages.length > 3) {\n setIsCollapsed(true);\n }\n wasActiveRef.current = isActive;\n }, [isActive, toolMessages.length]);\n\n const lastIndex = toolMessages.length - 1;\n\n const renderToolItem = (msg: ChatMessage, opts: { active?: boolean; showSpinner?: boolean }) => {\n const toolCall = msg.tool_calls?.[0];\n const toolName = toolCall?.function?.name;\n const summaryText = msg.summary || toolName || (opts.active ? 'Processing...' : 'Completed');\n\n // Custom renderer for completed tools\n if (!opts.active && toolName && toolRenderers?.[toolName] && allMessages) {\n const toolResponse = allMessages.find(\n (m) => m.role === 'tool' && m.tool_call_id === toolCall!.id\n );\n let input: any = {};\n try { input = JSON.parse(toolCall!.function.arguments); } catch {}\n const output = toolResponse?.content?.data ?? toolResponse?.content?.message;\n return toolRenderers[toolName](input, output);\n }\n\n const icon = opts.showSpinner\n ? <SpinnerIcon />\n : (toolName && toolIcons?.[toolName]) || <ToolDoneIcon />;\n\n return (\n <>\n <span className=\"devic-tool-activity-icon\">{icon}</span>\n <span className={`devic-tool-activity-text ${opts.active ? 'devic-glow-text' : ''}`}>\n {summaryText}\n </span>\n </>\n );\n };\n\n // If active, show all items; last one gets the glow treatment\n if (isActive) {\n return (\n <div className=\"devic-tool-group\">\n {toolMessages.map((msg, idx) => {\n const isLast = idx === lastIndex;\n return (\n <div\n key={msg.uid}\n className={`devic-tool-activity ${isLast ? 'devic-tool-activity--active' : ''}`}\n >\n {renderToolItem(msg, { active: isLast, showSpinner: isLast })}\n </div>\n );\n })}\n </div>\n );\n }\n\n // Completed: collapse if > 3 actions\n if (shouldCollapse && isCollapsed) {\n return (\n <div className=\"devic-tool-group\">\n <button\n className=\"devic-tool-collapse-btn\"\n onClick={() => setIsCollapsed(false)}\n type=\"button\"\n >\n <ToolDoneIcon />\n <span>{toolMessages.length} actions</span>\n <ChevronDownIcon />\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"devic-tool-group\">\n {shouldCollapse && (\n <button\n className=\"devic-tool-collapse-btn\"\n onClick={() => setIsCollapsed(true)}\n type=\"button\"\n >\n <span>{toolMessages.length} actions</span>\n <ChevronUpIcon />\n </button>\n )}\n <div className=\"devic-tool-group-items\" data-expanded=\"true\">\n {toolMessages.map((msg) => (\n <div key={msg.uid} className=\"devic-tool-activity\">\n {renderToolItem(msg, {})}\n </div>\n ))}\n </div>\n </div>\n );\n}\n\n/**\n * Messages list component\n */\nconst markdownOverrides = {\n table: {\n component: ({ children, ...props }: any) =>\n React.createElement('div', { className: 'markdown-table' },\n React.createElement('table', props, children)\n ),\n },\n};\n\nexport function ChatMessages({\n messages,\n allMessages,\n isLoading,\n welcomeMessage,\n suggestedMessages,\n onSuggestedClick,\n toolRenderers,\n toolIcons,\n loadingIndicator,\n showFeedback = true,\n feedbackMap,\n onFeedback,\n}: ChatMessagesProps): JSX.Element {\n const containerRef = useRef<HTMLDivElement>(null);\n const prevLengthRef = useRef(messages.length);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n if (containerRef.current) {\n containerRef.current.scrollTop = containerRef.current.scrollHeight;\n }\n prevLengthRef.current = messages.length;\n }, [messages.length, isLoading]);\n\n const grouped = groupMessages(messages, isLoading);\n\n // Show loading dots only if there's no active tool group at the end\n const lastGroup = grouped[grouped.length - 1];\n const showLoadingDots = isLoading && !(lastGroup?.type === 'toolGroup' && lastGroup.isActive);\n\n return (\n <div className=\"devic-messages-container\" ref={containerRef}>\n {messages.length === 0 && !isLoading && (welcomeMessage || suggestedMessages?.length) && (\n <div className=\"devic-welcome\">\n {welcomeMessage && (\n <p className=\"devic-welcome-text\">{welcomeMessage}</p>\n )}\n {suggestedMessages && suggestedMessages.length > 0 && (\n <div className=\"devic-suggested-messages\">\n {suggestedMessages.map((msg, idx) => (\n <button\n key={idx}\n className=\"devic-suggested-btn\"\n onClick={() => onSuggestedClick?.(msg)}\n >\n {msg}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {grouped.map((item) => {\n if (item.type === 'toolGroup') {\n return (\n <ToolGroup\n key={`tg-${item.toolMessages[0].uid}`}\n toolMessages={item.toolMessages}\n isActive={item.isActive}\n allMessages={allMessages}\n toolRenderers={toolRenderers}\n toolIcons={toolIcons}\n />\n );\n }\n\n const message = item.message;\n const messageText = message.content?.message;\n const hasFiles = message.content?.files && message.content.files.length > 0;\n const isAssistant = message.role === 'assistant';\n const currentFeedback = feedbackMap?.get(message.uid) || 'none';\n\n return (\n <div\n key={message.uid}\n className=\"devic-message\"\n data-role={message.role}\n >\n <div className=\"devic-message-bubble\">\n {messageText && isAssistant ? (\n <Markdown options={{ overrides: markdownOverrides }}>{messageText}</Markdown>\n ) : (\n messageText\n )}\n {hasFiles && (\n <div className=\"devic-message-files\">\n {message.content!.files!.map((file, fileIdx) => (\n <div key={fileIdx} className=\"devic-message-file\">\n <FileIcon />\n <span>{file.name}</span>\n </div>\n ))}\n </div>\n )}\n </div>\n <div className=\"devic-message-footer\">\n <span className=\"devic-message-time\">\n {formatTime(message.timestamp)}\n </span>\n {isAssistant && showFeedback && onFeedback && (\n <MessageActions\n messageId={message.uid}\n messageContent={messageText}\n currentFeedback={currentFeedback as FeedbackState}\n onFeedback={onFeedback}\n showCopy={true}\n showFeedback={true}\n />\n )}\n </div>\n </div>\n );\n })}\n\n {showLoadingDots && (\n loadingIndicator ? (\n <div className=\"devic-loading\">{loadingIndicator}</div>\n ) : (\n <div className=\"devic-loading\">\n <span className=\"devic-loading-dot\"></span>\n <span className=\"devic-loading-dot\"></span>\n <span className=\"devic-loading-dot\"></span>\n </div>\n )\n )}\n </div>\n );\n}\n\n/* ── Icons ── */\n\nfunction SpinnerIcon(): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n className=\"devic-spinner\"\n >\n <path d=\"M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83\" />\n </svg>\n );\n}\n\nfunction ToolDoneIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20,6 9,17 4,12\" />\n </svg>\n );\n}\n\nfunction ChevronDownIcon(): JSX.Element {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6,9 12,15 18,9\" />\n </svg>\n );\n}\n\nfunction ChevronUpIcon(): JSX.Element {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"6,15 12,9 18,15\" />\n </svg>\n );\n}\n\nfunction FileIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14,2 14,8 20,8\" />\n </svg>\n );\n}\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
@@ -3,4 +3,4 @@ export { ChatMessages } from './ChatMessages';
3
3
  export { ChatInput } from './ChatInput';
4
4
  export { ToolTimeline } from './ToolTimeline';
5
5
  export { ConversationSelector } from './ConversationSelector';
6
- export type { ChatDrawerProps, ChatDrawerOptions, ChatMessagesProps, ChatInputProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, } from './ChatDrawer.types';
6
+ export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, } from './ChatDrawer.types';
@@ -0,0 +1,50 @@
1
+ import type { FeedbackEntry } from '../../api/types';
2
+ /**
3
+ * Feedback state for a message
4
+ */
5
+ export type FeedbackState = 'none' | 'positive' | 'negative';
6
+ /**
7
+ * Theme configuration for feedback components
8
+ */
9
+ export interface FeedbackTheme {
10
+ backgroundColor?: string;
11
+ textColor?: string;
12
+ textMutedColor?: string;
13
+ secondaryBackgroundColor?: string;
14
+ borderColor?: string;
15
+ primaryColor?: string;
16
+ primaryHoverColor?: string;
17
+ }
18
+ /**
19
+ * Props for FeedbackModal component
20
+ */
21
+ export interface FeedbackModalProps {
22
+ isOpen: boolean;
23
+ onClose: () => void;
24
+ onSubmit: (comment: string) => void;
25
+ feedbackType: 'positive' | 'negative';
26
+ isSubmitting?: boolean;
27
+ theme?: FeedbackTheme;
28
+ }
29
+ /**
30
+ * Props for MessageActions component
31
+ */
32
+ export interface MessageActionsProps {
33
+ messageId: string;
34
+ messageContent?: string;
35
+ currentFeedback?: FeedbackState;
36
+ onFeedback?: (messageId: string, positive: boolean, comment?: string) => void;
37
+ onCopy?: (content: string) => void;
38
+ showCopy?: boolean;
39
+ showFeedback?: boolean;
40
+ disabled?: boolean;
41
+ theme?: FeedbackTheme;
42
+ }
43
+ /**
44
+ * Context value for feedback
45
+ */
46
+ export interface FeedbackContextValue {
47
+ feedbackMap: Map<string, FeedbackEntry>;
48
+ submitFeedback: (messageId: string, positive: boolean, comment?: string) => Promise<void>;
49
+ isSubmitting: boolean;
50
+ }
@@ -0,0 +1,5 @@
1
+ import type { FeedbackModalProps } from './Feedback.types';
2
+ /**
3
+ * Modal for submitting feedback with optional comment
4
+ */
5
+ export declare function FeedbackModal({ isOpen, onClose, onSubmit, feedbackType, isSubmitting, theme, }: FeedbackModalProps): JSX.Element | null;
@@ -0,0 +1,85 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useRef, useMemo, useEffect } from 'react';
3
+
4
+ /**
5
+ * Modal for submitting feedback with optional comment
6
+ */
7
+ function FeedbackModal({ isOpen, onClose, onSubmit, feedbackType, isSubmitting = false, theme, }) {
8
+ const [comment, setComment] = useState('');
9
+ const textareaRef = useRef(null);
10
+ const modalRef = useRef(null);
11
+ // Build inline styles from theme
12
+ const modalStyle = useMemo(() => {
13
+ if (!theme)
14
+ return undefined;
15
+ return {
16
+ '--devic-bg': theme.backgroundColor,
17
+ '--devic-text': theme.textColor,
18
+ '--devic-text-muted': theme.textMutedColor,
19
+ '--devic-text-secondary': theme.textMutedColor,
20
+ '--devic-bg-secondary': theme.secondaryBackgroundColor,
21
+ '--devic-border': theme.borderColor,
22
+ '--devic-primary': theme.primaryColor,
23
+ '--devic-primary-hover': theme.primaryHoverColor,
24
+ };
25
+ }, [theme]);
26
+ // Focus textarea when modal opens
27
+ useEffect(() => {
28
+ if (isOpen && textareaRef.current) {
29
+ setTimeout(() => textareaRef.current?.focus(), 50);
30
+ }
31
+ }, [isOpen]);
32
+ // Reset comment when modal closes
33
+ useEffect(() => {
34
+ if (!isOpen) {
35
+ setComment('');
36
+ }
37
+ }, [isOpen]);
38
+ // Handle click outside
39
+ useEffect(() => {
40
+ if (!isOpen)
41
+ return;
42
+ const handleClickOutside = (e) => {
43
+ if (modalRef.current && !modalRef.current.contains(e.target)) {
44
+ onClose();
45
+ }
46
+ };
47
+ const handleEscape = (e) => {
48
+ if (e.key === 'Escape') {
49
+ onClose();
50
+ }
51
+ };
52
+ document.addEventListener('mousedown', handleClickOutside);
53
+ document.addEventListener('keydown', handleEscape);
54
+ return () => {
55
+ document.removeEventListener('mousedown', handleClickOutside);
56
+ document.removeEventListener('keydown', handleEscape);
57
+ };
58
+ }, [isOpen, onClose]);
59
+ if (!isOpen)
60
+ return null;
61
+ const handleSubmit = (e) => {
62
+ e.preventDefault();
63
+ onSubmit(comment);
64
+ };
65
+ const handleKeyDown = (e) => {
66
+ if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
67
+ e.preventDefault();
68
+ onSubmit(comment);
69
+ }
70
+ };
71
+ return (jsx("div", { className: "devic-feedback-overlay", children: jsxs("div", { className: "devic-feedback-modal", ref: modalRef, style: modalStyle, children: [jsxs("div", { className: "devic-feedback-modal-header", children: [jsx("span", { className: "devic-feedback-modal-icon", children: feedbackType === 'positive' ? jsx(ThumbsUpIcon, { filled: true }) : jsx(ThumbsDownIcon, { filled: true }) }), jsx("span", { className: "devic-feedback-modal-title", children: feedbackType === 'positive' ? 'What did you like?' : 'What could be improved?' }), jsx("button", { type: "button", className: "devic-feedback-modal-close", onClick: onClose, "aria-label": "Close", children: jsx(CloseIcon, {}) })] }), jsxs("form", { onSubmit: handleSubmit, children: [jsx("textarea", { ref: textareaRef, className: "devic-feedback-textarea", placeholder: "Add a comment (optional)...", value: comment, onChange: (e) => setComment(e.target.value), onKeyDown: handleKeyDown, rows: 3, disabled: isSubmitting }), jsxs("div", { className: "devic-feedback-modal-actions", children: [jsx("button", { type: "button", className: "devic-feedback-btn devic-feedback-btn--secondary", onClick: onClose, disabled: isSubmitting, children: "Cancel" }), jsx("button", { type: "submit", className: "devic-feedback-btn devic-feedback-btn--primary", disabled: isSubmitting, children: isSubmitting ? 'Sending...' : 'Submit' })] })] })] }) }));
72
+ }
73
+ /* ── Icons ── */
74
+ function ThumbsUpIcon({ filled = false }) {
75
+ return (jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: filled ? 'currentColor' : 'none', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M7 10v12M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z" }) }));
76
+ }
77
+ function ThumbsDownIcon({ filled = false }) {
78
+ return (jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: filled ? 'currentColor' : 'none', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M17 14V2M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z" }) }));
79
+ }
80
+ function CloseIcon() {
81
+ return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
82
+ }
83
+
84
+ export { FeedbackModal };
85
+ //# sourceMappingURL=FeedbackModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeedbackModal.js","sources":["../../../../src/components/Feedback/FeedbackModal.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useMemo } from 'react';\nimport type { FeedbackModalProps } from './Feedback.types';\n\n/**\n * Modal for submitting feedback with optional comment\n */\nexport function FeedbackModal({\n isOpen,\n onClose,\n onSubmit,\n feedbackType,\n isSubmitting = false,\n theme,\n}: FeedbackModalProps): JSX.Element | null {\n const [comment, setComment] = useState('');\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n\n // Build inline styles from theme\n const modalStyle = useMemo(() => {\n if (!theme) return undefined;\n return {\n '--devic-bg': theme.backgroundColor,\n '--devic-text': theme.textColor,\n '--devic-text-muted': theme.textMutedColor,\n '--devic-text-secondary': theme.textMutedColor,\n '--devic-bg-secondary': theme.secondaryBackgroundColor,\n '--devic-border': theme.borderColor,\n '--devic-primary': theme.primaryColor,\n '--devic-primary-hover': theme.primaryHoverColor,\n } as React.CSSProperties;\n }, [theme]);\n\n // Focus textarea when modal opens\n useEffect(() => {\n if (isOpen && textareaRef.current) {\n setTimeout(() => textareaRef.current?.focus(), 50);\n }\n }, [isOpen]);\n\n // Reset comment when modal closes\n useEffect(() => {\n if (!isOpen) {\n setComment('');\n }\n }, [isOpen]);\n\n // Handle click outside\n useEffect(() => {\n if (!isOpen) return;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (modalRef.current && !modalRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n };\n }, [isOpen, onClose]);\n\n if (!isOpen) return null;\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onSubmit(comment);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n onSubmit(comment);\n }\n };\n\n return (\n <div className=\"devic-feedback-overlay\">\n <div className=\"devic-feedback-modal\" ref={modalRef} style={modalStyle}>\n <div className=\"devic-feedback-modal-header\">\n <span className=\"devic-feedback-modal-icon\">\n {feedbackType === 'positive' ? <ThumbsUpIcon filled /> : <ThumbsDownIcon filled />}\n </span>\n <span className=\"devic-feedback-modal-title\">\n {feedbackType === 'positive' ? 'What did you like?' : 'What could be improved?'}\n </span>\n <button\n type=\"button\"\n className=\"devic-feedback-modal-close\"\n onClick={onClose}\n aria-label=\"Close\"\n >\n <CloseIcon />\n </button>\n </div>\n\n <form onSubmit={handleSubmit}>\n <textarea\n ref={textareaRef}\n className=\"devic-feedback-textarea\"\n placeholder=\"Add a comment (optional)...\"\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n onKeyDown={handleKeyDown}\n rows={3}\n disabled={isSubmitting}\n />\n\n <div className=\"devic-feedback-modal-actions\">\n <button\n type=\"button\"\n className=\"devic-feedback-btn devic-feedback-btn--secondary\"\n onClick={onClose}\n disabled={isSubmitting}\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n className=\"devic-feedback-btn devic-feedback-btn--primary\"\n disabled={isSubmitting}\n >\n {isSubmitting ? 'Sending...' : 'Submit'}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n\n/* ── Icons ── */\n\nfunction ThumbsUpIcon({ filled = false }: { filled?: boolean }): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill={filled ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M7 10v12M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z\" />\n </svg>\n );\n}\n\nfunction ThumbsDownIcon({ filled = false }: { filled?: boolean }): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill={filled ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M17 14V2M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z\" />\n </svg>\n );\n}\n\nfunction CloseIcon(): JSX.Element {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n"],"names":["_jsx","_jsxs"],"mappings":";;;AAGA;;AAEG;SACa,aAAa,CAAC,EAC5B,MAAM,EACN,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,YAAY,GAAG,KAAK,EACpB,KAAK,GACc,EAAA;IACnB,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;AAC1C,IAAA,MAAM,WAAW,GAAG,MAAM,CAAsB,IAAI,CAAC;AACrD,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAiB,IAAI,CAAC;;AAG7C,IAAA,MAAM,UAAU,GAAG,OAAO,CAAC,MAAK;AAC9B,QAAA,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,SAAS;QAC5B,OAAO;YACL,YAAY,EAAE,KAAK,CAAC,eAAe;YACnC,cAAc,EAAE,KAAK,CAAC,SAAS;YAC/B,oBAAoB,EAAE,KAAK,CAAC,cAAc;YAC1C,wBAAwB,EAAE,KAAK,CAAC,cAAc;YAC9C,sBAAsB,EAAE,KAAK,CAAC,wBAAwB;YACtD,gBAAgB,EAAE,KAAK,CAAC,WAAW;YACnC,iBAAiB,EAAE,KAAK,CAAC,YAAY;YACrC,uBAAuB,EAAE,KAAK,CAAC,iBAAiB;SAC1B;AAC1B,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;;IAGX,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE;AACjC,YAAA,UAAU,CAAC,MAAM,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACpD;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;;IAGZ,SAAS,CAAC,MAAK;QACb,IAAI,CAAC,MAAM,EAAE;YACX,UAAU,CAAC,EAAE,CAAC;QAChB;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;;IAGZ,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,CAAC,MAAM;YAAE;AAEb,QAAA,MAAM,kBAAkB,GAAG,CAAC,CAAa,KAAI;AAC3C,YAAA,IAAI,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAc,CAAC,EAAE;AACpE,gBAAA,OAAO,EAAE;YACX;AACF,QAAA,CAAC;AAED,QAAA,MAAM,YAAY,GAAG,CAAC,CAAgB,KAAI;AACxC,YAAA,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE;AACtB,gBAAA,OAAO,EAAE;YACX;AACF,QAAA,CAAC;AAED,QAAA,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,kBAAkB,CAAC;AAC1D,QAAA,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,YAAY,CAAC;AAClD,QAAA,OAAO,MAAK;AACV,YAAA,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,CAAC;AAC7D,YAAA,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC;AACvD,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAErB,IAAA,IAAI,CAAC,MAAM;AAAE,QAAA,OAAO,IAAI;AAExB,IAAA,MAAM,YAAY,GAAG,CAAC,CAAkB,KAAI;QAC1C,CAAC,CAAC,cAAc,EAAE;QAClB,QAAQ,CAAC,OAAO,CAAC;AACnB,IAAA,CAAC;AAED,IAAA,MAAM,aAAa,GAAG,CAAC,CAAsB,KAAI;AAC/C,QAAA,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE;YACjD,CAAC,CAAC,cAAc,EAAE;YAClB,QAAQ,CAAC,OAAO,CAAC;QACnB;AACF,IAAA,CAAC;IAED,QACEA,aAAK,SAAS,EAAC,wBAAwB,EAAA,QAAA,EACrCC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sBAAsB,EAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAA,QAAA,EAAA,CACpEA,cAAK,SAAS,EAAC,6BAA6B,EAAA,QAAA,EAAA,CAC1CD,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,2BAA2B,YACxC,YAAY,KAAK,UAAU,GAAGA,GAAA,CAAC,YAAY,IAAC,MAAM,EAAA,IAAA,EAAA,CAAG,GAAGA,IAAC,cAAc,EAAA,EAAC,MAAM,EAAA,IAAA,EAAA,CAAG,EAAA,CAC7E,EACPA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,4BAA4B,EAAA,QAAA,EACzC,YAAY,KAAK,UAAU,GAAG,oBAAoB,GAAG,yBAAyB,EAAA,CAC1E,EACPA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,4BAA4B,EACtC,OAAO,EAAE,OAAO,EAAA,YAAA,EACL,OAAO,YAElBA,GAAA,CAAC,SAAS,KAAG,EAAA,CACN,CAAA,EAAA,CACL,EAENC,IAAA,CAAA,MAAA,EAAA,EAAM,QAAQ,EAAE,YAAY,EAAA,QAAA,EAAA,CAC1BD,GAAA,CAAA,UAAA,EAAA,EACE,GAAG,EAAE,WAAW,EAChB,SAAS,EAAC,yBAAyB,EACnC,WAAW,EAAC,6BAA6B,EACzC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC3C,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,YAAY,EAAA,CACtB,EAEFC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,8BAA8B,aAC3CD,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kDAAkD,EAC5D,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,YAAY,EAAA,QAAA,EAAA,QAAA,EAAA,CAGf,EACTA,GAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,gDAAgD,EAC1D,QAAQ,EAAE,YAAY,EAAA,QAAA,EAErB,YAAY,GAAG,YAAY,GAAG,QAAQ,EAAA,CAChC,IACL,CAAA,EAAA,CACD,CAAA,EAAA,CACH,EAAA,CACF;AAEV;AAEA;AAEA,SAAS,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,EAAwB,EAAA;IAC5D,QACEA,aACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,MAAM,EACtC,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EAAA,QAAA,EAEtBA,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,oKAAoK,EAAA,CAAG,EAAA,CAC3K;AAEV;AAEA,SAAS,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,EAAwB,EAAA;IAC9D,QACEA,aACE,KAAK,EAAC,IAAI,EACV,MAAM,EAAC,IAAI,EACX,OAAO,EAAC,WAAW,EACnB,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,MAAM,EACtC,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EAAA,QAAA,EAEtBA,GAAA,CAAA,MAAA,EAAA,EAAM,CAAC,EAAC,mKAAmK,EAAA,CAAG,EAAA,CAC1K;AAEV;AAEA,SAAS,SAAS,GAAA;AAChB,IAAA,QACEC,IAAA,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,CAEtBD,GAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAA,CAAG,EACtCA,GAAA,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;;;;"}
@@ -0,0 +1,5 @@
1
+ import type { MessageActionsProps } from './Feedback.types';
2
+ /**
3
+ * Action buttons for a message (copy, thumbs up, thumbs down)
4
+ */
5
+ export declare function MessageActions({ messageId, messageContent, currentFeedback, onFeedback, onCopy, showCopy, showFeedback, disabled, theme, }: MessageActionsProps): JSX.Element;
@@ -0,0 +1,72 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useState, useMemo, useCallback } from 'react';
3
+ import { FeedbackModal } from './FeedbackModal.js';
4
+
5
+ /**
6
+ * Action buttons for a message (copy, thumbs up, thumbs down)
7
+ */
8
+ function MessageActions({ messageId, messageContent, currentFeedback = 'none', onFeedback, onCopy, showCopy = true, showFeedback = true, disabled = false, theme, }) {
9
+ const [feedbackState, setFeedbackState] = useState(currentFeedback);
10
+ const [modalOpen, setModalOpen] = useState(false);
11
+ const [pendingFeedbackType, setPendingFeedbackType] = useState('positive');
12
+ const [isSubmitting, setIsSubmitting] = useState(false);
13
+ const [copied, setCopied] = useState(false);
14
+ // Build inline styles from theme for the actions container
15
+ const containerStyle = useMemo(() => {
16
+ if (!theme)
17
+ return undefined;
18
+ return {
19
+ '--devic-bg-secondary': theme.secondaryBackgroundColor,
20
+ '--devic-text-secondary': theme.textMutedColor,
21
+ };
22
+ }, [theme]);
23
+ const handleCopy = useCallback(async () => {
24
+ if (!messageContent)
25
+ return;
26
+ try {
27
+ await navigator.clipboard.writeText(messageContent);
28
+ setCopied(true);
29
+ onCopy?.(messageContent);
30
+ setTimeout(() => setCopied(false), 2000);
31
+ }
32
+ catch (err) {
33
+ console.error('Failed to copy:', err);
34
+ }
35
+ }, [messageContent, onCopy]);
36
+ const handleFeedbackClick = useCallback((type) => {
37
+ setPendingFeedbackType(type);
38
+ setModalOpen(true);
39
+ }, [feedbackState]);
40
+ const handleModalSubmit = useCallback(async (comment) => {
41
+ setIsSubmitting(true);
42
+ try {
43
+ const isPositive = pendingFeedbackType === 'positive';
44
+ await onFeedback?.(messageId, isPositive, comment || undefined);
45
+ setFeedbackState(isPositive ? 'positive' : 'negative');
46
+ setModalOpen(false);
47
+ }
48
+ catch (err) {
49
+ console.error('Failed to submit feedback:', err);
50
+ }
51
+ finally {
52
+ setIsSubmitting(false);
53
+ }
54
+ }, [messageId, pendingFeedbackType, onFeedback]);
55
+ return (jsxs(Fragment, { children: [jsxs("div", { className: "devic-message-actions", style: containerStyle, children: [showCopy && messageContent && (jsx("button", { type: "button", className: `devic-action-btn ${copied ? 'devic-action-btn--active' : ''}`, onClick: handleCopy, disabled: disabled, title: "Copy to clipboard", "aria-label": "Copy to clipboard", children: copied ? jsx(CheckIcon, {}) : jsx(CopyIcon, {}) })), showFeedback && (jsxs(Fragment, { children: [jsx("button", { type: "button", className: `devic-action-btn ${feedbackState === 'positive' ? 'devic-action-btn--active devic-action-btn--positive' : ''}`, onClick: () => handleFeedbackClick('positive'), disabled: disabled, title: "Good response", "aria-label": "Good response", children: jsx(ThumbsUpIcon, { filled: feedbackState === 'positive' }) }), jsx("button", { type: "button", className: `devic-action-btn ${feedbackState === 'negative' ? 'devic-action-btn--active devic-action-btn--negative' : ''}`, onClick: () => handleFeedbackClick('negative'), disabled: disabled, title: "Bad response", "aria-label": "Bad response", children: jsx(ThumbsDownIcon, { filled: feedbackState === 'negative' }) })] }))] }), jsx(FeedbackModal, { isOpen: modalOpen, onClose: () => setModalOpen(false), onSubmit: handleModalSubmit, feedbackType: pendingFeedbackType, isSubmitting: isSubmitting, theme: theme })] }));
56
+ }
57
+ /* ── Icons ── */
58
+ function CopyIcon() {
59
+ return (jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }));
60
+ }
61
+ function CheckIcon() {
62
+ return (jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20,6 9,17 4,12" }) }));
63
+ }
64
+ function ThumbsUpIcon({ filled = false }) {
65
+ return (jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: filled ? 'currentColor' : 'none', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M7 10v12M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z" }) }));
66
+ }
67
+ function ThumbsDownIcon({ filled = false }) {
68
+ return (jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: filled ? 'currentColor' : 'none', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M17 14V2M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z" }) }));
69
+ }
70
+
71
+ export { MessageActions };
72
+ //# sourceMappingURL=MessageActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageActions.js","sources":["../../../../src/components/Feedback/MessageActions.tsx"],"sourcesContent":["import React, { useState, useCallback, useMemo } from 'react';\nimport { FeedbackModal } from './FeedbackModal';\nimport type { MessageActionsProps, FeedbackState } from './Feedback.types';\n\n/**\n * Action buttons for a message (copy, thumbs up, thumbs down)\n */\nexport function MessageActions({\n messageId,\n messageContent,\n currentFeedback = 'none',\n onFeedback,\n onCopy,\n showCopy = true,\n showFeedback = true,\n disabled = false,\n theme,\n}: MessageActionsProps): JSX.Element {\n const [feedbackState, setFeedbackState] = useState<FeedbackState>(currentFeedback);\n const [modalOpen, setModalOpen] = useState(false);\n const [pendingFeedbackType, setPendingFeedbackType] = useState<'positive' | 'negative'>('positive');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [copied, setCopied] = useState(false);\n\n // Build inline styles from theme for the actions container\n const containerStyle = useMemo(() => {\n if (!theme) return undefined;\n return {\n '--devic-bg-secondary': theme.secondaryBackgroundColor,\n '--devic-text-secondary': theme.textMutedColor,\n } as React.CSSProperties;\n }, [theme]);\n\n const handleCopy = useCallback(async () => {\n if (!messageContent) return;\n\n try {\n await navigator.clipboard.writeText(messageContent);\n setCopied(true);\n onCopy?.(messageContent);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n }, [messageContent, onCopy]);\n\n const handleFeedbackClick = useCallback((type: 'positive' | 'negative') => {\n // If clicking the same feedback type that's already selected, toggle it off\n if ((type === 'positive' && feedbackState === 'positive') ||\n (type === 'negative' && feedbackState === 'negative')) {\n // Optionally could allow removal - for now we just open modal to change comment\n }\n\n setPendingFeedbackType(type);\n setModalOpen(true);\n }, [feedbackState]);\n\n const handleModalSubmit = useCallback(async (comment: string) => {\n setIsSubmitting(true);\n try {\n const isPositive = pendingFeedbackType === 'positive';\n await onFeedback?.(messageId, isPositive, comment || undefined);\n setFeedbackState(isPositive ? 'positive' : 'negative');\n setModalOpen(false);\n } catch (err) {\n console.error('Failed to submit feedback:', err);\n } finally {\n setIsSubmitting(false);\n }\n }, [messageId, pendingFeedbackType, onFeedback]);\n\n return (\n <>\n <div className=\"devic-message-actions\" style={containerStyle}>\n {showCopy && messageContent && (\n <button\n type=\"button\"\n className={`devic-action-btn ${copied ? 'devic-action-btn--active' : ''}`}\n onClick={handleCopy}\n disabled={disabled}\n title=\"Copy to clipboard\"\n aria-label=\"Copy to clipboard\"\n >\n {copied ? <CheckIcon /> : <CopyIcon />}\n </button>\n )}\n\n {showFeedback && (\n <>\n <button\n type=\"button\"\n className={`devic-action-btn ${feedbackState === 'positive' ? 'devic-action-btn--active devic-action-btn--positive' : ''}`}\n onClick={() => handleFeedbackClick('positive')}\n disabled={disabled}\n title=\"Good response\"\n aria-label=\"Good response\"\n >\n <ThumbsUpIcon filled={feedbackState === 'positive'} />\n </button>\n\n <button\n type=\"button\"\n className={`devic-action-btn ${feedbackState === 'negative' ? 'devic-action-btn--active devic-action-btn--negative' : ''}`}\n onClick={() => handleFeedbackClick('negative')}\n disabled={disabled}\n title=\"Bad response\"\n aria-label=\"Bad response\"\n >\n <ThumbsDownIcon filled={feedbackState === 'negative'} />\n </button>\n </>\n )}\n </div>\n\n <FeedbackModal\n isOpen={modalOpen}\n onClose={() => setModalOpen(false)}\n onSubmit={handleModalSubmit}\n feedbackType={pendingFeedbackType}\n isSubmitting={isSubmitting}\n theme={theme}\n />\n </>\n );\n}\n\n/* ── Icons ── */\n\nfunction CopyIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n );\n}\n\nfunction CheckIcon(): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20,6 9,17 4,12\" />\n </svg>\n );\n}\n\nfunction ThumbsUpIcon({ filled = false }: { filled?: boolean }): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill={filled ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M7 10v12M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z\" />\n </svg>\n );\n}\n\nfunction ThumbsDownIcon({ filled = false }: { filled?: boolean }): JSX.Element {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill={filled ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M17 14V2M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z\" />\n </svg>\n );\n}\n"],"names":["_jsxs","_jsx","_Fragment"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { FeedbackModal } from './FeedbackModal';
2
+ export { MessageActions } from './MessageActions';
3
+ export type { FeedbackModalProps, MessageActionsProps, FeedbackState, FeedbackContextValue, FeedbackTheme, } from './Feedback.types';
@@ -1,10 +1,14 @@
1
1
  export { DevicProvider, DevicContext, useDevicContext, useOptionalDevicContext } from './provider';
2
2
  export type { DevicProviderConfig, DevicProviderProps, DevicContextValue } from './provider';
3
3
  export { ChatDrawer, ChatMessages, ChatInput, ToolTimeline, ConversationSelector } from './components/ChatDrawer';
4
- export type { ChatDrawerProps, ChatDrawerOptions, ChatMessagesProps, ChatInputProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, } from './components/ChatDrawer';
4
+ export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, } from './components/ChatDrawer';
5
+ export { AICommandBar, useAICommandBar, formatShortcut } from './components/AICommandBar';
6
+ export type { AICommandBarProps, AICommandBarOptions, AICommandBarHandle, AICommandBarCommand, CommandBarResult, ToolCallSummary, } from './components/AICommandBar';
5
7
  export { useDevicChat, usePolling, useModelInterface } from './hooks';
6
8
  export type { UseDevicChatOptions, UseDevicChatResult, UsePollingOptions, UsePollingResult, UseModelInterfaceOptions, UseModelInterfaceResult, } from './hooks';
7
9
  export { DevicApiClient, DevicApiError } from './api/client';
8
10
  export type { DevicApiClientConfig } from './api/client';
9
- export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, RealtimeChatHistory, RealtimeStatus, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, PreviousMessage, ApiError, ConversationSummary, } from './api/types';
11
+ export type { ChatMessage, ChatFile, MessageContent, ToolCall, ToolCallResponse, ProcessMessageDto, AssistantResponse, AsyncResponse, RealtimeChatHistory, RealtimeStatus, ChatHistory, AssistantSpecialization, ModelInterfaceTool, ModelInterfaceToolSchema, PreviousMessage, ApiError, ConversationSummary, FeedbackSubmission, FeedbackEntry, } from './api/types';
12
+ export { MessageActions, FeedbackModal } from './components/Feedback';
13
+ export type { MessageActionsProps, FeedbackModalProps, FeedbackState, FeedbackTheme } from './components/Feedback';
10
14
  export { generateId, deepMerge, debounce, throttle, formatFileSize, storage } from './utils';
package/dist/esm/index.js CHANGED
@@ -5,9 +5,13 @@ export { ChatMessages } from './components/ChatDrawer/ChatMessages.js';
5
5
  export { ChatInput } from './components/ChatDrawer/ChatInput.js';
6
6
  export { ToolTimeline } from './components/ChatDrawer/ToolTimeline.js';
7
7
  export { ConversationSelector } from './components/ChatDrawer/ConversationSelector.js';
8
+ export { AICommandBar } from './components/AICommandBar/AICommandBar.js';
9
+ export { formatShortcut, useAICommandBar } from './components/AICommandBar/useAICommandBar.js';
8
10
  export { useDevicChat } from './hooks/useDevicChat.js';
9
11
  export { usePolling } from './hooks/usePolling.js';
10
12
  export { useModelInterface } from './hooks/useModelInterface.js';
11
13
  export { DevicApiClient, DevicApiError } from './api/client.js';
14
+ export { FeedbackModal } from './components/Feedback/FeedbackModal.js';
15
+ export { MessageActions } from './components/Feedback/MessageActions.js';
12
16
  export { debounce, deepMerge, formatFileSize, generateId, storage, throttle } from './utils/index.js';
13
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- .devic-chat-drawer{--devic-primary:#1890ff;--devic-primary-hover:#40a9ff;--devic-primary-light:#e6f7ff;--devic-bg:#fff;--devic-bg-secondary:#f5f5f5;--devic-text:#333;--devic-text-secondary:#666;--devic-text-muted:#999;--devic-border:#e8e8e8;--devic-shadow:0 4px 12px rgba(0,0,0,.15);--devic-radius:8px;--devic-radius-sm:4px;--devic-radius-lg:16px;--devic-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--devic-transition:0.3s ease;background:var(--devic-bg);bottom:0;box-shadow:var(--devic-shadow);color:var(--devic-text);display:flex;flex-direction:column;font-family:var(--devic-font-family);font-size:14px;line-height:1.5;position:fixed;top:0;transition:transform var(--devic-transition)}.devic-chat-drawer[data-position=right]{right:0;transform:translateX(100%)}.devic-chat-drawer[data-position=left]{left:0;transform:translateX(-100%)}.devic-chat-drawer[data-open=true]{transform:translateX(0)}.devic-drawer-overlay{background:rgba(0,0,0,.3);inset:0;opacity:0;position:fixed;transition:opacity var(--devic-transition),visibility var(--devic-transition);visibility:hidden}.devic-drawer-overlay[data-open=true]{opacity:1;visibility:visible}.devic-drawer-header{align-items:center;border-bottom:1px solid var(--devic-border);display:flex;flex-shrink:0;justify-content:space-between;padding:16px}.devic-drawer-avatar{border-radius:50%;flex-shrink:0;height:28px;object-fit:cover;width:28px}.devic-drawer-title{font-size:16px;font-weight:600;margin:0}.devic-drawer-close{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-drawer-close:hover{background:var(--devic-bg-secondary);color:var(--devic-text)}.devic-messages-container{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.devic-welcome{color:var(--devic-text-secondary);padding:24px 16px;text-align:center}.devic-welcome-text{font-size:16px;margin-bottom:16px}.devic-suggested-messages{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}.devic-suggested-btn{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-lg);color:var(--devic-text);cursor:pointer;font-size:13px;padding:8px 16px;transition:border-color var(--devic-transition),background var(--devic-transition)}.devic-suggested-btn:hover{background:var(--devic-primary-light);border-color:var(--devic-primary)}.devic-message{display:flex;flex-direction:column;max-width:85%}.devic-message[data-role=user]{align-self:flex-end}.devic-message[data-role=assistant],.devic-message[data-role=tool]{align-self:flex-start}.devic-message-bubble{word-wrap:break-word;border-radius:var(--devic-radius);padding:10px 14px}.devic-message[data-role=user] .devic-message-bubble{background:var(--devic-user-bubble,var(--devic-primary));border-bottom-right-radius:var(--devic-radius-sm);color:var(--devic-user-bubble-text,#fff)}.devic-message[data-role=assistant] .devic-message-bubble{background:var(--devic-assistant-bubble,var(--devic-bg-secondary));border-bottom-left-radius:var(--devic-radius-sm);color:var(--devic-assistant-bubble-text,var(--devic-text))}.devic-message[data-role=tool] .devic-message-bubble{background:var(--devic-primary-light);border:1px solid var(--devic-primary);color:var(--devic-text);font-size:12px}.devic-message-time{color:var(--devic-text-muted);font-size:11px;margin-top:4px}.devic-message[data-role=user] .devic-message-time{text-align:right}.devic-message-files{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}.devic-message-file{align-items:center;background:hsla(0,0%,100%,.2);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:6px 10px}.devic-loading{align-self:flex-start;display:flex;gap:4px;padding:10px 14px}.devic-loading-dot{animation:devic-bounce 1.4s ease-in-out infinite both;background:var(--devic-text-muted);border-radius:50%;height:8px;width:8px}.devic-loading-dot:first-child{animation-delay:-.32s}.devic-loading-dot:nth-child(2){animation-delay:-.16s}@keyframes devic-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.devic-tool-group{align-self:flex-start;display:flex;flex-direction:column;gap:2px;max-width:85%}.devic-tool-activity{align-items:flex-start;animation:devic-slideUp .3s ease-out;display:flex;gap:8px;padding:4px 0}.devic-tool-activity-icon{align-items:center;color:var(--devic-text-muted);display:flex;flex-shrink:0;margin-top:1px}.devic-tool-activity--active .devic-tool-activity-icon{color:var(--devic-primary)}.devic-tool-activity-text{color:var(--devic-text-secondary);font-size:13px;line-height:1.4}.devic-glow-text{animation:devic-pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes devic-pulse{0%,to{opacity:1}50%{opacity:.5}}.devic-spinner{animation:devic-spin 1s linear infinite}@keyframes devic-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes devic-slideUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.devic-tool-collapse-btn{align-items:center;background:none;border:none;color:var(--devic-text-muted);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:12px;gap:6px;padding:4px 0;transition:color .2s ease}.devic-tool-collapse-btn:hover{color:var(--devic-primary)}.devic-tool-group-items{animation:devic-expandItems .4s ease-out;overflow:hidden}.devic-tool-group-items[data-expanded=true]{max-height:500px}@keyframes devic-expandItems{0%{max-height:0;opacity:0}to{max-height:500px;opacity:1}}.devic-input-area{border-top:1px solid var(--devic-border);flex-shrink:0;padding:16px}.devic-input-wrapper{align-items:flex-end;background:var(--devic-bg-secondary);border-radius:var(--devic-radius);display:flex;gap:8px;padding:8px 12px}.devic-input{background:none;border:none;color:var(--devic-text);flex:1;font-family:inherit;font-size:14px;line-height:1.5;max-height:120px;min-height:24px;outline:none;resize:none}.devic-input::placeholder{color:var(--devic-text-muted)}.devic-input-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;flex-shrink:0;padding:4px;transition:color var(--devic-transition)}.devic-input-btn:hover:not(:disabled){color:var(--devic-primary)}.devic-input-btn:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn{background:var(--devic-send-btn,var(--devic-primary));border-radius:var(--devic-radius-sm);color:#fff;padding:6px 12px}.devic-send-btn-wrapper{flex-shrink:0;position:relative}.devic-send-btn-custom{align-items:center;display:flex;justify-content:center;pointer-events:none}.devic-send-btn-overlay{background:transparent;border:none;cursor:pointer;inset:0;margin:0;padding:0;position:absolute}.devic-send-btn-overlay:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn:hover:not(:disabled){background:var(--devic-primary-hover);color:#fff}.devic-file-preview{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.devic-file-preview-item{align-items:center;background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:4px 8px}.devic-file-remove{background:none;border:none;color:var(--devic-text-muted);cursor:pointer;font-size:16px;line-height:1;padding:0}.devic-file-remove:hover{color:#ff4d4f}.devic-trigger{align-items:center;background:var(--devic-primary);border:none;border-radius:50%;box-shadow:var(--devic-shadow);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;position:fixed;transition:background var(--devic-transition),transform var(--devic-transition);width:56px}.devic-trigger:hover{background:var(--devic-primary-hover);transform:scale(1.05)}.devic-trigger svg{height:24px;width:24px}.devic-error{background:#fff2f0;border:1px solid #ffccc7;border-radius:var(--devic-radius);color:#ff4d4f;font-size:13px;margin:8px 16px;padding:12px}.devic-messages-container::-webkit-scrollbar{width:6px}.devic-messages-container::-webkit-scrollbar-track{background:transparent}.devic-messages-container::-webkit-scrollbar-thumb{background:var(--devic-border);border-radius:3px}.devic-messages-container::-webkit-scrollbar-thumb:hover{background:var(--devic-text-muted)}.devic-chat-drawer[data-mode=inline]{border:1px solid var(--devic-border);bottom:auto;box-shadow:none;height:100%;left:auto;position:relative;right:auto;top:auto;transform:none}.devic-drawer-header-actions{align-items:center;display:flex;gap:4px;margin-left:auto}.devic-new-chat-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-new-chat-btn:hover{background:var(--devic-bg-secondary);color:var(--devic-primary)}.devic-conversation-selector{flex:1;margin:0 8px;min-width:0;position:relative}.devic-conversation-selector-trigger{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;gap:6px;padding:6px 10px;text-align:left;transition:border-color var(--devic-transition);width:100%}.devic-conversation-selector-trigger:hover{border-color:var(--devic-primary)}.devic-conversation-selector-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-dropdown{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius);box-shadow:var(--devic-shadow);display:flex;flex-direction:column;left:0;max-height:320px;position:absolute;right:0;top:calc(100% + 4px);z-index:10}.devic-conversation-search-wrapper{border-bottom:1px solid var(--devic-border);padding:8px}.devic-conversation-search{background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);box-sizing:border-box;color:var(--devic-text);font-family:var(--devic-font-family);font-size:13px;outline:none;padding:6px 8px;width:100%}.devic-conversation-search:focus{border-color:var(--devic-primary)}.devic-conversation-list{flex:1;overflow-y:auto}.devic-conversation-item{align-items:center;background:none;border:none;color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;justify-content:space-between;padding:8px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-item:hover,.devic-conversation-item[data-active=true]{background:var(--devic-bg-secondary)}.devic-conversation-item-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-item-date{color:var(--devic-text-muted);flex-shrink:0;font-size:11px;margin-left:8px}.devic-conversation-empty,.devic-conversation-loading{color:var(--devic-text-muted);font-size:13px;padding:12px;text-align:center}.devic-conversation-new{background:none;border:none;border-top:1px solid var(--devic-border);color:var(--devic-primary);cursor:pointer;display:block;font-family:var(--devic-font-family);font-size:13px;padding:10px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-new:hover{background:var(--devic-bg-secondary)}.devic-conversation-item-check{align-items:center;color:var(--devic-primary);display:flex;flex-shrink:0;margin-right:6px}.devic-message-bubble h1,.devic-message-bubble h2,.devic-message-bubble h3,.devic-message-bubble h4,.devic-message-bubble h5,.devic-message-bubble h6{line-height:1.3;margin:8px 0 4px}.devic-message-bubble h1{font-size:1.3em}.devic-message-bubble h2{font-size:1.2em}.devic-message-bubble h3{font-size:1.1em}.devic-message-bubble p{margin:4px 0}.devic-message-bubble ol,.devic-message-bubble ul{margin:4px 0;padding-left:20px}.devic-message-bubble code{background:rgba(0,0,0,.06);border-radius:3px;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:.9em;padding:1px 4px}.devic-message-bubble pre{background:rgba(0,0,0,.06);border-radius:var(--devic-radius-sm);margin:8px 0;overflow-x:auto;padding:10px}.devic-message-bubble pre code{background:none;padding:0}.devic-message-bubble blockquote{border-left:3px solid var(--devic-border);color:var(--devic-text-secondary);margin:4px 0;padding-left:12px}.devic-message-bubble a{color:var(--devic-primary);text-decoration:underline}.markdown-table{margin:8px 0;overflow-x:auto}.markdown-table table{border-collapse:collapse;font-size:13px;width:100%}.markdown-table td,.markdown-table th{border:1px solid var(--devic-border);padding:6px 10px;text-align:left}.markdown-table th{background:var(--devic-bg-secondary);font-weight:600}.devic-resize-handle{bottom:0;cursor:col-resize;position:absolute;top:0;width:6px;z-index:1}.devic-resize-handle[data-position=right]{left:0}.devic-resize-handle[data-position=left]{right:0}.devic-resize-handle:active,.devic-resize-handle:hover{background:var(--devic-primary);opacity:.3}@media (max-width:480px){.devic-chat-drawer{width:100%}}
1
+ .devic-message-actions{align-items:center;display:flex;gap:4px;opacity:0;transition:opacity .15s ease}.devic-message-actions:focus-within,.devic-message:hover .devic-message-actions{opacity:1}.devic-message-actions:has(.devic-action-btn--active){opacity:1}.devic-action-btn{align-items:center;background:transparent;border:none;border-radius:var(--devic-radius-sm,6px);color:var(--devic-text-muted,#94a3b8);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;transition:all .15s ease;width:28px}.devic-action-btn:hover:not(:disabled){background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-action-btn:disabled{cursor:not-allowed;opacity:.5}.devic-action-btn--active{color:var(--devic-primary,#3b82f6)}.devic-action-btn--active.devic-action-btn--positive{color:#22c55e}.devic-action-btn--active.devic-action-btn--negative{color:#ef4444}.devic-feedback-overlay{align-items:center;animation:devic-feedback-fade-in .15s ease;background:rgba(0,0,0,.4);bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:10001}@keyframes devic-feedback-fade-in{0%{opacity:0}to{opacity:1}}.devic-feedback-modal{animation:devic-feedback-slide-up .2s ease;background:var(--devic-bg,#fff);border-radius:var(--devic-radius,12px);box-shadow:0 20px 60px rgba(0,0,0,.2);margin:16px;max-width:400px;width:100%}@keyframes devic-feedback-slide-up{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.devic-feedback-modal-header{align-items:center;border-bottom:1px solid var(--devic-border,#e2e8f0);display:flex;gap:10px;padding:16px 16px 12px}.devic-feedback-modal-icon{align-items:center;background:var(--devic-bg-secondary,#f8fafc);border-radius:8px;color:var(--devic-text,#1e293b);display:flex;height:32px;justify-content:center;width:32px}.devic-feedback-modal-title{color:var(--devic-text,#1e293b);flex:1;font-size:15px;font-weight:600}.devic-feedback-modal-close{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--devic-text-muted,#94a3b8);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;transition:all .15s ease;width:28px}.devic-feedback-modal-close:hover{background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-feedback-textarea{background:transparent;border:none;border-bottom:1px solid var(--devic-border,#e2e8f0);box-sizing:border-box;color:var(--devic-text,#1e293b);display:block;font-family:inherit;font-size:14px;line-height:1.5;padding:12px 16px;resize:none;width:100%}.devic-feedback-textarea:focus{outline:none}.devic-feedback-textarea::placeholder{color:var(--devic-text-muted,#94a3b8)}.devic-feedback-modal-actions{display:flex;gap:8px;justify-content:flex-end;padding:12px 16px}.devic-feedback-btn{border:none;border-radius:var(--devic-radius-sm,6px);cursor:pointer;font-family:inherit;font-size:14px;font-weight:500;padding:8px 16px;transition:all .15s ease}.devic-feedback-btn:disabled{cursor:not-allowed;opacity:.6}.devic-feedback-btn--secondary{background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-feedback-btn--secondary:hover:not(:disabled){background:var(--devic-border,#e2e8f0)}.devic-feedback-btn--primary{background:var(--devic-primary,#3b82f6);color:#fff}.devic-feedback-btn--primary:hover:not(:disabled){background:var(--devic-primary-hover,#2563eb)}.devic-cmd-result-actions{border-top:1px solid var(--devic-cmd-border,var(--devic-border,#e5e7eb));margin-top:8px;padding-top:8px}.devic-cmd-result-actions .devic-message-actions{opacity:1;padding-left:10px}.devic-cmd-result-actions .devic-action-btn{opacity:.7}.devic-cmd-result-actions .devic-action-btn--active,.devic-cmd-result-actions .devic-action-btn:hover{opacity:1}.devic-chat-drawer{--devic-primary:#1890ff;--devic-primary-hover:#40a9ff;--devic-primary-light:#e6f7ff;--devic-bg:#fff;--devic-bg-secondary:#f5f5f5;--devic-text:#333;--devic-text-secondary:#666;--devic-text-muted:#999;--devic-border:#e8e8e8;--devic-shadow:0 4px 12px rgba(0,0,0,.15);--devic-radius:8px;--devic-radius-sm:4px;--devic-radius-lg:16px;--devic-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--devic-transition:0.3s ease;background:var(--devic-bg);bottom:0;box-shadow:var(--devic-shadow);color:var(--devic-text);display:flex;flex-direction:column;font-family:var(--devic-font-family);font-size:14px;line-height:1.5;position:fixed;top:0;transition:transform var(--devic-transition)}.devic-chat-drawer[data-position=right]{right:0;transform:translateX(100%)}.devic-chat-drawer[data-position=left]{left:0;transform:translateX(-100%)}.devic-chat-drawer[data-open=true]{transform:translateX(0)}.devic-drawer-overlay{background:rgba(0,0,0,.3);inset:0;opacity:0;position:fixed;transition:opacity var(--devic-transition),visibility var(--devic-transition);visibility:hidden}.devic-drawer-overlay[data-open=true]{opacity:1;visibility:visible}.devic-drawer-header{align-items:center;border-bottom:1px solid var(--devic-border);display:flex;flex-shrink:0;justify-content:space-between;padding:16px}.devic-drawer-avatar{border-radius:50%;flex-shrink:0;height:28px;object-fit:cover;width:28px}.devic-drawer-title{font-size:16px;font-weight:600;margin:0}.devic-drawer-close{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-drawer-close:hover{background:var(--devic-bg-secondary);color:var(--devic-text)}.devic-messages-container{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.devic-welcome{color:var(--devic-text-secondary);padding:24px 16px;text-align:center}.devic-welcome-text{font-size:16px;margin-bottom:16px}.devic-suggested-messages{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}.devic-suggested-btn{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-lg);color:var(--devic-text);cursor:pointer;font-size:13px;padding:8px 16px;transition:border-color var(--devic-transition),background var(--devic-transition)}.devic-suggested-btn:hover{background:var(--devic-primary-light);border-color:var(--devic-primary)}.devic-message{display:flex;flex-direction:column;max-width:85%}.devic-message[data-role=user]{align-self:flex-end}.devic-message[data-role=assistant],.devic-message[data-role=tool]{align-self:flex-start}.devic-message-bubble{word-wrap:break-word;border-radius:var(--devic-radius);padding:10px 14px}.devic-message[data-role=user] .devic-message-bubble{background:var(--devic-user-bubble,var(--devic-primary));border-bottom-right-radius:var(--devic-radius-sm);color:var(--devic-user-bubble-text,#fff)}.devic-message[data-role=assistant] .devic-message-bubble{background:var(--devic-assistant-bubble,var(--devic-bg-secondary));border-bottom-left-radius:var(--devic-radius-sm);color:var(--devic-assistant-bubble-text,var(--devic-text))}.devic-message[data-role=tool] .devic-message-bubble{background:var(--devic-primary-light);border:1px solid var(--devic-primary);color:var(--devic-text);font-size:12px}.devic-message-footer{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-top:4px}.devic-message-time{color:var(--devic-text-muted);font-size:11px}.devic-message[data-role=user] .devic-message-footer{justify-content:flex-end}.devic-message[data-role=user] .devic-message-time{text-align:right}.devic-message-files{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}.devic-message-file{align-items:center;background:hsla(0,0%,100%,.2);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:6px 10px}.devic-loading{align-self:flex-start;display:flex;gap:4px;padding:10px 14px}.devic-loading-dot{animation:devic-bounce 1.4s ease-in-out infinite both;background:var(--devic-text-muted);border-radius:50%;height:8px;width:8px}.devic-loading-dot:first-child{animation-delay:-.32s}.devic-loading-dot:nth-child(2){animation-delay:-.16s}@keyframes devic-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.devic-tool-group{align-self:flex-start;display:flex;flex-direction:column;gap:2px;max-width:85%}.devic-tool-activity{align-items:flex-start;animation:devic-slideUp .3s ease-out;display:flex;gap:8px;padding:4px 0}.devic-tool-activity-icon{align-items:center;color:var(--devic-text-muted);display:flex;flex-shrink:0;margin-top:1px}.devic-tool-activity--active .devic-tool-activity-icon{color:var(--devic-primary)}.devic-tool-activity-text{color:var(--devic-text-secondary);font-size:13px;line-height:1.4}.devic-glow-text{animation:devic-pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes devic-pulse{0%,to{opacity:1}50%{opacity:.5}}.devic-spinner{animation:devic-spin 1s linear infinite}@keyframes devic-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes devic-slideUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.devic-tool-collapse-btn{align-items:center;background:none;border:none;color:var(--devic-text-muted);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:12px;gap:6px;padding:4px 0;transition:color .2s ease}.devic-tool-collapse-btn:hover{color:var(--devic-primary)}.devic-tool-group-items{animation:devic-expandItems .4s ease-out;overflow:hidden}.devic-tool-group-items[data-expanded=true]{max-height:500px}@keyframes devic-expandItems{0%{max-height:0;opacity:0}to{max-height:500px;opacity:1}}.devic-input-area{border-top:1px solid var(--devic-border);flex-shrink:0;padding:16px}.devic-input-wrapper{align-items:flex-end;background:var(--devic-bg-secondary);border-radius:var(--devic-radius);display:flex;gap:8px;padding:8px 12px}.devic-input{background:none;border:none;color:var(--devic-text);flex:1;font-family:inherit;font-size:14px;line-height:1.5;max-height:120px;min-height:24px;outline:none;resize:none}.devic-input::placeholder{color:var(--devic-text-muted)}.devic-input-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;flex-shrink:0;padding:4px;transition:color var(--devic-transition)}.devic-input-btn:hover:not(:disabled){color:var(--devic-primary)}.devic-input-btn:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn{background:var(--devic-send-btn,var(--devic-primary));border-radius:var(--devic-radius-sm);color:#fff;padding:6px 12px}.devic-send-btn-wrapper{flex-shrink:0;position:relative}.devic-send-btn-custom{align-items:center;display:flex;justify-content:center;pointer-events:none}.devic-send-btn-overlay{background:transparent;border:none;cursor:pointer;inset:0;margin:0;padding:0;position:absolute}.devic-send-btn-overlay:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn:hover:not(:disabled){background:var(--devic-primary-hover);color:#fff}.devic-file-preview{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.devic-file-preview-item{align-items:center;background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:4px 8px}.devic-file-remove{background:none;border:none;color:var(--devic-text-muted);cursor:pointer;font-size:16px;line-height:1;padding:0}.devic-file-remove:hover{color:#ff4d4f}.devic-trigger{align-items:center;background:var(--devic-primary);border:none;border-radius:50%;box-shadow:var(--devic-shadow);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;position:fixed;transition:background var(--devic-transition),transform var(--devic-transition);width:56px}.devic-trigger:hover{background:var(--devic-primary-hover);transform:scale(1.05)}.devic-trigger svg{height:24px;width:24px}.devic-error{background:#fff2f0;border:1px solid #ffccc7;border-radius:var(--devic-radius);color:#ff4d4f;font-size:13px;margin:8px 16px;padding:12px}.devic-messages-container::-webkit-scrollbar{width:6px}.devic-messages-container::-webkit-scrollbar-track{background:transparent}.devic-messages-container::-webkit-scrollbar-thumb{background:var(--devic-border);border-radius:3px}.devic-messages-container::-webkit-scrollbar-thumb:hover{background:var(--devic-text-muted)}.devic-chat-drawer[data-mode=inline]{border:1px solid var(--devic-border);bottom:auto;box-shadow:none;height:100%;left:auto;position:relative;right:auto;top:auto;transform:none}.devic-drawer-header-actions{align-items:center;display:flex;gap:4px;margin-left:auto}.devic-new-chat-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-new-chat-btn:hover{background:var(--devic-bg-secondary);color:var(--devic-primary)}.devic-conversation-selector{flex:1;margin:0 8px;min-width:0;position:relative}.devic-conversation-selector-trigger{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;gap:6px;padding:6px 10px;text-align:left;transition:border-color var(--devic-transition);width:100%}.devic-conversation-selector-trigger:hover{border-color:var(--devic-primary)}.devic-conversation-selector-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-dropdown{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius);box-shadow:var(--devic-shadow);display:flex;flex-direction:column;left:0;max-height:320px;position:absolute;right:0;top:calc(100% + 4px);z-index:10}.devic-conversation-search-wrapper{border-bottom:1px solid var(--devic-border);padding:8px}.devic-conversation-search{background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);box-sizing:border-box;color:var(--devic-text);font-family:var(--devic-font-family);font-size:13px;outline:none;padding:6px 8px;width:100%}.devic-conversation-search:focus{border-color:var(--devic-primary)}.devic-conversation-list{flex:1;overflow-y:auto}.devic-conversation-item{align-items:center;background:none;border:none;color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;justify-content:space-between;padding:8px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-item:hover,.devic-conversation-item[data-active=true]{background:var(--devic-bg-secondary)}.devic-conversation-item-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-item-date{color:var(--devic-text-muted);flex-shrink:0;font-size:11px;margin-left:8px}.devic-conversation-empty,.devic-conversation-loading{color:var(--devic-text-muted);font-size:13px;padding:12px;text-align:center}.devic-conversation-new{background:none;border:none;border-top:1px solid var(--devic-border);color:var(--devic-primary);cursor:pointer;display:block;font-family:var(--devic-font-family);font-size:13px;padding:10px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-new:hover{background:var(--devic-bg-secondary)}.devic-conversation-item-check{align-items:center;color:var(--devic-primary);display:flex;flex-shrink:0;margin-right:6px}.devic-message-bubble h1,.devic-message-bubble h2,.devic-message-bubble h3,.devic-message-bubble h4,.devic-message-bubble h5,.devic-message-bubble h6{line-height:1.3;margin:8px 0 4px}.devic-message-bubble h1{font-size:1.3em}.devic-message-bubble h2{font-size:1.2em}.devic-message-bubble h3{font-size:1.1em}.devic-message-bubble p{margin:4px 0}.devic-message-bubble ol,.devic-message-bubble ul{margin:4px 0;padding-left:20px}.devic-message-bubble code{background:rgba(0,0,0,.06);border-radius:3px;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:.9em;padding:1px 4px}.devic-message-bubble pre{background:rgba(0,0,0,.06);border-radius:var(--devic-radius-sm);margin:8px 0;overflow-x:auto;padding:10px}.devic-message-bubble pre code{background:none;padding:0}.devic-message-bubble blockquote{border-left:3px solid var(--devic-border);color:var(--devic-text-secondary);margin:4px 0;padding-left:12px}.devic-message-bubble a{color:var(--devic-primary);text-decoration:underline}.markdown-table{margin:8px 0;overflow-x:auto}.markdown-table table{border-collapse:collapse;font-size:13px;width:100%}.markdown-table td,.markdown-table th{border:1px solid var(--devic-border);padding:6px 10px;text-align:left}.markdown-table th{background:var(--devic-bg-secondary);font-weight:600}.devic-resize-handle{bottom:0;cursor:col-resize;position:absolute;top:0;width:6px;z-index:1}.devic-resize-handle[data-position=right]{left:0}.devic-resize-handle[data-position=left]{right:0}.devic-resize-handle:active,.devic-resize-handle:hover{background:var(--devic-primary);opacity:.3}@media (max-width:480px){.devic-chat-drawer{width:100%}}.devic-command-bar-container{--devic-cmd-bg:var(--devic-cmd-bg-override,#fff);--devic-cmd-text:var(--devic-cmd-text-override,#1f2937);--devic-cmd-text-secondary:var(--devic-cmd-text-secondary-override,#6b7280);--devic-cmd-border:var(--devic-cmd-border-override,#e5e7eb);--devic-cmd-radius:var(--devic-cmd-radius-override,12px);--devic-cmd-shadow:var(--devic-cmd-shadow-override,0 4px 20px rgba(0,0,0,.1));--devic-cmd-primary:var(--devic-cmd-primary-override,#3b82f6);--devic-cmd-font-family:var(--devic-cmd-font-family-override,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);--devic-cmd-font-size:var(--devic-cmd-font-size-override,14px);--devic-cmd-animation-duration:var(--devic-cmd-animation-duration-override,200ms);color:var(--devic-cmd-text);display:flex;flex-direction:column;font-family:var(--devic-cmd-font-family);font-size:var(--devic-cmd-font-size);gap:8px;max-width:100%;width:400px}.devic-command-bar-container[data-position=fixed]{position:fixed}.devic-command-bar-container[data-position=inline]{position:relative}.devic-command-bar-container[data-visible=false]{opacity:0;pointer-events:none;transform:translateY(8px)}.devic-command-bar-container[data-visible=false],.devic-command-bar-container[data-visible=true]{transition:opacity var(--devic-cmd-animation-duration) ease,transform var(--devic-cmd-animation-duration) ease}.devic-command-bar-container[data-visible=true]{opacity:1;transform:translateY(0)}.devic-command-bar{align-items:center;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);display:flex;gap:12px;padding:12px 16px}.devic-command-bar-icon{align-items:center;color:var(--devic-cmd-text-secondary);display:flex;flex-shrink:0;height:20px;justify-content:center;width:20px}.devic-command-bar-icon svg{height:100%;width:100%}.devic-command-bar-input{background:transparent;border:none;color:inherit;flex:1;font-family:inherit;font-size:inherit;min-width:0;outline:none}.devic-command-bar-input::placeholder{color:var(--devic-cmd-text-secondary)}.devic-command-bar-summary{animation:devic-cmd-pulse 1.5s ease-in-out infinite;color:var(--devic-cmd-text-secondary);flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@keyframes devic-cmd-pulse{0%,to{opacity:1}50%{opacity:.6}}.devic-command-bar-shortcut{background:var(--devic-cmd-border);border-radius:6px;color:var(--devic-cmd-text-secondary);flex-shrink:0;font-size:12px;font-weight:500;letter-spacing:.5px;padding:4px 8px}.devic-command-bar-spinner{animation:devic-cmd-spin .8s linear infinite;border:2px solid var(--devic-cmd-border);border-radius:50%;border-top-color:var(--devic-cmd-primary);height:20px;width:20px}@keyframes devic-cmd-spin{to{transform:rotate(1turn)}}.devic-command-bar-result{animation:devic-cmd-slide-up .2s ease-out;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);overflow:hidden}@keyframes devic-cmd-slide-up{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.devic-command-bar-result-tools{border-bottom:1px solid var(--devic-cmd-border)}.devic-command-bar-result-tools-header{align-items:center;color:var(--devic-cmd-text-secondary);cursor:pointer;display:flex;font-size:13px;gap:8px;padding:10px 14px;transition:background .15s ease;user-select:none}.devic-command-bar-result-tools-header:hover{background:rgba(0,0,0,.02)}.devic-command-bar-result-tools-chevron{height:16px;transition:transform .2s ease;width:16px}.devic-command-bar-result-tools-header[data-expanded=true] .devic-command-bar-result-tools-chevron{transform:rotate(90deg)}.devic-command-bar-result-tools-count{align-items:center;background:var(--devic-cmd-primary);border-radius:10px;color:#fff;display:inline-flex;font-size:11px;font-weight:600;height:20px;justify-content:center;min-width:20px;padding:0 6px}.devic-command-bar-result-tools-list{display:flex;flex-direction:column;gap:6px;padding:8px 14px 12px}.devic-command-bar-result-tools-list[data-expanded=false]{display:none}.devic-command-bar-result-tool-item{align-items:center;background:rgba(0,0,0,.02);border-radius:6px;display:flex;font-size:12px;gap:8px;padding:6px 10px}.devic-command-bar-result-tool-icon{color:#10b981;height:14px;width:14px}.devic-command-bar-result-tool-name{color:var(--devic-cmd-text-secondary)}.devic-command-bar-result-message{line-height:1.5;max-height:300px;overflow-y:auto;padding:14px}.devic-command-bar-result-message::-webkit-scrollbar{width:6px}.devic-command-bar-result-message::-webkit-scrollbar-track{background:transparent}.devic-command-bar-result-message::-webkit-scrollbar-thumb{background:var(--devic-cmd-border);border-radius:3px}.devic-command-bar-error{background:#fef2f2;border:1px solid #fecaca;border-radius:var(--devic-cmd-radius);color:#dc2626;font-size:13px;padding:10px 14px}.devic-command-bar-result-empty{color:var(--devic-cmd-text-secondary);font-size:13px;padding:14px;text-align:center}.devic-command-bar-dropdown{animation:devic-cmd-slide-up .2s ease-out;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);overflow:hidden}.devic-command-bar-dropdown-header{align-items:center;border-bottom:1px solid var(--devic-cmd-border);color:var(--devic-cmd-text-secondary);display:flex;font-size:12px;font-weight:600;justify-content:space-between;letter-spacing:.5px;padding:10px 14px;text-transform:uppercase}.devic-command-bar-dropdown-hint{align-items:center;display:flex;font-weight:400;gap:4px;letter-spacing:0;text-transform:none}.devic-command-bar-dropdown-hint kbd{align-items:center;background:var(--devic-cmd-border);border-radius:4px;display:inline-flex;font-family:inherit;font-size:10px;height:18px;justify-content:center;min-width:18px;padding:0 4px}.devic-command-bar-dropdown-clear{background:none;border:none;border-radius:4px;color:var(--devic-cmd-primary);cursor:pointer;font-family:inherit;font-size:12px;font-weight:500;letter-spacing:0;padding:2px 6px;text-transform:none}.devic-command-bar-dropdown-clear:hover{background:rgba(0,0,0,.05)}.devic-command-bar-dropdown-list{max-height:250px;overflow-y:auto}.devic-command-bar-dropdown-list::-webkit-scrollbar{width:6px}.devic-command-bar-dropdown-list::-webkit-scrollbar-track{background:transparent}.devic-command-bar-dropdown-list::-webkit-scrollbar-thumb{background:var(--devic-cmd-border);border-radius:3px}.devic-command-bar-dropdown-item{align-items:center;cursor:pointer;display:flex;gap:10px;padding:10px 14px;transition:background .15s ease}.devic-command-bar-dropdown-item:hover,.devic-command-bar-dropdown-item[data-selected=true]{background:rgba(0,0,0,.04)}.devic-command-bar-dropdown-item[data-selected=true]{background:var(--devic-cmd-primary);background:rgba(59,130,246,.1)}.devic-command-bar-dropdown-icon{align-items:center;color:var(--devic-cmd-text-secondary);display:flex;flex-shrink:0;height:16px;justify-content:center;width:16px}.devic-command-bar-dropdown-keyword{color:var(--devic-cmd-text);flex-shrink:0;font-weight:600}.devic-command-bar-dropdown-desc{color:var(--devic-cmd-text-secondary);flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-command-bar-dropdown-empty{color:var(--devic-cmd-text-secondary);font-size:13px;padding:20px 14px;text-align:center}.devic-command-bar-history-item{border-bottom:1px solid rgba(0,0,0,.04)}.devic-command-bar-history-item:last-child{border-bottom:none}.devic-command-bar-history-text{flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devicai/ui",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "React component library for Devic AI assistants",
6
6
  "engines": {