@chainai/react 1.0.0 → 1.0.2

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,17 +1,17 @@
1
- # @chain-ai/react
1
+ # @chainai/react
2
2
 
3
3
  React components for Chain AI - Embeddable blockchain AI assistant.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @chain-ai/react @chain-ai/core
8
+ npm install @chainai/react @chainai/core
9
9
  ```
10
10
 
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { ChainAI } from '@chain-ai/react';
14
+ import { ChainAI } from '@chainai/react';
15
15
 
16
16
  function App() {
17
17
  return (
@@ -38,7 +38,7 @@ function App() {
38
38
  ### Standalone Component
39
39
 
40
40
  ```typescript
41
- import { ChainAI } from '@chain-ai/react';
41
+ import { ChainAI } from '@chainai/react';
42
42
 
43
43
  function App() {
44
44
  return (
@@ -61,7 +61,7 @@ function App() {
61
61
  ### Advanced Usage with Provider
62
62
 
63
63
  ```typescript
64
- import { ChainAIProvider, useChainAI, useChat } from '@chain-ai/react';
64
+ import { ChainAIProvider, useChainAI, useChat } from '@chainai/react';
65
65
 
66
66
  function App() {
67
67
  return (
@@ -112,7 +112,7 @@ function MyCustomChat() {
112
112
  ### Built-in Themes
113
113
 
114
114
  ```typescript
115
- import { ChainAI, darkTheme, lightTheme } from '@chain-ai/react';
115
+ import { ChainAI, darkTheme, lightTheme } from '@chainai/react';
116
116
 
117
117
  // Dark theme
118
118
  <ChainAI config={config} theme={darkTheme} />
@@ -124,7 +124,7 @@ import { ChainAI, darkTheme, lightTheme } from '@chain-ai/react';
124
124
  ### Custom Theme
125
125
 
126
126
  ```typescript
127
- import { ChainAI, Theme } from '@chain-ai/react';
127
+ import { ChainAI, Theme } from '@chainai/react';
128
128
 
129
129
  const customTheme: Theme = {
130
130
  colors: {
@@ -187,7 +187,7 @@ import {
187
187
  ChatHeader,
188
188
  useChat,
189
189
  defaultTheme,
190
- } from '@chain-ai/react';
190
+ } from '@chainai/react';
191
191
 
192
192
  function CustomLayout() {
193
193
  const { messages, sendMessage, isLoading } = useChat();
@@ -219,7 +219,7 @@ import type {
219
219
  Message,
220
220
  ChainAIConfig,
221
221
  ResponseCustomization,
222
- } from '@chain-ai/react';
222
+ } from '@chainai/react';
223
223
  ```
224
224
 
225
225
  ## License
@@ -8,7 +8,7 @@
8
8
  * - Works in any context (web, extension, mobile)
9
9
  */
10
10
  import React from 'react';
11
- import type { ChainAIConfig } from '@chainai/core';
11
+ import type { ChainAIConfig, WalletAddress } from '@chainai/core';
12
12
  import type { Theme } from '../styles/themes';
13
13
  import '../styles/widget.css';
14
14
  /** Branding configuration for white-labeling */
@@ -55,6 +55,27 @@ export interface DimensionConfig {
55
55
  }
56
56
  export interface ChainAIWidgetProps {
57
57
  config: ChainAIConfig;
58
+ /**
59
+ * Connected wallet addresses - passed with every request so the AI knows
60
+ * the user's wallets for balance checks, transaction history, etc.
61
+ *
62
+ * @example
63
+ * ```tsx
64
+ * const { address } = useAccount(); // wagmi
65
+ * const { publicKey } = useWallet(); // solana
66
+ *
67
+ * <ChainAIWidget
68
+ * config={{ apiKey: 'xxx' }}
69
+ * wallets={[
70
+ * { chain: 'ethereum', address: address },
71
+ * { chain: 'solana', address: publicKey?.toString() },
72
+ * ]}
73
+ * />
74
+ * ```
75
+ */
76
+ wallets?: WalletAddress[];
77
+ /** Currently active chain (optional, for context) */
78
+ activeChain?: string;
58
79
  /** Branding/white-label configuration */
59
80
  branding?: BrandingConfig;
60
81
  /** Dimension/size configuration */
@@ -92,7 +92,7 @@ const Logo = ({ branding }) => {
92
92
  // Default: use avatar as logo
93
93
  return react_1.default.createElement(Avatar, { branding: branding, size: "medium" });
94
94
  };
95
- const ChainAIWidgetInner = ({ branding = {}, dimensions = {}, defaultOpen = false, position = 'bottom-right', customPosition, theme: customTheme, className = '', placeholder = 'Ask me anything...', zIndex = 9999, onToggle, onMessage, }) => {
95
+ const ChainAIWidgetInner = ({ wallets, activeChain, branding = {}, dimensions = {}, defaultOpen = false, position = 'bottom-right', customPosition, theme: customTheme, className = '', placeholder = 'Ask me anything...', zIndex = 9999, onToggle, onMessage, }) => {
96
96
  const [isOpen, setIsOpen] = (0, react_1.useState)(defaultOpen);
97
97
  const [input, setInput] = (0, react_1.useState)('');
98
98
  const [pendingAction, setPendingAction] = (0, react_1.useState)(null);
@@ -166,7 +166,13 @@ const ChainAIWidgetInner = ({ branding = {}, dimensions = {}, defaultOpen = fals
166
166
  const text = input;
167
167
  setInput('');
168
168
  onMessage?.(text);
169
- await sendMessage(text);
169
+ // Include wallet context with every request
170
+ const walletContext = wallets?.length ? {
171
+ wallets,
172
+ activeChain,
173
+ activeAddress: wallets.find(w => w.isPrimary)?.address || wallets[0]?.address,
174
+ } : undefined;
175
+ await sendMessage(text, { walletContext });
170
176
  };
171
177
  const handleKeyDown = (e) => {
172
178
  if (e.key === 'Enter' && !e.shiftKey) {
@@ -175,7 +181,12 @@ const ChainAIWidgetInner = ({ branding = {}, dimensions = {}, defaultOpen = fals
175
181
  }
176
182
  };
177
183
  const handleActionFieldSubmit = (field, value) => {
178
- sendMessage(`${field}: ${value}`);
184
+ const walletContext = wallets?.length ? {
185
+ wallets,
186
+ activeChain,
187
+ activeAddress: wallets.find(w => w.isPrimary)?.address || wallets[0]?.address,
188
+ } : undefined;
189
+ sendMessage(`${field}: ${value}`, { walletContext });
179
190
  setPendingAction(null);
180
191
  };
181
192
  // CSS custom properties for theming and dimensions
@@ -3,13 +3,18 @@
3
3
  */
4
4
  import React, { ReactNode } from 'react';
5
5
  import { ChainAIClient } from '@chainai/core';
6
- import type { ChainAIConfig, ResponseCustomization } from '@chainai/core';
6
+ import type { ChainAIConfig, ResponseCustomization, WalletProvider } from '@chainai/core';
7
7
  export interface ChainAIContextValue {
8
8
  client: ChainAIClient | null;
9
9
  isReady: boolean;
10
10
  error: string | null;
11
11
  customization: ResponseCustomization | null;
12
12
  updateCustomization: (customization: Partial<ResponseCustomization>) => Promise<void>;
13
+ /**
14
+ * Set or update the wallet provider function
15
+ * This allows dynamic updates when wallets connect/disconnect
16
+ */
17
+ setWalletProvider: (provider: WalletProvider) => void;
13
18
  }
14
19
  export interface ChainAIProviderProps {
15
20
  config: ChainAIConfig;
@@ -75,12 +75,18 @@ const ChainAIProvider = ({ config, children }) => {
75
75
  const updated = await client.getCustomization();
76
76
  setCustomization(updated);
77
77
  };
78
+ const setWalletProvider = (0, react_1.useCallback)((provider) => {
79
+ if (client) {
80
+ client.setWalletProvider(provider);
81
+ }
82
+ }, [client]);
78
83
  const value = {
79
84
  client,
80
85
  isReady,
81
86
  error,
82
87
  customization,
83
88
  updateCustomization,
89
+ setWalletProvider,
84
90
  };
85
91
  return react_1.default.createElement(ChainAIContext.Provider, { value: value }, children);
86
92
  };
@@ -1,12 +1,23 @@
1
1
  /**
2
2
  * useChat hook - Manages chat messages and state
3
3
  */
4
- import type { Message } from '@chainai/core';
4
+ import type { Message, WalletContext } from '@chainai/core';
5
+ export interface SendMessageOptions {
6
+ /** @deprecated Use walletContext instead */
7
+ userContext?: any;
8
+ /** Override wallet context for this specific request */
9
+ walletContext?: WalletContext;
10
+ }
5
11
  export interface UseChatReturn {
6
12
  messages: Message[];
7
13
  isLoading: boolean;
8
14
  error: string | null;
9
- sendMessage: (text: string, userContext?: any) => Promise<void>;
15
+ /**
16
+ * Send a message to the AI
17
+ * Wallet context is automatically included from the walletProvider in config.
18
+ * You can optionally override it by passing walletContext in options.
19
+ */
20
+ sendMessage: (text: string, options?: SendMessageOptions) => Promise<void>;
10
21
  clearMessages: () => void;
11
22
  }
12
23
  export declare const useChat: (conversationId?: string) => UseChatReturn;
@@ -11,7 +11,7 @@ const useChat = (conversationId) => {
11
11
  const [messages, setMessages] = (0, react_1.useState)([]);
12
12
  const [isLoading, setIsLoading] = (0, react_1.useState)(false);
13
13
  const [error, setError] = (0, react_1.useState)(null);
14
- const sendMessage = (0, react_1.useCallback)(async (text, userContext) => {
14
+ const sendMessage = (0, react_1.useCallback)(async (text, options) => {
15
15
  if (!client || !isReady) {
16
16
  setError('Client not ready');
17
17
  return;
@@ -38,7 +38,8 @@ const useChat = (conversationId) => {
38
38
  await client.streamChat({
39
39
  text,
40
40
  conversationId: conversationId || 'default',
41
- userContext,
41
+ userContext: options?.userContext,
42
+ walletContext: options?.walletContext,
42
43
  }, {
43
44
  onChunk: (chunk) => {
44
45
  assistantResponse += chunk;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @chain-ai/react - React components for Chain AI
2
+ * @chainai/react - React components for Chain AI
3
3
  *
4
4
  * Embeddable blockchain AI assistant components
5
5
  */
@@ -21,4 +21,4 @@ export { useChat } from './hooks/useChat';
21
21
  export type { UseChatReturn } from './hooks/useChat';
22
22
  export { defaultTheme, darkTheme, lightTheme } from './styles/themes';
23
23
  export type { Theme } from './styles/themes';
24
- export type { ChainAIConfig, ResponseCustomization, ResponseStyle, ResponseLength, Message, } from '@chainai/core';
24
+ export type { ChainAIConfig, ResponseCustomization, ResponseStyle, ResponseLength, Message, WalletAddress, WalletContext, } from '@chainai/core';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * @chain-ai/react - React components for Chain AI
3
+ * @chainai/react - React components for Chain AI
4
4
  *
5
5
  * Embeddable blockchain AI assistant components
6
6
  */
@@ -0,0 +1,156 @@
1
+ /* Chain AI Default Styles */
2
+
3
+ .chain-ai-container {
4
+ display: flex;
5
+ flex-direction: column;
6
+ border: 1px solid #e5e7eb;
7
+ border-radius: 8px;
8
+ overflow: hidden;
9
+ font-family: system-ui, -apple-system, sans-serif;
10
+ }
11
+
12
+ .chain-ai-header {
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: space-between;
16
+ padding: 16px;
17
+ border-bottom: 1px solid;
18
+ }
19
+
20
+ .chain-ai-header-title {
21
+ margin: 0;
22
+ font-size: 18px;
23
+ font-weight: 600;
24
+ }
25
+
26
+ .chain-ai-header-close {
27
+ background: none;
28
+ border: none;
29
+ font-size: 24px;
30
+ cursor: pointer;
31
+ padding: 0;
32
+ width: 32px;
33
+ height: 32px;
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ }
38
+
39
+ .chain-ai-messages {
40
+ flex: 1;
41
+ overflow-y: auto;
42
+ padding: 16px;
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: 12px;
46
+ }
47
+
48
+ .chain-ai-welcome {
49
+ text-align: center;
50
+ padding: 48px 16px;
51
+ color: #6b7280;
52
+ }
53
+
54
+ .chain-ai-welcome h2 {
55
+ margin: 0 0 8px 0;
56
+ font-size: 24px;
57
+ font-weight: 600;
58
+ color: inherit;
59
+ }
60
+
61
+ .chain-ai-welcome p {
62
+ margin: 0;
63
+ font-size: 16px;
64
+ }
65
+
66
+ .chain-ai-message {
67
+ max-width: 80%;
68
+ padding: 12px 16px;
69
+ border-radius: 8px;
70
+ position: relative;
71
+ }
72
+
73
+ .chain-ai-message-user {
74
+ align-self: flex-end;
75
+ margin-left: auto;
76
+ }
77
+
78
+ .chain-ai-message-assistant {
79
+ align-self: flex-start;
80
+ margin-right: auto;
81
+ }
82
+
83
+ .chain-ai-message-content {
84
+ margin: 0;
85
+ line-height: 1.5;
86
+ white-space: pre-wrap;
87
+ word-wrap: break-word;
88
+ }
89
+
90
+ .chain-ai-message-timestamp {
91
+ font-size: 11px;
92
+ opacity: 0.7;
93
+ margin-top: 4px;
94
+ }
95
+
96
+ .chain-ai-input-container {
97
+ display: flex;
98
+ gap: 8px;
99
+ padding: 16px;
100
+ border-top: 1px solid;
101
+ }
102
+
103
+ .chain-ai-input {
104
+ flex: 1;
105
+ padding: 12px;
106
+ border: 1px solid #e5e7eb;
107
+ border-radius: 6px;
108
+ font-size: 14px;
109
+ outline: none;
110
+ }
111
+
112
+ .chain-ai-input:focus {
113
+ border-color: #3b82f6;
114
+ }
115
+
116
+ .chain-ai-input:disabled {
117
+ opacity: 0.5;
118
+ cursor: not-allowed;
119
+ }
120
+
121
+ .chain-ai-send-button {
122
+ padding: 12px 24px;
123
+ border: none;
124
+ border-radius: 6px;
125
+ font-size: 14px;
126
+ font-weight: 500;
127
+ cursor: pointer;
128
+ transition: opacity 0.2s;
129
+ }
130
+
131
+ .chain-ai-send-button:hover:not(:disabled) {
132
+ opacity: 0.9;
133
+ }
134
+
135
+ .chain-ai-send-button:disabled {
136
+ opacity: 0.5;
137
+ cursor: not-allowed;
138
+ }
139
+
140
+ .chain-ai-loading {
141
+ display: flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ height: 100%;
145
+ color: #6b7280;
146
+ font-size: 14px;
147
+ }
148
+
149
+ .chain-ai-error {
150
+ padding: 12px;
151
+ background-color: #fee2e2;
152
+ color: #dc2626;
153
+ border-radius: 6px;
154
+ margin: 8px 0;
155
+ font-size: 14px;
156
+ }
@@ -0,0 +1,531 @@
1
+ /**
2
+ * Chain AI Widget Styles
3
+ *
4
+ * CSS Variables for theming:
5
+ * --chain-ai-primary: Primary brand color
6
+ * --chain-ai-primary-text: Text on primary color
7
+ * --chain-ai-bg: Background color
8
+ * --chain-ai-text: Main text color
9
+ * --chain-ai-border: Border color
10
+ * --chain-ai-user-bg: User message background
11
+ * --chain-ai-user-text: User message text
12
+ * --chain-ai-assistant-bg: Assistant message background
13
+ * --chain-ai-assistant-text: Assistant message text
14
+ * --chain-ai-font: Font family
15
+ *
16
+ * CSS Variables for dimensions:
17
+ * --chain-ai-fab-size: FAB button size (default: 56px)
18
+ * --chain-ai-fab-radius: FAB border radius (default: 50%)
19
+ * --chain-ai-window-width: Chat window width (default: 380px)
20
+ * --chain-ai-window-height: Chat window height (default: 520px)
21
+ * --chain-ai-window-radius: Chat window border radius (default: 16px)
22
+ * --chain-ai-avatar-gradient: Avatar gradient background
23
+ */
24
+
25
+ /* Reset and base */
26
+ .chain-ai-widget,
27
+ .chain-ai-widget * {
28
+ box-sizing: border-box;
29
+ margin: 0;
30
+ padding: 0;
31
+ }
32
+
33
+ .chain-ai-widget {
34
+ position: fixed;
35
+ font-family: var(--chain-ai-font, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
36
+ font-size: 14px;
37
+ line-height: 1.5;
38
+ -webkit-font-smoothing: antialiased;
39
+ }
40
+
41
+ /* Floating Action Button */
42
+ .chain-ai-widget-fab {
43
+ width: var(--chain-ai-fab-size, 56px);
44
+ height: var(--chain-ai-fab-size, 56px);
45
+ border-radius: var(--chain-ai-fab-radius, 50%);
46
+ border: none;
47
+ background: var(--chain-ai-primary, #3b82f6);
48
+ color: var(--chain-ai-primary-text, #ffffff);
49
+ cursor: pointer;
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1);
54
+ transition: all 0.2s ease;
55
+ position: relative;
56
+ z-index: 1;
57
+ }
58
+
59
+ .chain-ai-widget-fab:hover {
60
+ transform: scale(1.05);
61
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2), 0 3px 6px rgba(0, 0, 0, 0.1);
62
+ }
63
+
64
+ .chain-ai-widget-fab:active {
65
+ transform: scale(0.95);
66
+ }
67
+
68
+ .chain-ai-widget-fab-open {
69
+ background: var(--chain-ai-assistant-bg, #f3f4f6);
70
+ color: var(--chain-ai-text, #1f2937);
71
+ }
72
+
73
+ /* Chat Window */
74
+ .chain-ai-widget-window {
75
+ position: absolute;
76
+ bottom: calc(var(--chain-ai-fab-size, 56px) + 14px);
77
+ right: 0;
78
+ width: var(--chain-ai-window-width, 380px);
79
+ max-width: calc(100vw - 40px);
80
+ height: var(--chain-ai-window-height, 520px);
81
+ max-height: calc(100vh - 100px);
82
+ background: var(--chain-ai-bg, #ffffff);
83
+ border-radius: var(--chain-ai-window-radius, 16px);
84
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1);
85
+ display: flex;
86
+ flex-direction: column;
87
+ overflow: hidden;
88
+ animation: chain-ai-slide-up 0.2s ease;
89
+ }
90
+
91
+ @keyframes chain-ai-slide-up {
92
+ from {
93
+ opacity: 0;
94
+ transform: translateY(10px);
95
+ }
96
+ to {
97
+ opacity: 1;
98
+ transform: translateY(0);
99
+ }
100
+ }
101
+
102
+ /* Header */
103
+ .chain-ai-widget-header {
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: space-between;
107
+ padding: 16px;
108
+ background: var(--chain-ai-bg, #ffffff);
109
+ border-bottom: 1px solid var(--chain-ai-border, #e5e7eb);
110
+ }
111
+
112
+ .chain-ai-widget-header-info {
113
+ display: flex;
114
+ align-items: center;
115
+ gap: 12px;
116
+ }
117
+
118
+ .chain-ai-widget-avatar {
119
+ width: 36px;
120
+ height: 36px;
121
+ border-radius: 50%;
122
+ background: linear-gradient(135deg, var(--chain-ai-primary, #3b82f6), #8b5cf6);
123
+ display: flex;
124
+ align-items: center;
125
+ justify-content: center;
126
+ color: white;
127
+ flex-shrink: 0;
128
+ }
129
+
130
+ .chain-ai-widget-title {
131
+ font-weight: 600;
132
+ font-size: 16px;
133
+ color: var(--chain-ai-text, #1f2937);
134
+ }
135
+
136
+ .chain-ai-widget-close {
137
+ width: 32px;
138
+ height: 32px;
139
+ border: none;
140
+ background: transparent;
141
+ border-radius: 8px;
142
+ cursor: pointer;
143
+ display: flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+ color: var(--chain-ai-text, #6b7280);
147
+ transition: background 0.15s;
148
+ }
149
+
150
+ .chain-ai-widget-close:hover {
151
+ background: var(--chain-ai-assistant-bg, #f3f4f6);
152
+ }
153
+
154
+ /* Messages Area */
155
+ .chain-ai-widget-messages {
156
+ flex: 1;
157
+ overflow-y: auto;
158
+ padding: 16px;
159
+ display: flex;
160
+ flex-direction: column;
161
+ gap: 16px;
162
+ scroll-behavior: smooth;
163
+ }
164
+
165
+ .chain-ai-widget-messages::-webkit-scrollbar {
166
+ width: 6px;
167
+ }
168
+
169
+ .chain-ai-widget-messages::-webkit-scrollbar-track {
170
+ background: transparent;
171
+ }
172
+
173
+ .chain-ai-widget-messages::-webkit-scrollbar-thumb {
174
+ background: var(--chain-ai-border, #e5e7eb);
175
+ border-radius: 3px;
176
+ }
177
+
178
+ /* Welcome Screen */
179
+ .chain-ai-widget-welcome {
180
+ text-align: center;
181
+ padding: 32px 16px;
182
+ display: flex;
183
+ flex-direction: column;
184
+ align-items: center;
185
+ gap: 12px;
186
+ }
187
+
188
+ .chain-ai-widget-welcome .chain-ai-widget-avatar {
189
+ width: 48px;
190
+ height: 48px;
191
+ }
192
+
193
+ .chain-ai-widget-welcome h3 {
194
+ font-size: 18px;
195
+ font-weight: 600;
196
+ color: var(--chain-ai-text, #1f2937);
197
+ margin: 0;
198
+ }
199
+
200
+ .chain-ai-widget-welcome p {
201
+ color: #6b7280;
202
+ font-size: 14px;
203
+ max-width: 280px;
204
+ margin: 0;
205
+ }
206
+
207
+ /* Message Bubbles */
208
+ .chain-ai-widget-message {
209
+ display: flex;
210
+ gap: 8px;
211
+ max-width: 90%;
212
+ }
213
+
214
+ .chain-ai-widget-message-user {
215
+ align-self: flex-end;
216
+ flex-direction: row-reverse;
217
+ }
218
+
219
+ .chain-ai-widget-message-assistant {
220
+ align-self: flex-start;
221
+ }
222
+
223
+ .chain-ai-widget-message-assistant .chain-ai-widget-avatar {
224
+ width: 28px;
225
+ height: 28px;
226
+ font-size: 12px;
227
+ }
228
+
229
+ .chain-ai-widget-message-bubble {
230
+ flex: 1;
231
+ }
232
+
233
+ .chain-ai-widget-message-bubble .chain-ai-message {
234
+ max-width: 100%;
235
+ border-radius: 16px;
236
+ padding: 10px 14px;
237
+ }
238
+
239
+ .chain-ai-widget-message-user .chain-ai-message {
240
+ background: var(--chain-ai-user-bg, #3b82f6);
241
+ color: var(--chain-ai-user-text, #ffffff);
242
+ border-bottom-right-radius: 4px;
243
+ }
244
+
245
+ .chain-ai-widget-message-assistant .chain-ai-message {
246
+ background: var(--chain-ai-assistant-bg, #f3f4f6);
247
+ color: var(--chain-ai-assistant-text, #1f2937);
248
+ border-bottom-left-radius: 4px;
249
+ }
250
+
251
+ .chain-ai-widget-message-bubble .chain-ai-message-timestamp {
252
+ display: none;
253
+ }
254
+
255
+ /* Typing Indicator */
256
+ .chain-ai-widget-typing {
257
+ display: flex;
258
+ gap: 4px;
259
+ padding: 12px 16px;
260
+ background: var(--chain-ai-assistant-bg, #f3f4f6);
261
+ border-radius: 16px;
262
+ border-bottom-left-radius: 4px;
263
+ }
264
+
265
+ .chain-ai-widget-typing span {
266
+ width: 8px;
267
+ height: 8px;
268
+ background: #9ca3af;
269
+ border-radius: 50%;
270
+ animation: chain-ai-bounce 1.4s infinite ease-in-out both;
271
+ }
272
+
273
+ .chain-ai-widget-typing span:nth-child(1) { animation-delay: -0.32s; }
274
+ .chain-ai-widget-typing span:nth-child(2) { animation-delay: -0.16s; }
275
+
276
+ @keyframes chain-ai-bounce {
277
+ 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }
278
+ 40% { transform: scale(1); opacity: 1; }
279
+ }
280
+
281
+ /* Input Area */
282
+ .chain-ai-widget-input-area {
283
+ display: flex;
284
+ gap: 8px;
285
+ padding: 12px 16px;
286
+ background: var(--chain-ai-bg, #ffffff);
287
+ border-top: 1px solid var(--chain-ai-border, #e5e7eb);
288
+ }
289
+
290
+ .chain-ai-widget-input {
291
+ flex: 1;
292
+ padding: 10px 14px;
293
+ border: 1px solid var(--chain-ai-border, #e5e7eb);
294
+ border-radius: 24px;
295
+ font-size: 14px;
296
+ background: var(--chain-ai-bg, #ffffff);
297
+ color: var(--chain-ai-text, #1f2937);
298
+ outline: none;
299
+ transition: border-color 0.15s, box-shadow 0.15s;
300
+ }
301
+
302
+ .chain-ai-widget-input:focus {
303
+ border-color: var(--chain-ai-primary, #3b82f6);
304
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
305
+ }
306
+
307
+ .chain-ai-widget-input::placeholder {
308
+ color: #9ca3af;
309
+ }
310
+
311
+ .chain-ai-widget-input:disabled {
312
+ opacity: 0.6;
313
+ cursor: not-allowed;
314
+ }
315
+
316
+ .chain-ai-widget-send {
317
+ width: 40px;
318
+ height: 40px;
319
+ border: none;
320
+ border-radius: 50%;
321
+ background: var(--chain-ai-primary, #3b82f6);
322
+ color: var(--chain-ai-primary-text, #ffffff);
323
+ cursor: pointer;
324
+ display: flex;
325
+ align-items: center;
326
+ justify-content: center;
327
+ transition: all 0.15s;
328
+ flex-shrink: 0;
329
+ }
330
+
331
+ .chain-ai-widget-send:hover:not(:disabled) {
332
+ transform: scale(1.05);
333
+ }
334
+
335
+ .chain-ai-widget-send:disabled {
336
+ opacity: 0.5;
337
+ cursor: not-allowed;
338
+ }
339
+
340
+ /* Action Prompt */
341
+ .chain-ai-action-prompt {
342
+ background: var(--chain-ai-bg, #ffffff);
343
+ border: 1px solid var(--chain-ai-border, #e5e7eb);
344
+ border-radius: 12px;
345
+ padding: 16px;
346
+ margin-top: 8px;
347
+ }
348
+
349
+ .chain-ai-action-prompt-header {
350
+ display: flex;
351
+ align-items: center;
352
+ gap: 12px;
353
+ margin-bottom: 12px;
354
+ }
355
+
356
+ .chain-ai-action-prompt-icon {
357
+ width: 36px;
358
+ height: 36px;
359
+ border-radius: 10px;
360
+ background: rgba(59, 130, 246, 0.1);
361
+ display: flex;
362
+ align-items: center;
363
+ justify-content: center;
364
+ }
365
+
366
+ .chain-ai-action-prompt-title {
367
+ display: flex;
368
+ flex-direction: column;
369
+ }
370
+
371
+ .chain-ai-action-prompt-action {
372
+ font-weight: 600;
373
+ font-size: 12px;
374
+ letter-spacing: 0.5px;
375
+ color: var(--chain-ai-primary, #3b82f6);
376
+ }
377
+
378
+ .chain-ai-action-prompt-label {
379
+ font-size: 13px;
380
+ color: #6b7280;
381
+ }
382
+
383
+ .chain-ai-action-prompt-message {
384
+ font-size: 14px;
385
+ color: var(--chain-ai-text, #1f2937);
386
+ margin-bottom: 16px;
387
+ line-height: 1.5;
388
+ }
389
+
390
+ .chain-ai-action-prompt-form {
391
+ display: flex;
392
+ flex-direction: column;
393
+ gap: 12px;
394
+ }
395
+
396
+ .chain-ai-action-prompt-field {
397
+ display: flex;
398
+ flex-direction: column;
399
+ gap: 6px;
400
+ }
401
+
402
+ .chain-ai-action-prompt-field-label {
403
+ font-size: 12px;
404
+ font-weight: 500;
405
+ color: #6b7280;
406
+ }
407
+
408
+ .chain-ai-action-prompt-quick-options {
409
+ display: flex;
410
+ flex-wrap: wrap;
411
+ gap: 6px;
412
+ margin-bottom: 6px;
413
+ }
414
+
415
+ .chain-ai-action-prompt-quick-btn {
416
+ padding: 6px 12px;
417
+ border: 1px solid var(--chain-ai-border, #e5e7eb);
418
+ border-radius: 16px;
419
+ background: transparent;
420
+ font-size: 12px;
421
+ cursor: pointer;
422
+ transition: all 0.15s;
423
+ }
424
+
425
+ .chain-ai-action-prompt-quick-btn:hover {
426
+ border-color: var(--chain-ai-primary, #3b82f6);
427
+ color: var(--chain-ai-primary, #3b82f6);
428
+ }
429
+
430
+ .chain-ai-action-prompt-input {
431
+ padding: 10px 12px;
432
+ border: 1px solid var(--chain-ai-border, #e5e7eb);
433
+ border-radius: 8px;
434
+ font-size: 14px;
435
+ background: var(--chain-ai-bg, #ffffff);
436
+ color: var(--chain-ai-text, #1f2937);
437
+ outline: none;
438
+ transition: border-color 0.15s, box-shadow 0.15s;
439
+ }
440
+
441
+ .chain-ai-action-prompt-input:focus {
442
+ border-color: var(--chain-ai-primary, #3b82f6);
443
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
444
+ }
445
+
446
+ .chain-ai-action-prompt-input::placeholder {
447
+ color: #9ca3af;
448
+ }
449
+
450
+ .chain-ai-action-prompt-submit {
451
+ padding: 12px 16px;
452
+ border: none;
453
+ border-radius: 8px;
454
+ font-size: 14px;
455
+ font-weight: 500;
456
+ cursor: pointer;
457
+ transition: all 0.15s;
458
+ margin-top: 4px;
459
+ }
460
+
461
+ .chain-ai-action-prompt-submit:hover:not(:disabled) {
462
+ opacity: 0.9;
463
+ }
464
+
465
+ .chain-ai-action-prompt-submit:disabled {
466
+ opacity: 0.5;
467
+ cursor: not-allowed;
468
+ }
469
+
470
+ /* Dark mode support via data attribute or class */
471
+ .chain-ai-widget[data-theme="dark"],
472
+ .chain-ai-widget.dark {
473
+ --chain-ai-bg: #1f2937;
474
+ --chain-ai-text: #f9fafb;
475
+ --chain-ai-border: #374151;
476
+ --chain-ai-assistant-bg: #374151;
477
+ --chain-ai-assistant-text: #f9fafb;
478
+ }
479
+
480
+ /* Mobile responsive */
481
+ @media (max-width: 480px) {
482
+ .chain-ai-widget-window {
483
+ width: calc(100vw - 20px);
484
+ height: calc(100vh - 100px);
485
+ bottom: calc(var(--chain-ai-fab-size, 56px) + 14px);
486
+ right: -10px;
487
+ border-radius: var(--chain-ai-window-radius, 12px);
488
+ }
489
+ }
490
+
491
+ /* Logo in header */
492
+ .chain-ai-widget-logo {
493
+ display: flex;
494
+ align-items: center;
495
+ justify-content: center;
496
+ }
497
+
498
+ .chain-ai-widget-logo img {
499
+ max-height: 28px;
500
+ width: auto;
501
+ }
502
+
503
+ /* Powered by badge */
504
+ .chain-ai-widget-powered-by {
505
+ padding: 8px 16px;
506
+ text-align: center;
507
+ font-size: 11px;
508
+ color: #9ca3af;
509
+ border-top: 1px solid var(--chain-ai-border, #e5e7eb);
510
+ background: var(--chain-ai-bg, #ffffff);
511
+ }
512
+
513
+ .chain-ai-widget-powered-by a {
514
+ color: var(--chain-ai-primary, #3b82f6);
515
+ text-decoration: none;
516
+ font-weight: 500;
517
+ }
518
+
519
+ .chain-ai-widget-powered-by a:hover {
520
+ text-decoration: underline;
521
+ }
522
+
523
+ /* Custom header support */
524
+ .chain-ai-widget-header-custom {
525
+ padding: 12px 16px;
526
+ }
527
+
528
+ /* Custom welcome support */
529
+ .chain-ai-widget-welcome-custom {
530
+ padding: 16px;
531
+ }
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@chainai/react",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "React components for Chain AI - Embeddable blockchain AI assistant widget",
5
5
  "main": "dist/index.js",
6
- "module": "dist/index.esm.js",
7
6
  "types": "dist/index.d.ts",
8
7
  "sideEffects": [
9
8
  "**/*.css"
@@ -23,7 +22,7 @@
23
22
  },
24
23
  "scripts": {
25
24
  "build": "tsc && npm run copy-styles",
26
- "copy-styles": "mkdir -p styles && cp src/styles/*.css styles/",
25
+ "copy-styles": "mkdir -p styles && cp src/styles/*.css styles/ && mkdir -p dist/styles && cp src/styles/*.css dist/styles/",
27
26
  "dev": "tsc --watch",
28
27
  "test": "jest",
29
28
  "lint": "eslint src --ext .ts,.tsx",
@@ -45,7 +44,7 @@
45
44
  "author": "Chain AI",
46
45
  "license": "MIT",
47
46
  "dependencies": {
48
- "@chainai/core": "^1.0.0"
47
+ "@chainai/core": "^1.0.2"
49
48
  },
50
49
  "devDependencies": {
51
50
  "@types/react": "^18.3.3",