acecoderz-chat-ui 1.0.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 (62) hide show
  1. package/README.md +309 -0
  2. package/browser/index.ts +15 -0
  3. package/dist/adapters/react/ChatUI.d.ts +32 -0
  4. package/dist/adapters/react/ChatUI.d.ts.map +1 -0
  5. package/dist/adapters/react/ChatUI.js +170 -0
  6. package/dist/adapters/react/index.d.ts +5 -0
  7. package/dist/adapters/react/index.d.ts.map +1 -0
  8. package/dist/adapters/react/index.js +2 -0
  9. package/dist/adapters/react/useChat.d.ts +14 -0
  10. package/dist/adapters/react/useChat.d.ts.map +1 -0
  11. package/dist/adapters/react/useChat.js +64 -0
  12. package/dist/adapters/solid/createChat.d.ts +13 -0
  13. package/dist/adapters/solid/createChat.d.ts.map +1 -0
  14. package/dist/adapters/solid/createChat.js +34 -0
  15. package/dist/adapters/solid/index.d.ts +3 -0
  16. package/dist/adapters/solid/index.d.ts.map +1 -0
  17. package/dist/adapters/solid/index.js +1 -0
  18. package/dist/adapters/vanilla/index.d.ts +31 -0
  19. package/dist/adapters/vanilla/index.d.ts.map +1 -0
  20. package/dist/adapters/vanilla/index.js +346 -0
  21. package/dist/browser/Archive.zip +0 -0
  22. package/dist/browser/cdn-example.html +177 -0
  23. package/dist/browser/chatbot-ui.css +508 -0
  24. package/dist/browser/chatbot-ui.js +878 -0
  25. package/dist/browser/chatbot-ui.js.map +7 -0
  26. package/dist/browser/chatbot-ui.min.js +71 -0
  27. package/dist/browser/chatbot.html +100 -0
  28. package/dist/core/src/ChatEngine.d.ts +30 -0
  29. package/dist/core/src/ChatEngine.d.ts.map +1 -0
  30. package/dist/core/src/ChatEngine.js +357 -0
  31. package/dist/core/src/apiLogger.d.ts +47 -0
  32. package/dist/core/src/apiLogger.d.ts.map +1 -0
  33. package/dist/core/src/apiLogger.js +199 -0
  34. package/dist/core/src/index.d.ts +7 -0
  35. package/dist/core/src/index.d.ts.map +1 -0
  36. package/dist/core/src/index.js +3 -0
  37. package/dist/core/src/types.d.ts +62 -0
  38. package/dist/core/src/types.d.ts.map +1 -0
  39. package/dist/core/src/types.js +1 -0
  40. package/dist/core/src/urlWhitelist.d.ts +19 -0
  41. package/dist/core/src/urlWhitelist.d.ts.map +1 -0
  42. package/dist/core/src/urlWhitelist.js +66 -0
  43. package/dist/src/ChatUI.stories.d.ts +37 -0
  44. package/dist/src/ChatUI.stories.d.ts.map +1 -0
  45. package/dist/src/ChatUI.stories.js +65 -0
  46. package/dist/src/ChatUIThemes.stories.d.ts +28 -0
  47. package/dist/src/ChatUIThemes.stories.d.ts.map +1 -0
  48. package/dist/src/ChatUIThemes.stories.js +109 -0
  49. package/dist/src/ThemeProperties.stories.d.ts +92 -0
  50. package/dist/src/ThemeProperties.stories.d.ts.map +1 -0
  51. package/dist/src/ThemeProperties.stories.js +195 -0
  52. package/dist/src/UseChat.stories.d.ts +21 -0
  53. package/dist/src/UseChat.stories.d.ts.map +1 -0
  54. package/dist/src/UseChat.stories.js +66 -0
  55. package/dist/src/VanillaAdapter.stories.d.ts +39 -0
  56. package/dist/src/VanillaAdapter.stories.d.ts.map +1 -0
  57. package/dist/src/VanillaAdapter.stories.js +78 -0
  58. package/dist/src/index.d.ts +9 -0
  59. package/dist/src/index.d.ts.map +1 -0
  60. package/dist/src/index.js +8 -0
  61. package/package.json +117 -0
  62. package/styles/chat.css +508 -0
