vox-ai-react 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,111 +1,136 @@
1
- # vox-ai-react
2
-
3
- Official React component for VOX AI Chat Widget.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install vox-ai-react
9
- # or
10
- yarn add vox-ai-react
11
- # or
12
- pnpm add vox-ai-react
13
- ```
14
-
15
- ## Quick Start
16
-
17
- ```jsx
18
- import { VoxChat } from 'vox-ai-react';
19
-
20
- function App() {
21
- return (
22
- <div>
23
- <h1>My Website</h1>
24
- <VoxChat
25
- apiKey="vox_live_xxxxxxxx"
26
- geminiApiKey="your-gemini-api-key"
27
- apiUrl="https://voxai.zeabur.app"
28
- />
29
- </div>
30
- );
31
- }
32
- ```
33
-
34
- ## Using Server-Stored Configuration
35
-
36
- You can configure your agent (name, system instruction, voice) in the VOX Dashboard, and the widget will automatically use those settings:
37
-
38
- ```jsx
39
- <VoxChat
40
- apiKey="vox_live_xxxxxxxx"
41
- geminiApiKey="your-gemini-api-key"
42
- apiUrl="https://voxai.zeabur.app"
43
- useServerConfig={true} // Fetches config from your VOX account
44
- />
45
- ```
46
-
47
- ## Props
48
-
49
- | Prop | Type | Default | Description |
50
- |------|------|---------|-------------|
51
- | `apiKey` | `string` | Required | Your VOX API key |
52
- | `geminiApiKey` | `string` | Required | Your Gemini API key (for voice) |
53
- | `apiUrl` | `string` | Required | VOX API server URL |
54
- | `agentName` | `string` | `'VOX-01'` | Display name for the agent |
55
- | `voiceName` | `string` | `'Kore'` | Voice name for voice chat |
56
- | `systemInstruction` | `string` | `'You are a helpful AI assistant.'` | System instruction for the AI |
57
- | `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Widget position |
58
- | `theme` | `'dark' \| 'light'` | `'dark'` | Color theme |
59
- | `buttonColor` | `string` | Theme default | Custom button background color |
60
- | `buttonSize` | `number` | `56` | Button size in pixels |
61
- | `borderRadius` | `number` | `0` | Button border radius in pixels |
62
- | `iconColor` | `string` | Theme default | Custom icon color |
63
- | `useServerConfig` | `boolean` | `false` | Fetch agent config from server |
64
- | `onOpen` | `() => void` | - | Callback when chat opens |
65
- | `onClose` | `() => void` | - | Callback when chat closes |
66
-
67
- ## Customization Examples
68
-
69
- ### Custom Colors
70
-
71
- ```jsx
72
- <VoxChat
73
- apiKey="vox_live_xxxxxxxx"
74
- geminiApiKey="your-gemini-api-key"
75
- apiUrl="https://voxai.zeabur.app"
76
- buttonColor="#6366f1"
77
- iconColor="#ffffff"
78
- borderRadius={24}
79
- />
80
- ```
81
-
82
- ### Light Theme
83
-
84
- ```jsx
85
- <VoxChat
86
- apiKey="vox_live_xxxxxxxx"
87
- geminiApiKey="your-gemini-api-key"
88
- apiUrl="https://voxai.zeabur.app"
89
- theme="light"
90
- />
91
- ```
92
-
93
- ### With Callbacks
94
-
95
- ```jsx
96
- <VoxChat
97
- apiKey="vox_live_xxxxxxxx"
98
- geminiApiKey="your-gemini-api-key"
99
- apiUrl="https://voxai.zeabur.app"
100
- onOpen={() => console.log('Chat opened')}
101
- onClose={() => console.log('Chat closed')}
102
- />
103
- ```
104
-
105
- ## Get Your API Key
106
-
107
- Visit the VOX Dashboard to get your API key and configure your agent.
108
-
109
- ## License
110
-
111
- MIT
1
+ # vox-ai-react
2
+
3
+ Official React component for VOX AI Chat Widget.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install vox-ai-react
9
+ # or
10
+ yarn add vox-ai-react
11
+ # or
12
+ pnpm add vox-ai-react
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```jsx
18
+ import { VoxChat } from 'vox-ai-react';
19
+
20
+ function App() {
21
+ return (
22
+ <div>
23
+ <h1>My Website</h1>
24
+ <VoxChat
25
+ apiKey="vox_live_xxxxxxxx"
26
+ geminiApiKey="your-gemini-api-key"
27
+ apiUrl="https://voxai.zeabur.app"
28
+ />
29
+ </div>
30
+ );
31
+ }
32
+ ```
33
+
34
+ ## Using Server-Stored Configuration (Real-Time)
35
+
36
+ You can configure your agent (name, system instruction, voice, logo, colors, etc.) in the VOX Dashboard, and the widget will automatically use those settings. The widget polls for updates every 10 seconds, so changes you make in the dashboard appear in real-time on your website!
37
+
38
+ ```jsx
39
+ <VoxChat
40
+ apiKey="vox_live_xxxxxxxx"
41
+ geminiApiKey="your-gemini-api-key"
42
+ apiUrl="https://voxai.zeabur.app"
43
+ useServerConfig={true} // Fetches config from your VOX account
44
+ />
45
+ ```
46
+
47
+ ### Custom Polling Interval
48
+
49
+ By default, the widget checks for configuration updates every 10 seconds. You can customize this:
50
+
51
+ ```jsx
52
+ <VoxChat
53
+ apiKey="vox_live_xxxxxxxx"
54
+ geminiApiKey="your-gemini-api-key"
55
+ apiUrl="https://voxai.zeabur.app"
56
+ useServerConfig={true}
57
+ configPollInterval={5000} // Check every 5 seconds
58
+ />
59
+ ```
60
+
61
+ **What gets synced in real-time:**
62
+ - Agent name
63
+ - System instructions
64
+ - Voice settings
65
+ - Custom logo
66
+ - Button colors
67
+ - Button size
68
+ - Border radius
69
+ - Widget position
70
+
71
+ ## Props
72
+
73
+ | Prop | Type | Default | Description |
74
+ |------|------|---------|-------------|
75
+ | `apiKey` | `string` | Required | Your VOX API key |
76
+ | `geminiApiKey` | `string` | Required | Your Gemini API key (for voice) |
77
+ | `apiUrl` | `string` | Required | VOX API server URL |
78
+ | `agentName` | `string` | `'VOX-01'` | Display name for the agent |
79
+ | `voiceName` | `string` | `'Kore'` | Voice name for voice chat |
80
+ | `systemInstruction` | `string` | `'You are a helpful AI assistant.'` | System instruction for the AI |
81
+ | `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Widget position |
82
+ | `theme` | `'dark' \| 'light'` | `'dark'` | Color theme |
83
+ | `buttonColor` | `string` | Theme default | Custom button background color |
84
+ | `buttonSize` | `number` | `56` | Button size in pixels |
85
+ | `borderRadius` | `number` | `0` | Button border radius in pixels |
86
+ | `iconColor` | `string` | Theme default | Custom icon color |
87
+ | `useServerConfig` | `boolean` | `false` | Fetch agent config from server |
88
+ | `configPollInterval` | `number` | `10000` | Config polling interval in ms (when useServerConfig is true) |
89
+ | `onOpen` | `() => void` | - | Callback when chat opens |
90
+ | `onClose` | `() => void` | - | Callback when chat closes |
91
+
92
+ ## Customization Examples
93
+
94
+ ### Custom Colors
95
+
96
+ ```jsx
97
+ <VoxChat
98
+ apiKey="vox_live_xxxxxxxx"
99
+ geminiApiKey="your-gemini-api-key"
100
+ apiUrl="https://voxai.zeabur.app"
101
+ buttonColor="#6366f1"
102
+ iconColor="#ffffff"
103
+ borderRadius={24}
104
+ />
105
+ ```
106
+
107
+ ### Light Theme
108
+
109
+ ```jsx
110
+ <VoxChat
111
+ apiKey="vox_live_xxxxxxxx"
112
+ geminiApiKey="your-gemini-api-key"
113
+ apiUrl="https://voxai.zeabur.app"
114
+ theme="light"
115
+ />
116
+ ```
117
+
118
+ ### With Callbacks
119
+
120
+ ```jsx
121
+ <VoxChat
122
+ apiKey="vox_live_xxxxxxxx"
123
+ geminiApiKey="your-gemini-api-key"
124
+ apiUrl="https://voxai.zeabur.app"
125
+ onOpen={() => console.log('Chat opened')}
126
+ onClose={() => console.log('Chat closed')}
127
+ />
128
+ ```
129
+
130
+ ## Get Your API Key
131
+
132
+ Visit the VOX Dashboard to get your API key and configure your agent.
133
+
134
+ ## License
135
+
136
+ MIT
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export interface VoxChatProps {
15
15
  onOpen?: () => void;
16
16
  onClose?: () => void;
17
17
  useServerConfig?: boolean;
18
+ configPollInterval?: number;
18
19
  }
19
20
  export declare const VoxChat: React.FC<VoxChatProps>;
20
21
  export default VoxChat;
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
- import { useState, useEffect, useRef, useCallback } from 'react';
2
+ import { useState, useCallback, useEffect, useRef } from 'react';
3
3
 
4
4
  var ConnectionState;
5
5
  (function (ConnectionState) {
@@ -50,7 +50,7 @@ const AlertCircleIcon = () => (jsxs("svg", { width: "14", height: "14", viewBox:
50
50
  // Visualizer Component
51
51
  const Visualizer = ({ analyser, isActive }) => {
52
52
  const canvasRef = useRef(null);
53
- const animationRef = useRef();
53
+ const animationRef = useRef(undefined);
54
54
  useEffect(() => {
55
55
  const canvas = canvasRef.current;
56
56
  if (!canvas)
@@ -413,15 +413,16 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
413
413
  }, children: [jsx(PhoneOffIcon, {}), "End Call"] }))] }));
414
414
  };
415
415
  // Main VoxChat Component
416
- const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', agentName: propAgentName = 'VOX-01', voiceName: propVoiceName = 'Kore', systemInstruction: propSystemInstruction = 'You are a helpful AI assistant.', position = 'bottom-right', theme = 'dark', buttonColor, buttonSize = 56, borderRadius = 0, iconColor, onOpen, onClose, useServerConfig = false }) => {
416
+ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', agentName: propAgentName = 'VOX-01', voiceName: propVoiceName = 'Kore', systemInstruction: propSystemInstruction = 'You are a helpful AI assistant.', position = 'bottom-right', theme = 'dark', buttonColor, buttonSize = 56, borderRadius = 0, iconColor, onOpen, onClose, useServerConfig = false, configPollInterval = 10000 }) => {
417
+ var _a, _b, _c, _d, _e, _f;
417
418
  const [isOpen, setIsOpen] = useState(false);
418
419
  const [activeTab, setActiveTab] = useState('text');
419
420
  const [isVoiceActive, setIsVoiceActive] = useState(false);
420
421
  // Server config state
421
422
  const [serverConfig, setServerConfig] = useState(null);
422
423
  const [configLoaded, setConfigLoaded] = useState(!useServerConfig);
423
- // Fetch config from server if useServerConfig is true
424
- useEffect(() => {
424
+ // Fetch config from server
425
+ const fetchConfig = useCallback(() => {
425
426
  if (useServerConfig && apiKey && apiUrl) {
426
427
  fetch(`${apiUrl}/api/v1/config`, {
427
428
  headers: { 'x-api-key': apiKey }
@@ -439,10 +440,28 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
439
440
  });
440
441
  }
441
442
  }, [useServerConfig, apiKey, apiUrl]);
443
+ // Initial fetch and real-time polling (every 10 seconds)
444
+ useEffect(() => {
445
+ if (useServerConfig && apiKey && apiUrl) {
446
+ // Fetch immediately
447
+ fetchConfig();
448
+ // Poll at specified interval for real-time updates
449
+ const intervalId = setInterval(fetchConfig, configPollInterval);
450
+ // Cleanup interval on unmount
451
+ return () => clearInterval(intervalId);
452
+ }
453
+ }, [useServerConfig, apiKey, apiUrl, fetchConfig, configPollInterval]);
442
454
  // Use server config if available, otherwise use props
443
455
  const agentName = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.name) || propAgentName;
444
456
  const voiceName = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.voiceName) || propVoiceName;
445
457
  const systemInstruction = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.systemInstruction) || propSystemInstruction;
458
+ // Widget style from server or props
459
+ const finalButtonColor = ((_a = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _a === void 0 ? void 0 : _a.buttonColor) || buttonColor || (theme === 'light' ? '#000000' : '#ffffff');
460
+ const finalButtonSize = ((_b = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _b === void 0 ? void 0 : _b.buttonSize) || buttonSize || 56;
461
+ const finalBorderRadius = ((_c = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _c === void 0 ? void 0 : _c.borderRadius) !== undefined ? serverConfig.widgetStyle.borderRadius : (borderRadius !== undefined ? borderRadius : 50);
462
+ const finalPosition = ((_d = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _d === void 0 ? void 0 : _d.position) || position || 'bottom-right';
463
+ const finalIconColor = ((_e = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _e === void 0 ? void 0 : _e.iconColor) || iconColor || (theme === 'light' ? '#ffffff' : '#000000');
464
+ const finalLogoUrl = (_f = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _f === void 0 ? void 0 : _f.logoUrl;
446
465
  const handleOpen = () => { setIsOpen(true); onOpen === null || onOpen === void 0 ? void 0 : onOpen(); };
447
466
  const handleClose = () => { setIsOpen(false); setIsVoiceActive(false); setActiveTab('text'); onClose === null || onClose === void 0 ? void 0 : onClose(); };
448
467
  const handleTabChange = (tab) => {
@@ -459,33 +478,32 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
459
478
  setIsVoiceActive(false);
460
479
  setActiveTab('text');
461
480
  };
462
- const positionStyles = position === 'bottom-left'
481
+ const positionStyles = finalPosition === 'bottom-left'
463
482
  ? { bottom: '16px', left: '16px' }
464
483
  : { bottom: '16px', right: '16px' };
465
- // Button colors based on theme
466
- const btnBg = buttonColor || (theme === 'light' ? '#000000' : '#ffffff');
467
- const btnIcon = iconColor || (theme === 'light' ? '#ffffff' : '#000000');
468
- return (jsxs(Fragment, { children: [jsx("style", { children: `
469
- @keyframes vox-fade-in { from { opacity: 0; transform: translateY(40px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
470
- @keyframes vox-spin { to { transform: rotate(360deg); } }
471
- @keyframes vox-ping { 0% { transform: scale(1); opacity: 0.5; } 50% { transform: scale(1.15); opacity: 0; } 100% { transform: scale(1); opacity: 0; } }
472
- .vox-widget { animation: vox-fade-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
473
- ` }), jsxs("div", { style: { position: 'fixed', zIndex: 10000, display: 'flex', flexDirection: 'column', alignItems: position === 'bottom-left' ? 'flex-start' : 'flex-end', gap: '24px', ...positionStyles }, children: [isOpen && (jsxs("div", { className: "vox-widget", style: {
474
- width: 'min(calc(100vw - 32px), 400px)', height: 'min(calc(100vh - 100px), 640px)', maxHeight: '640px',
484
+ return (jsxs(Fragment, { children: [jsx("style", { children: `
485
+ @keyframes vox-fade-in { from { opacity: 0; transform: translateY(40px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
486
+ @keyframes vox-spin { to { transform: rotate(360deg); } }
487
+ @keyframes vox-ping { 0% { transform: scale(1); opacity: 0.5; } 50% { transform: scale(1.15); opacity: 0; } 100% { transform: scale(1); opacity: 0; } }
488
+ .vox-widget { animation: vox-fade-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
489
+ ` }), jsxs("div", { style: { position: 'fixed', zIndex: 10000, display: 'flex', flexDirection: 'column', alignItems: finalPosition === 'bottom-left' ? 'flex-start' : 'flex-end', gap: '24px', ...positionStyles }, children: [isOpen && (jsxs("div", { className: "vox-widget", style: {
490
+ width: 'min(calc(100vw - 32px), 360px)', height: '550px', maxHeight: '550px',
475
491
  background: '#000000', overflow: 'hidden', display: 'flex', flexDirection: 'column',
476
- border: '1px solid #3f3f46', boxShadow: '0 30px 60px -15px rgba(0,0,0,0.5)'
477
- }, children: [jsxs("div", { style: { height: '56px', background: '#000000', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', flexShrink: 0, borderBottom: '1px solid #3f3f46' }, children: [jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '12px' }, children: [jsx("div", { style: { width: '32px', height: '32px', border: '1px solid #52525b', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#ffffff' }, children: jsx(MessageCircleIcon, {}) }), jsxs("div", { children: [jsx("h2", { style: { color: '#ffffff', fontWeight: 900, fontSize: '10px', textTransform: 'uppercase', letterSpacing: '0.2em', margin: 0 }, children: agentName }), jsxs("p", { style: { color: '#a1a1aa', fontSize: '9px', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', margin: 0, display: 'flex', alignItems: 'center' }, children: [jsx("span", { style: { width: '4px', height: '4px', background: '#ffffff', borderRadius: '50%', marginRight: '8px' } }), "Active"] })] })] }), jsx("button", { onClick: handleClose, style: { background: 'none', border: 'none', color: '#a1a1aa', cursor: 'pointer', padding: '4px', transition: 'color 0.2s' }, children: jsx(XIcon, {}) })] }), jsxs("div", { style: { display: 'flex', padding: '4px', background: '#18181b', borderBottom: '1px solid #3f3f46', flexShrink: 0 }, children: [jsx("button", { onClick: () => handleTabChange('text'), style: {
478
- flex: 1, padding: '12px', fontSize: '10px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.2em',
492
+ border: '1px solid #3f3f46', boxShadow: '0 20px 40px -10px rgba(0,0,0,0.5)', borderRadius: '12px'
493
+ }, children: [jsxs("div", { style: { height: '48px', background: '#000000', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', flexShrink: 0, borderBottom: '1px solid #3f3f46' }, children: [jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [jsx("div", { style: { width: '28px', height: '28px', border: '1px solid #52525b', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#ffffff' }, children: finalLogoUrl ? (jsx("img", { src: finalLogoUrl, alt: agentName, style: { width: '18px', height: '18px', objectFit: 'contain' } })) : (jsx(MessageCircleIcon, {})) }), jsxs("div", { children: [jsx("h2", { style: { color: '#ffffff', fontWeight: 900, fontSize: '9px', textTransform: 'uppercase', letterSpacing: '0.15em', margin: 0 }, children: agentName }), jsxs("p", { style: { color: '#a1a1aa', fontSize: '8px', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', margin: 0, display: 'flex', alignItems: 'center' }, children: [jsx("span", { style: { width: '3px', height: '3px', background: '#ffffff', borderRadius: '50%', marginRight: '6px' } }), "Active"] })] })] }), jsx("button", { onClick: handleClose, style: { background: 'none', border: 'none', color: '#a1a1aa', cursor: 'pointer', padding: '4px', transition: 'color 0.2s' }, children: jsx(XIcon, {}) })] }), jsxs("div", { style: { display: 'flex', padding: '2px', background: '#18181b', borderBottom: '1px solid #3f3f46', flexShrink: 0 }, children: [jsx("button", { onClick: () => handleTabChange('text'), style: {
494
+ flex: 1, padding: '8px', fontSize: '9px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.15em',
479
495
  background: 'none', border: 'none', cursor: 'pointer', color: activeTab === 'text' ? '#ffffff' : '#71717a', transition: 'color 0.2s'
480
496
  }, children: "Text Interface" }), jsx("div", { style: { width: '1px', background: '#3f3f46' } }), jsx("button", { onClick: () => handleTabChange('voice'), style: {
481
- flex: 1, padding: '12px', fontSize: '10px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.2em',
497
+ flex: 1, padding: '8px', fontSize: '9px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.15em',
482
498
  background: 'none', border: 'none', cursor: 'pointer', color: activeTab === 'voice' ? '#ffffff' : '#71717a', transition: 'color 0.2s'
483
499
  }, children: "Voice Protocol" })] }), jsx("div", { style: { flex: 1, overflow: 'hidden', position: 'relative', background: '#000000' }, children: activeTab === 'text' ? (jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction })) : (isVoiceActive ? (jsx(VoiceInterface, { geminiApiKey: geminiApiKey, voiceName: voiceName, systemInstruction: systemInstruction, onEndCall: handleEndCall })) : (jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction }))) })] })), !isOpen && (jsx("button", { onClick: handleOpen, style: {
484
- width: `${buttonSize}px`, height: `${buttonSize}px`, borderRadius: `${borderRadius}%`,
485
- background: btnBg, color: btnIcon, border: 'none', cursor: 'pointer',
500
+ width: `${finalButtonSize}px`, height: `${finalButtonSize}px`,
501
+ borderRadius: `${finalBorderRadius}px`,
502
+ background: finalButtonColor, color: finalIconColor, border: 'none', cursor: 'pointer',
486
503
  display: 'flex', alignItems: 'center', justifyContent: 'center',
487
- boxShadow: '0 4px 20px rgba(0,0,0,0.3)', transition: 'transform 0.2s'
488
- }, children: jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: jsx("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) }) }))] })] }));
504
+ boxShadow: '0 4px 20px rgba(0,0,0,0.3)',
505
+ transition: 'all 0.3s ease, transform 0.2s'
506
+ }, children: finalLogoUrl ? (jsx("img", { src: finalLogoUrl, alt: "Chat", style: { width: '60%', height: '60%', objectFit: 'contain', transition: 'opacity 0.3s ease' } })) : (jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: jsx("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) })) }))] })] }));
489
507
  };
490
508
 
491
509
  export { VoxChat, VoxChat as default };