package/README.md ADDED
@@ -0,0 +1,309 @@
1
+ # @chatbot/chat-ui
2
+
3
+ A framework-agnostic, fully customizable chat UI package that works with React, Solid, Vanilla JS, and any other framework.
4
+
5
+ ## Features
6
+
7
+ - 🎨 **Fully Customizable** - Theme via CSS variables or props
8
+ - 🔌 **Framework Agnostic** - Works with React, Solid, Vue, Svelte, and Vanilla JS
9
+ - 🚀 **Lightweight Core** - Zero framework dependencies in the core
10
+ - 💬 **Real-time Support** - WebSocket and HTTP API support
11
+ - 🎯 **TypeScript** - Full TypeScript support
12
+ - 📦 **Modular** - Import only what you need
13
+
14
+ ## Installation
15
+
16
+ ### npm/pnpm/yarn
17
+
18
+ ```bash
19
+ pnpm add @chatbot/chat-ui
20
+ # or
21
+ npm install @chatbot/chat-ui
22
+ # or
23
+ yarn add @chatbot/chat-ui
24
+ ```
25
+
26
+ ### Browser / CDN (Script Tag)
27
+
28
+ For browser usage without a build step, see [CDN.md](./CDN.md) for detailed documentation.
29
+
30
+ **Quick Start:**
31
+ ```html
32
+ <!-- Include CSS -->
33
+ <link rel="stylesheet" href="https://cdn.example.com/chatbot-ui.css">
34
+
35
+ <!-- Include JavaScript -->
36
+ <script src="https://cdn.example.com/chatbot-ui.min.js"></script>
37
+
38
+ <!-- Add container -->
39
+ <div id="chatbot-container"></div>
40
+
41
+ <!-- Initialize -->
42
+ <script>
43
+ ChatbotUI.init('chatbot-container', {
44
+ config: {
45
+ apiUrl: 'https://your-api.com/api/chat',
46
+ },
47
+ theme: {
48
+ primaryColor: '#3b82f6',
49
+ userMessageColor: '#3b82f6',
50
+ assistantMessageColor: '#f1f5f9',
51
+ },
52
+ });
53
+ </script>
54
+ ```
55
+
56
+ **Building for CDN:**
57
+ ```bash
58
+ # Build browser bundle
59
+ pnpm build:browser
60
+
61
+ # Output files will be in dist/browser/:
62
+ # - chatbot-ui.min.js (production)
63
+ # - chatbot-ui.js (development)
64
+ # - chatbot-ui.css (styles)
65
+ # - cdn-example.html (example file)
66
+ ```
67
+
68
+ ### Iframe Embedding
69
+
70
+ After building, you can embed the chatbot in an iframe:
71
+
72
+ ```html
73
+ <iframe
74
+ src="https://cdn.example.com/chatbot.html?apiUrl=https://your-api.com/api/chat"
75
+ width="400"
76
+ height="600"
77
+ frameborder="0">
78
+ </iframe>
79
+ ```
80
+
81
+ ## CSS Setup
82
+
83
+ Import the CSS file in your project:
84
+
85
+ ```css
86
+ @import '@chatbot/chat-ui/styles';
87
+ ```
88
+
89
+ Or in your JavaScript/TypeScript:
90
+
91
+ ```javascript
92
+ import '@chatbot/chat-ui/styles';
93
+ ```
94
+
95
+ ## Usage
96
+
97
+ ### React
98
+
99
+ ```tsx
100
+ import { ChatUI } from '@chatbot/chat-ui/react';
101
+ import '@chatbot/chat-ui/styles';
102
+
103
+ function App() {
104
+ return (
105
+ <ChatUI
106
+ config={{
107
+ apiUrl: 'http://localhost:3000/api',
108
+ }}
109
+ theme={{
110
+ primaryColor: '#3b82f6',
111
+ userMessageColor: '#3b82f6',
112
+ }}
113
+ />
114
+ );
115
+ }
116
+ ```
117
+
118
+ Or use the hook directly:
119
+
120
+ ```tsx
121
+ import { useChat } from '@chatbot/chat-ui/react';
122
+
123
+ function CustomChat() {
124
+ const { messages, input, sendMessage, setInput } = useChat({
125
+ apiUrl: 'http://localhost:3000/api',
126
+ });
127
+
128
+ return (
129
+ <div>
130
+ {messages.map(msg => (
131
+ <div key={msg.id}>{msg.content}</div>
132
+ ))}
133
+ <input value={input} onChange={e => setInput(e.target.value)} />
134
+ <button onClick={() => sendMessage(input)}>Send</button>
135
+ </div>
136
+ );
137
+ }
138
+ ```
139
+
140
+ ### Solid
141
+
142
+ ```tsx
143
+ import { createChat } from '@chatbot/chat-ui/solid';
144
+ import '@chatbot/chat-ui/styles';
145
+
146
+ function App() {
147
+ const chat = createChat({
148
+ apiUrl: 'http://localhost:3000/api',
149
+ });
150
+
151
+ return (
152
+ <div>
153
+ <For each={chat.messages()}>
154
+ {(msg) => <div>{msg.content}</div>}
155
+ </For>
156
+ <input
157
+ value={chat.input()}
158
+ onInput={e => chat.setInput(e.target.value)}
159
+ />
160
+ <button onClick={() => chat.sendMessage(chat.input())}>
161
+ Send
162
+ </button>
163
+ </div>
164
+ );
165
+ }
166
+ ```
167
+
168
+ ### Vanilla JS
169
+
170
+ ```javascript
171
+ import { createChatUI } from '@chatbot/chat-ui/vanilla';
172
+ import '@chatbot/chat-ui/styles';
173
+
174
+ const container = document.getElementById('chat-container');
175
+
176
+ const chatUI = createChatUI({
177
+ config: {
178
+ apiUrl: 'http://localhost:3000/api',
179
+ },
180
+ theme: {
181
+ primaryColor: '#3b82f6',
182
+ },
183
+ container,
184
+ });
185
+
186
+ // Later, to destroy:
187
+ // chatUI.destroy();
188
+ ```
189
+
190
+ ### Core Only (Advanced)
191
+
192
+ ```typescript
193
+ import { ChatEngine } from '@chatbot/chat-ui/core';
194
+
195
+ const engine = new ChatEngine({
196
+ apiUrl: 'http://localhost:3000/api',
197
+ });
198
+
199
+ engine.on('messagesChange', (messages) => {
200
+ console.log('Messages updated:', messages);
201
+ });
202
+
203
+ engine.sendMessage('Hello!');
204
+ ```
205
+
206
+ ## Theming
207
+
208
+ ### CSS Variables
209
+
210
+ The package uses CSS variables for theming. You can override them:
211
+
212
+ ```css
213
+ .chat-container {
214
+ --chat-primary-color: #your-color;
215
+ --chat-user-message-color: #your-color;
216
+ --chat-assistant-message-color: #your-color;
217
+ --chat-border-radius: 0.5rem;
218
+ --chat-font-family: 'Your Font', sans-serif;
219
+ /* ... and more */
220
+ }
221
+ ```
222
+
223
+ ### Theme Props (React)
224
+
225
+ ```tsx
226
+ <ChatUI
227
+ config={config}
228
+ theme={{
229
+ primaryColor: '#3b82f6',
230
+ userMessageColor: '#3b82f6',
231
+ assistantMessageColor: '#f1f5f9',
232
+ borderRadius: '0.5rem',
233
+ fontFamily: 'system-ui, sans-serif',
234
+ }}
235
+ />
236
+ ```
237
+
238
+ ## Configuration
239
+
240
+ ```typescript
241
+ interface ChatConfig {
242
+ apiUrl?: string; // Backend API URL
243
+ apiKey?: string; // API key for authentication
244
+ headers?: Record<string, string>; // Custom headers
245
+ onMessage?: (message: Message) => void; // Message callback
246
+ onError?: (error: Error) => void; // Error callback
247
+ enableWebSocket?: boolean; // Enable WebSocket
248
+ websocketUrl?: string; // WebSocket URL
249
+ }
250
+ ```
251
+
252
+ ## Customization
253
+
254
+ ### Custom Message Renderer (React)
255
+
256
+ ```tsx
257
+ <ChatUI
258
+ config={config}
259
+ customMessageRenderer={(message) => (
260
+ <div className="my-custom-message">
261
+ {message.content}
262
+ </div>
263
+ )}
264
+ />
265
+ ```
266
+
267
+ ### Custom Input Renderer (React)
268
+
269
+ ```tsx
270
+ <ChatUI
271
+ config={config}
272
+ customInputRenderer={({ value, onChange, onSend, disabled }) => (
273
+ <div>
274
+ <textarea value={value} onChange={e => onChange(e.target.value)} />
275
+ <button onClick={onSend} disabled={disabled}>Send</button>
276
+ </div>
277
+ )}
278
+ />
279
+ ```
280
+
281
+ ## Backend API
282
+
283
+ The package expects a backend API with the following endpoint:
284
+
285
+ ### POST `/api/chat`
286
+
287
+ Request:
288
+ ```json
289
+ {
290
+ "message": "Hello!",
291
+ "conversationId": "optional-conversation-id"
292
+ }
293
+ ```
294
+
295
+ Response:
296
+ ```json
297
+ {
298
+ "id": "message-id",
299
+ "message": "Response message",
300
+ "content": "Response message",
301
+ "timestamp": "2024-01-01T00:00:00.000Z",
302
+ "metadata": {}
303
+ }
304
+ ```
305
+
306
+ ## License
307
+
308
+ MIT
309
+
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Browser Entry Point
3
+ * This file is used to create the browser bundle (UMD format)
4
+ * It imports the vanilla adapter, exposing ChatbotUI globally
5
+ */
6
+
7
+ // Import the vanilla adapter (which already sets up window.ChatbotUI)
8
+ import { createChatUI } from '../adapters/vanilla/index.js';
9
+
10
+ // Re-export for convenience
11
+ export { createChatUI };
12
+ export type { ChatUIOptions, ChatUIInstance } from '../adapters/vanilla/index.js';
13
+
14
+ // The vanilla adapter already sets up window.ChatbotUI when in browser context
15
+ // This ensures it's available globally when loaded via script tag
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import type { ChatConfig, ChatTheme, Message } from '../../core/src/types';
3
+ export interface ChatUIProps {
4
+ config: ChatConfig;
5
+ theme?: ChatTheme;
6
+ className?: string;
7
+ placeholder?: string;
8
+ showTimestamp?: boolean;
9
+ showAvatar?: boolean;
10
+ userAvatar?: string | React.ReactNode;
11
+ assistantAvatar?: string | React.ReactNode;
12
+ maxHeight?: string;
13
+ disabled?: boolean;
14
+ initialGreeting?: string;
15
+ messagesContainerClassName?: string;
16
+ messageClassName?: string;
17
+ inputContainerClassName?: string;
18
+ inputClassName?: string;
19
+ buttonClassName?: string;
20
+ errorClassName?: string;
21
+ emptyStateClassName?: string;
22
+ customMessageRenderer?: (message: Message) => React.ReactNode;
23
+ customInputRenderer?: (props: {
24
+ value: string;
25
+ onChange: (value: string) => void;
26
+ onSend: () => void;
27
+ disabled: boolean;
28
+ }) => React.ReactNode;
29
+ dataAttributes?: Record<string, string>;
30
+ }
31
+ export declare const ChatUI: React.FC<ChatUIProps>;
32
+ //# sourceMappingURL=ChatUI.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatUI.d.ts","sourceRoot":"","sources":["../../../adapters/react/ChatUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAuD3E,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;IAC9D,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE;QAC5B,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,MAAM,EAAE,MAAM,IAAI,CAAC;QACnB,QAAQ,EAAE,OAAO,CAAC;KACnB,KAAK,KAAK,CAAC,SAAS,CAAC;IAEtB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAgOxC,CAAC"}
@@ -0,0 +1,170 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { useChat } from './useChat';
4
+ // Optional markdown support - will be dynamically imported if available
5
+ // Add react-markdown and remark-gfm to your app's dependencies to enable markdown rendering
6
+ const MarkdownContent = ({ content }) => {
7
+ const [MarkdownRenderer, setMarkdownRenderer] = React.useState(null);
8
+ React.useEffect(() => {
9
+ // @ts-ignore - react-markdown is an optional dependency
10
+ import('react-markdown')
11
+ .then((module) => {
12
+ // @ts-ignore - remark-gfm is an optional dependency
13
+ import('remark-gfm')
14
+ .then((gfm) => {
15
+ setMarkdownRenderer(() => {
16
+ const ReactMarkdown = module.default;
17
+ const remarkGfm = gfm.default;
18
+ // Note: react-markdown v10+ removed className prop
19
+ // We wrap it in a div with the className instead
20
+ return (props) => (_jsx("div", { className: "chat-markdown", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: props.children }) }));
21
+ });
22
+ })
23
+ .catch(() => {
24
+ // remark-gfm not available, use basic markdown
25
+ setMarkdownRenderer(() => {
26
+ const ReactMarkdown = module.default;
27
+ return (props) => (_jsx("div", { className: "chat-markdown", children: _jsx(ReactMarkdown, { children: props.children }) }));
28
+ });
29
+ });
30
+ })
31
+ .catch(() => {
32
+ // react-markdown not available, will use plain text
33
+ });
34
+ }, []);
35
+ if (MarkdownRenderer) {
36
+ return _jsx(MarkdownRenderer, { children: content });
37
+ }
38
+ return _jsx("div", { className: "chat-markdown", children: content });
39
+ };
40
+ export const ChatUI = ({ config, theme = {}, className = '', placeholder = 'Type your message...', showTimestamp = true, showAvatar = true, userAvatar, assistantAvatar, maxHeight = '600px', disabled = false, initialGreeting, messagesContainerClassName = '', messageClassName = '', inputContainerClassName = '', inputClassName = '', buttonClassName = '', errorClassName = '', emptyStateClassName = '', customMessageRenderer, customInputRenderer, dataAttributes = {}, }) => {
41
+ const { messages, input, isLoading, error, sendMessage, setInput, addMessage, } = useChat(config);
42
+ // Add initial greeting message when component mounts
43
+ React.useEffect(() => {
44
+ if (initialGreeting && messages.length === 0) {
45
+ const greetingMessage = {
46
+ id: `greeting-${Date.now()}`,
47
+ content: initialGreeting,
48
+ role: 'assistant',
49
+ timestamp: new Date(),
50
+ };
51
+ addMessage(greetingMessage);
52
+ }
53
+ }, [initialGreeting, messages.length, addMessage]);
54
+ const handleSubmit = (e) => {
55
+ e.preventDefault();
56
+ if (input.trim() && !isLoading && !disabled) {
57
+ sendMessage(input);
58
+ }
59
+ };
60
+ const formatTimestamp = (date) => {
61
+ return new Intl.DateTimeFormat('en-US', {
62
+ hour: '2-digit',
63
+ minute: '2-digit',
64
+ }).format(date);
65
+ };
66
+ const renderAvatar = (role) => {
67
+ if (role === 'system')
68
+ return null;
69
+ if (!showAvatar)
70
+ return null;
71
+ const avatar = role === 'user' ? userAvatar : assistantAvatar;
72
+ if (typeof avatar === 'string') {
73
+ return (_jsx("div", { className: "chat-avatar", children: _jsx("img", { src: avatar, alt: role }) }));
74
+ }
75
+ if (React.isValidElement(avatar)) {
76
+ return _jsx("div", { className: "chat-avatar", children: avatar });
77
+ }
78
+ return (_jsx("div", { className: "chat-avatar", children: role === 'user' ? 'U' : 'A' }));
79
+ };
80
+ const renderMessage = (message) => {
81
+ if (customMessageRenderer) {
82
+ return customMessageRenderer(message);
83
+ }
84
+ const isUser = message.role === 'user';
85
+ return (_jsxs("div", { className: `chat-message ${isUser ? 'chat-message-user' : 'chat-message-assistant'} ${messageClassName}`, "data-message-role": message.role, "data-message-id": message.id, children: [!isUser && renderAvatar(message.role), _jsxs("div", { className: `chat-message-content ${isUser ? 'chat-message-content-user' : 'chat-message-content-assistant'}`, children: [_jsx("div", { className: "chat-message-text", children: isUser ? (message.content) : (_jsx(MarkdownContent, { content: message.content })) }), showTimestamp && (_jsx("div", { className: "chat-message-timestamp", children: formatTimestamp(message.timestamp) }))] }), isUser && renderAvatar(message.role)] }, message.id));
86
+ };
87
+ // Apply theme via CSS variables (only set if provided)
88
+ const themeStyles = {};
89
+ if (theme?.primaryColor)
90
+ themeStyles['--chat-primary-color'] = theme.primaryColor;
91
+ if (theme?.secondaryColor)
92
+ themeStyles['--chat-secondary-color'] = theme.secondaryColor;
93
+ if (theme?.backgroundColor)
94
+ themeStyles['--chat-background-color'] = theme.backgroundColor;
95
+ if (theme?.textColor)
96
+ themeStyles['--chat-text-color'] = theme.textColor;
97
+ if (theme?.userMessageColor)
98
+ themeStyles['--chat-user-message-color'] = theme.userMessageColor;
99
+ if (theme?.assistantMessageColor)
100
+ themeStyles['--chat-assistant-message-color'] = theme.assistantMessageColor;
101
+ if (theme?.inputBackgroundColor)
102
+ themeStyles['--chat-input-background-color'] = theme.inputBackgroundColor;
103
+ if (theme?.inputTextColor)
104
+ themeStyles['--chat-input-text-color'] = theme.inputTextColor;
105
+ if (theme?.errorBackgroundColor)
106
+ themeStyles['--chat-error-background-color'] = theme.errorBackgroundColor;
107
+ if (theme?.errorTextColor)
108
+ themeStyles['--chat-error-text-color'] = theme.errorTextColor;
109
+ if (theme?.borderColor)
110
+ themeStyles['--chat-border-color'] = theme.borderColor;
111
+ if (theme?.fontFamily)
112
+ themeStyles['--chat-font-family'] = theme.fontFamily;
113
+ if (theme?.fontSize)
114
+ themeStyles['--chat-font-size'] = theme.fontSize;
115
+ if (theme?.fontWeight)
116
+ themeStyles['--chat-font-weight'] = theme.fontWeight;
117
+ if (theme?.lineHeight)
118
+ themeStyles['--chat-line-height'] = theme.lineHeight;
119
+ if (theme?.padding)
120
+ themeStyles['--chat-padding'] = theme.padding;
121
+ if (theme?.messageGap)
122
+ themeStyles['--chat-message-gap'] = theme.messageGap;
123
+ if (theme?.inputPadding)
124
+ themeStyles['--chat-input-padding'] = theme.inputPadding;
125
+ if (theme?.messagePadding)
126
+ themeStyles['--chat-message-padding'] = theme.messagePadding;
127
+ if (theme?.borderRadius)
128
+ themeStyles['--chat-border-radius'] = theme.borderRadius;
129
+ if (theme?.messageBorderRadius)
130
+ themeStyles['--chat-message-border-radius'] = theme.messageBorderRadius;
131
+ if (theme?.inputBorderRadius)
132
+ themeStyles['--chat-input-border-radius'] = theme.inputBorderRadius;
133
+ if (theme?.borderWidth)
134
+ themeStyles['--chat-border-width'] = theme.borderWidth;
135
+ if (theme?.boxShadow)
136
+ themeStyles['--chat-box-shadow'] = theme.boxShadow;
137
+ if (theme?.messageBoxShadow)
138
+ themeStyles['--chat-message-box-shadow'] = theme.messageBoxShadow;
139
+ if (theme?.inputBoxShadow)
140
+ themeStyles['--chat-input-box-shadow'] = theme.inputBoxShadow;
141
+ if (maxHeight || theme?.maxHeight)
142
+ themeStyles['--chat-max-height'] = maxHeight || theme.maxHeight || '';
143
+ if (theme?.maxWidth)
144
+ themeStyles['--chat-max-width'] = theme.maxWidth;
145
+ if (theme?.messageMaxWidth)
146
+ themeStyles['--chat-message-max-width'] = theme.messageMaxWidth;
147
+ if (theme?.avatarSize)
148
+ themeStyles['--chat-avatar-size'] = theme.avatarSize;
149
+ if (theme?.transitionDuration)
150
+ themeStyles['--chat-transition-duration'] = theme.transitionDuration;
151
+ if (theme?.animationDuration)
152
+ themeStyles['--chat-animation-duration'] = theme.animationDuration;
153
+ if (theme?.scrollbarWidth)
154
+ themeStyles['--chat-scrollbar-width'] = theme.scrollbarWidth;
155
+ if (theme?.scrollbarColor)
156
+ themeStyles['--chat-scrollbar-color'] = theme.scrollbarColor;
157
+ if (theme?.scrollbarTrackColor)
158
+ themeStyles['--chat-scrollbar-track-color'] = theme.scrollbarTrackColor;
159
+ // Build data attributes
160
+ const containerDataAttributes = {
161
+ 'data-chat-ui': 'true',
162
+ ...dataAttributes,
163
+ };
164
+ return (_jsxs("div", { className: `chat-container ${className}`, style: themeStyles, ...containerDataAttributes, children: [theme?.customCSS && (_jsx("style", { dangerouslySetInnerHTML: { __html: theme.customCSS } })), _jsxs("div", { className: `chat-messages-container ${messagesContainerClassName}`, children: [messages.length === 0 && (_jsx("div", { className: `chat-empty-state ${emptyStateClassName}`, children: "Start a conversation..." })), messages.map(renderMessage), isLoading && (_jsxs("div", { className: `chat-message chat-message-assistant ${messageClassName}`, children: [renderAvatar('assistant'), _jsx("div", { className: "chat-message-content chat-message-content-assistant", children: _jsx("div", { className: "chat-message-text", children: "Thinking..." }) })] }))] }), error && (_jsxs("div", { className: `chat-error ${errorClassName}`, children: ["Error: ", error.message] })), _jsx("div", { className: `chat-input-container ${inputContainerClassName}`, children: customInputRenderer ? (customInputRenderer({
165
+ value: input,
166
+ onChange: setInput,
167
+ onSend: () => sendMessage(input),
168
+ disabled: disabled || isLoading,
169
+ })) : (_jsxs("form", { onSubmit: handleSubmit, className: "chat-input-form", children: [_jsx("input", { type: "text", value: input, onChange: (e) => setInput(e.target.value), placeholder: placeholder, disabled: disabled || isLoading, className: `chat-input ${inputClassName}` }), _jsx("button", { type: "submit", disabled: disabled || isLoading || !input.trim(), className: `chat-send-button ${buttonClassName}`, children: "Send" })] })) })] }));
170
+ };
@@ -0,0 +1,5 @@
1
+ export { ChatUI } from './ChatUI';
2
+ export { useChat } from './useChat';
3
+ export type { ChatUIProps } from './ChatUI';
4
+ export type { UseChatReturn } from './useChat';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../adapters/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { ChatUI } from './ChatUI';
2
+ export { useChat } from './useChat';
@@ -0,0 +1,14 @@
1
+ import type { ChatConfig, Message } from '../../core/src/types';
2
+ export interface UseChatReturn {
3
+ messages: Message[];
4
+ input: string;
5
+ isLoading: boolean;
6
+ error: Error | null;
7
+ sendMessage: (content: string) => Promise<void>;
8
+ setInput: (value: string) => void;
9
+ clearMessages: () => void;
10
+ retryLastMessage: () => Promise<void>;
11
+ addMessage: (message: Message) => void;
12
+ }
13
+ export declare function useChat(config: ChatConfig): UseChatReturn;
14
+ //# sourceMappingURL=useChat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../../adapters/react/useChat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CA0EzD"}
@@ -0,0 +1,64 @@
1
+ import { useState, useEffect, useRef, useCallback } from 'react';
2
+ import { ChatEngine } from '../../core/src/ChatEngine';
3
+ export function useChat(config) {
4
+ const engineRef = useRef(null);
5
+ const [messages, setMessages] = useState([]);
6
+ const [input, setInput] = useState('');
7
+ const [isLoading, setIsLoading] = useState(false);
8
+ const [error, setError] = useState(null);
9
+ useEffect(() => {
10
+ const engine = new ChatEngine(config);
11
+ engineRef.current = engine;
12
+ // Set initial state
13
+ setMessages(engine.getMessages());
14
+ setInput(engine.getInput());
15
+ setIsLoading(engine.getIsLoading());
16
+ setError(engine.getError());
17
+ // Subscribe to events
18
+ const unsubscribeMessages = engine.on('messagesChange', (msgs) => {
19
+ setMessages(msgs || []);
20
+ });
21
+ const unsubscribeInput = engine.on('inputChange', (value) => {
22
+ setInput(value || '');
23
+ });
24
+ const unsubscribeLoading = engine.on('loadingChange', (loading) => {
25
+ setIsLoading(loading || false);
26
+ });
27
+ const unsubscribeError = engine.on('error', (err) => {
28
+ setError(err || null);
29
+ });
30
+ return () => {
31
+ unsubscribeMessages();
32
+ unsubscribeInput();
33
+ unsubscribeLoading();
34
+ unsubscribeError();
35
+ engine.destroy();
36
+ };
37
+ }, []);
38
+ const sendMessage = useCallback(async (content) => {
39
+ await engineRef.current?.sendMessage(content);
40
+ }, []);
41
+ const setInputValue = useCallback((value) => {
42
+ engineRef.current?.setInput(value);
43
+ }, []);
44
+ const clearMessages = useCallback(() => {
45
+ engineRef.current?.clearMessages();
46
+ }, []);
47
+ const retryLastMessage = useCallback(async () => {
48
+ await engineRef.current?.retryLastMessage();
49
+ }, []);
50
+ const addMessage = useCallback((message) => {
51
+ engineRef.current?.addMessage(message);
52
+ }, []);
53
+ return {
54
+ messages,
55
+ input,
56
+ isLoading,
57
+ error,
58
+ sendMessage,
59
+ setInput: setInputValue,
60
+ clearMessages,
61
+ retryLastMessage,
62
+ addMessage,
63
+ };
64
+ }
@@ -0,0 +1,13 @@
1
+ import type { ChatConfig, Message } from '../../core/src/types';
2
+ export interface CreateChatReturn {
3
+ messages: () => Message[];
4
+ input: () => string;
5
+ isLoading: () => boolean;
6
+ error: () => Error | null;
7
+ sendMessage: (content: string) => Promise<void>;
8
+ setInput: (value: string) => void;
9
+ clearMessages: () => void;
10
+ retryLastMessage: () => Promise<void>;
11
+ }
12
+ export declare function createChat(config: ChatConfig): CreateChatReturn;
13
+ //# sourceMappingURL=createChat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createChat.d.ts","sourceRoot":"","sources":["../../../adapters/solid/createChat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,OAAO,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,KAAK,EAAE,MAAM,KAAK,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,CAqC/D"}
@@ -0,0 +1,34 @@
1
+ import { createSignal, onCleanup } from 'solid-js';
2
+ import { ChatEngine } from '../../core/src/ChatEngine';
3
+ export function createChat(config) {
4
+ const engine = new ChatEngine(config);
5
+ const [messages, setMessages] = createSignal(engine.getMessages());
6
+ const [input, setInput] = createSignal(engine.getInput());
7
+ const [isLoading, setIsLoading] = createSignal(engine.getIsLoading());
8
+ const [error, setError] = createSignal(engine.getError());
9
+ engine.on('messagesChange', (msgs) => {
10
+ setMessages(msgs || []);
11
+ });
12
+ engine.on('inputChange', (value) => {
13
+ setInput(value || '');
14
+ });
15
+ engine.on('loadingChange', (loading) => {
16
+ setIsLoading(loading || false);
17
+ });
18
+ engine.on('error', (err) => {
19
+ setError(err || null);
20
+ });
21
+ onCleanup(() => {
22
+ engine.destroy();
23
+ });
24
+ return {
25
+ messages,
26
+ input,
27
+ isLoading,
28
+ error,
29
+ sendMessage: (content) => engine.sendMessage(content),
30
+ setInput: (value) => engine.setInput(value),
31
+ clearMessages: () => engine.clearMessages(),
32
+ retryLastMessage: () => engine.retryLastMessage(),
33
+ };
34
+ }