@chainai/react 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.
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ /**
3
+ * ChainAIWidget - Fully customizable floating chat widget
4
+ *
5
+ * Features:
6
+ * - Floating action button (FAB) that expands to chat
7
+ * - Full branding customization (logo, colors, text)
8
+ * - CSS variables for easy styling
9
+ * - Works in any context (web, extension, mobile)
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.ChainAIWidget = void 0;
46
+ const react_1 = __importStar(require("react"));
47
+ const ChainAIProvider_1 = require("../context/ChainAIProvider");
48
+ const useChat_1 = require("../hooks/useChat");
49
+ const ChatMessage_1 = require("./ChatMessage");
50
+ const ActionPrompt_1 = require("./ActionPrompt");
51
+ const themes_1 = require("../styles/themes");
52
+ require("../styles/widget.css");
53
+ // Default icons
54
+ const DefaultChatIcon = () => (react_1.default.createElement("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
55
+ react_1.default.createElement("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })));
56
+ const DefaultCloseIcon = () => (react_1.default.createElement("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
57
+ react_1.default.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
58
+ react_1.default.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })));
59
+ const DefaultSendIcon = () => (react_1.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" },
60
+ react_1.default.createElement("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
61
+ react_1.default.createElement("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })));
62
+ const Avatar = ({ branding, size = 'medium', className = '' }) => {
63
+ const sizeMap = { small: 28, medium: 36, large: 48 };
64
+ const iconSizeMap = { small: 14, medium: 20, large: 24 };
65
+ const px = sizeMap[size];
66
+ const iconPx = iconSizeMap[size];
67
+ const gradient = branding?.avatarGradient || ['#3b82f6', '#8b5cf6'];
68
+ const gradientStyle = `linear-gradient(135deg, ${gradient[0]}, ${gradient[1]})`;
69
+ // If avatar is a string (URL), render as image
70
+ if (typeof branding?.avatar === 'string') {
71
+ return (react_1.default.createElement("div", { className: `chain-ai-widget-avatar ${className}`, style: { width: px, height: px } },
72
+ react_1.default.createElement("img", { src: branding.avatar, alt: "Assistant", style: { width: '100%', height: '100%', borderRadius: '50%', objectFit: 'cover' } })));
73
+ }
74
+ // If avatar is a React node, render it
75
+ if (branding?.avatar) {
76
+ return (react_1.default.createElement("div", { className: `chain-ai-widget-avatar ${className}`, style: { width: px, height: px, background: gradientStyle } }, branding.avatar));
77
+ }
78
+ // Default avatar
79
+ return (react_1.default.createElement("div", { className: `chain-ai-widget-avatar ${className}`, style: { width: px, height: px, background: gradientStyle } },
80
+ react_1.default.createElement("svg", { width: iconPx, height: iconPx, viewBox: "0 0 24 24", fill: "currentColor" },
81
+ react_1.default.createElement("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" }))));
82
+ };
83
+ const Logo = ({ branding }) => {
84
+ // If logo is a string (URL), render as image
85
+ if (typeof branding?.logo === 'string') {
86
+ return (react_1.default.createElement("img", { src: branding.logo, alt: branding?.name || 'Logo', className: "chain-ai-widget-logo", style: { height: 28, width: 'auto', objectFit: 'contain' } }));
87
+ }
88
+ // If logo is a React node, render it
89
+ if (branding?.logo) {
90
+ return react_1.default.createElement("div", { className: "chain-ai-widget-logo" }, branding.logo);
91
+ }
92
+ // Default: use avatar as logo
93
+ return react_1.default.createElement(Avatar, { branding: branding, size: "medium" });
94
+ };
95
+ const ChainAIWidgetInner = ({ branding = {}, dimensions = {}, defaultOpen = false, position = 'bottom-right', customPosition, theme: customTheme, className = '', placeholder = 'Ask me anything...', zIndex = 9999, onToggle, onMessage, }) => {
96
+ const [isOpen, setIsOpen] = (0, react_1.useState)(defaultOpen);
97
+ const [input, setInput] = (0, react_1.useState)('');
98
+ const [pendingAction, setPendingAction] = (0, react_1.useState)(null);
99
+ const messagesEndRef = (0, react_1.useRef)(null);
100
+ const inputRef = (0, react_1.useRef)(null);
101
+ const { isReady } = (0, ChainAIProvider_1.useChainAI)();
102
+ const { messages, isLoading, sendMessage } = (0, useChat_1.useChat)();
103
+ // Merge custom theme with defaults
104
+ const theme = {
105
+ ...themes_1.defaultTheme,
106
+ ...customTheme,
107
+ colors: { ...themes_1.defaultTheme.colors, ...customTheme?.colors },
108
+ fonts: { ...themes_1.defaultTheme.fonts, ...customTheme?.fonts },
109
+ spacing: { ...themes_1.defaultTheme.spacing, ...customTheme?.spacing },
110
+ };
111
+ // Branding defaults (Chain AI branding)
112
+ const { name = 'Chain AI', welcomeTitle = 'Hi! I\'m Chain AI', welcomeMessage = 'Ask me anything about blockchain operations, transactions, or crypto.', welcomeContent, showPoweredBy = false, fabIcon, fabIconOpen, sendIcon, headerContent, avatarGradient = ['#3b82f6', '#8b5cf6'], } = branding;
113
+ // Dimension defaults
114
+ const { fabSize = 56, windowWidth = 380, windowHeight = 520, fabBorderRadius = '50%', windowBorderRadius = 16, offset = 20, } = dimensions;
115
+ // Position styles
116
+ const getPositionStyles = () => {
117
+ if (customPosition) {
118
+ return customPosition;
119
+ }
120
+ const positionMap = {
121
+ 'bottom-right': { bottom: offset, right: offset },
122
+ 'bottom-left': { bottom: offset, left: offset },
123
+ 'top-right': { top: offset, right: offset },
124
+ 'top-left': { top: offset, left: offset },
125
+ };
126
+ return positionMap[position];
127
+ };
128
+ // Auto-scroll to bottom
129
+ (0, react_1.useEffect)(() => {
130
+ if (isOpen) {
131
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
132
+ }
133
+ }, [messages, isOpen]);
134
+ // Focus input when opened
135
+ (0, react_1.useEffect)(() => {
136
+ if (isOpen && inputRef.current) {
137
+ setTimeout(() => inputRef.current?.focus(), 100);
138
+ }
139
+ }, [isOpen]);
140
+ // Check for incomplete actions in messages
141
+ (0, react_1.useEffect)(() => {
142
+ const lastMessage = messages[messages.length - 1];
143
+ if (lastMessage?.role === 'assistant' && lastMessage.content) {
144
+ try {
145
+ const parsed = JSON.parse(lastMessage.content);
146
+ if (parsed.type === 'action' && parsed.status === 'incomplete') {
147
+ setPendingAction(parsed);
148
+ }
149
+ else {
150
+ setPendingAction(null);
151
+ }
152
+ }
153
+ catch {
154
+ setPendingAction(null);
155
+ }
156
+ }
157
+ }, [messages]);
158
+ const handleToggle = () => {
159
+ const newState = !isOpen;
160
+ setIsOpen(newState);
161
+ onToggle?.(newState);
162
+ };
163
+ const handleSend = async () => {
164
+ if (!input.trim() || isLoading)
165
+ return;
166
+ const text = input;
167
+ setInput('');
168
+ onMessage?.(text);
169
+ await sendMessage(text);
170
+ };
171
+ const handleKeyDown = (e) => {
172
+ if (e.key === 'Enter' && !e.shiftKey) {
173
+ e.preventDefault();
174
+ handleSend();
175
+ }
176
+ };
177
+ const handleActionFieldSubmit = (field, value) => {
178
+ sendMessage(`${field}: ${value}`);
179
+ setPendingAction(null);
180
+ };
181
+ // CSS custom properties for theming and dimensions
182
+ const cssVars = {
183
+ '--chain-ai-primary': theme.colors.primary,
184
+ '--chain-ai-primary-text': theme.colors.primaryText,
185
+ '--chain-ai-bg': theme.colors.background,
186
+ '--chain-ai-text': theme.colors.text,
187
+ '--chain-ai-border': theme.colors.border,
188
+ '--chain-ai-user-bg': theme.colors.userMessage,
189
+ '--chain-ai-user-text': theme.colors.userMessageText,
190
+ '--chain-ai-assistant-bg': theme.colors.assistantMessage,
191
+ '--chain-ai-assistant-text': theme.colors.assistantMessageText,
192
+ '--chain-ai-font': theme.fonts.body,
193
+ '--chain-ai-fab-size': typeof fabSize === 'number' ? `${fabSize}px` : fabSize,
194
+ '--chain-ai-fab-radius': typeof fabBorderRadius === 'number' ? `${fabBorderRadius}px` : fabBorderRadius,
195
+ '--chain-ai-window-width': typeof windowWidth === 'number' ? `${windowWidth}px` : windowWidth,
196
+ '--chain-ai-window-height': typeof windowHeight === 'number' ? `${windowHeight}px` : windowHeight,
197
+ '--chain-ai-window-radius': typeof windowBorderRadius === 'number' ? `${windowBorderRadius}px` : windowBorderRadius,
198
+ '--chain-ai-avatar-gradient': `linear-gradient(135deg, ${avatarGradient[0]}, ${avatarGradient[1]})`,
199
+ };
200
+ // Render FAB icon
201
+ const renderFabIcon = () => {
202
+ if (isOpen) {
203
+ return fabIconOpen || react_1.default.createElement(DefaultCloseIcon, null);
204
+ }
205
+ return fabIcon || react_1.default.createElement(DefaultChatIcon, null);
206
+ };
207
+ return (react_1.default.createElement("div", { className: `chain-ai-widget ${className}`, style: { ...getPositionStyles(), zIndex, ...cssVars } },
208
+ isOpen && (react_1.default.createElement("div", { className: "chain-ai-widget-window" },
209
+ headerContent ? (react_1.default.createElement("div", { className: "chain-ai-widget-header chain-ai-widget-header-custom" }, headerContent)) : (react_1.default.createElement("div", { className: "chain-ai-widget-header" },
210
+ react_1.default.createElement("div", { className: "chain-ai-widget-header-info" },
211
+ react_1.default.createElement(Logo, { branding: branding }),
212
+ react_1.default.createElement("span", { className: "chain-ai-widget-title" }, name)),
213
+ react_1.default.createElement("button", { className: "chain-ai-widget-close", onClick: handleToggle, "aria-label": "Close chat" },
214
+ react_1.default.createElement(DefaultCloseIcon, null)))),
215
+ react_1.default.createElement("div", { className: "chain-ai-widget-messages" },
216
+ messages.length === 0 ? (welcomeContent ? (react_1.default.createElement("div", { className: "chain-ai-widget-welcome chain-ai-widget-welcome-custom" }, welcomeContent)) : (react_1.default.createElement("div", { className: "chain-ai-widget-welcome" },
217
+ react_1.default.createElement(Avatar, { branding: branding, size: "large" }),
218
+ react_1.default.createElement("h3", null, welcomeTitle),
219
+ react_1.default.createElement("p", null, welcomeMessage)))) : (messages.map((message) => (react_1.default.createElement("div", { key: message.id, className: `chain-ai-widget-message chain-ai-widget-message-${message.role}` },
220
+ message.role === 'assistant' && (react_1.default.createElement(Avatar, { branding: branding, size: "small" })),
221
+ react_1.default.createElement("div", { className: "chain-ai-widget-message-bubble" },
222
+ react_1.default.createElement(ChatMessage_1.ChatMessage, { message: message, theme: theme })))))),
223
+ isLoading && (react_1.default.createElement("div", { className: "chain-ai-widget-message chain-ai-widget-message-assistant" },
224
+ react_1.default.createElement(Avatar, { branding: branding, size: "small" }),
225
+ react_1.default.createElement("div", { className: "chain-ai-widget-typing" },
226
+ react_1.default.createElement("span", null),
227
+ react_1.default.createElement("span", null),
228
+ react_1.default.createElement("span", null)))),
229
+ pendingAction && (react_1.default.createElement(ActionPrompt_1.ActionPrompt, { action: pendingAction.action, missing: pendingAction.missing, prompt: pendingAction.prompt, onSubmit: handleActionFieldSubmit, theme: theme })),
230
+ react_1.default.createElement("div", { ref: messagesEndRef })),
231
+ react_1.default.createElement("div", { className: "chain-ai-widget-input-area" },
232
+ react_1.default.createElement("input", { ref: inputRef, type: "text", className: "chain-ai-widget-input", value: input, onChange: (e) => setInput(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: !isReady || isLoading }),
233
+ react_1.default.createElement("button", { className: "chain-ai-widget-send", onClick: handleSend, disabled: !input.trim() || isLoading, "aria-label": "Send message" }, sendIcon || react_1.default.createElement(DefaultSendIcon, null))),
234
+ showPoweredBy && (react_1.default.createElement("div", { className: "chain-ai-widget-powered-by" },
235
+ "Powered by ",
236
+ react_1.default.createElement("a", { href: "https://chain-ai.io", target: "_blank", rel: "noopener noreferrer" }, "Chain AI"))))),
237
+ react_1.default.createElement("button", { className: `chain-ai-widget-fab ${isOpen ? 'chain-ai-widget-fab-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? 'Close chat' : 'Open chat' }, renderFabIcon())));
238
+ };
239
+ const ChainAIWidget = ({ config, ...props }) => {
240
+ return (react_1.default.createElement(ChainAIProvider_1.ChainAIProvider, { config: config },
241
+ react_1.default.createElement(ChainAIWidgetInner, { ...props })));
242
+ };
243
+ exports.ChainAIWidget = ChainAIWidget;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * ChatHeader - Header bar for chat component
3
+ */
4
+ import React from 'react';
5
+ import type { Theme } from '../styles/themes';
6
+ export interface ChatHeaderProps {
7
+ title: string;
8
+ theme: Theme;
9
+ onClose?: () => void;
10
+ }
11
+ export declare const ChatHeader: React.FC<ChatHeaderProps>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * ChatHeader - Header bar for chat component
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ChatHeader = void 0;
10
+ const react_1 = __importDefault(require("react"));
11
+ const ChatHeader = ({ title, theme, onClose }) => {
12
+ return (react_1.default.createElement("div", { className: "chain-ai-header", style: {
13
+ backgroundColor: theme.colors.headerBackground,
14
+ color: theme.colors.headerText,
15
+ borderBottomColor: theme.colors.border,
16
+ } },
17
+ react_1.default.createElement("h3", { className: "chain-ai-header-title" }, title),
18
+ onClose && (react_1.default.createElement("button", { className: "chain-ai-header-close", onClick: onClose }, "\u00D7"))));
19
+ };
20
+ exports.ChatHeader = ChatHeader;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * ChatInput - Input field and send button for chat
3
+ */
4
+ import React from 'react';
5
+ import type { Theme } from '../styles/themes';
6
+ export interface ChatInputProps {
7
+ onSend: (text: string) => void;
8
+ placeholder?: string;
9
+ disabled?: boolean;
10
+ theme: Theme;
11
+ }
12
+ export declare const ChatInput: React.FC<ChatInputProps>;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ /**
3
+ * ChatInput - Input field and send button for chat
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ChatInput = void 0;
40
+ const react_1 = __importStar(require("react"));
41
+ const ChatInput = ({ onSend, placeholder = 'Type a message...', disabled = false, theme, }) => {
42
+ const [input, setInput] = (0, react_1.useState)('');
43
+ const handleSend = () => {
44
+ if (input.trim() && !disabled) {
45
+ onSend(input);
46
+ setInput('');
47
+ }
48
+ };
49
+ const handleKeyDown = (e) => {
50
+ if (e.key === 'Enter' && !e.shiftKey) {
51
+ e.preventDefault();
52
+ handleSend();
53
+ }
54
+ };
55
+ return (react_1.default.createElement("div", { className: "chain-ai-input-container", style: { borderColor: theme.colors.border } },
56
+ react_1.default.createElement("input", { type: "text", className: "chain-ai-input", value: input, onChange: (e) => setInput(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, style: {
57
+ backgroundColor: theme.colors.inputBackground,
58
+ color: theme.colors.text,
59
+ } }),
60
+ react_1.default.createElement("button", { className: "chain-ai-send-button", onClick: handleSend, disabled: disabled || !input.trim(), style: {
61
+ backgroundColor: theme.colors.primary,
62
+ color: theme.colors.primaryText,
63
+ } }, "Send")));
64
+ };
65
+ exports.ChatInput = ChatInput;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * ChatMessage - Displays a single chat message
3
+ */
4
+ import React from 'react';
5
+ import type { Message } from '@chainai/core';
6
+ import type { Theme } from '../styles/themes';
7
+ export interface ChatMessageProps {
8
+ message: Message;
9
+ theme: Theme;
10
+ }
11
+ export declare const ChatMessage: React.FC<ChatMessageProps>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * ChatMessage - Displays a single chat message
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ChatMessage = void 0;
10
+ const react_1 = __importDefault(require("react"));
11
+ const ChatMessage = ({ message, theme }) => {
12
+ const isUser = message.role === 'user';
13
+ return (react_1.default.createElement("div", { className: `chain-ai-message ${isUser ? 'chain-ai-message-user' : 'chain-ai-message-assistant'}`, style: {
14
+ backgroundColor: isUser ? theme.colors.userMessage : theme.colors.assistantMessage,
15
+ color: isUser ? theme.colors.userMessageText : theme.colors.assistantMessageText,
16
+ } },
17
+ react_1.default.createElement("div", { className: "chain-ai-message-content" }, message.content),
18
+ react_1.default.createElement("div", { className: "chain-ai-message-timestamp" }, new Date(message.timestamp).toLocaleTimeString())));
19
+ };
20
+ exports.ChatMessage = ChatMessage;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * ChainAIProvider - Context provider for Chain AI client
3
+ */
4
+ import React, { ReactNode } from 'react';
5
+ import { ChainAIClient } from '@chainai/core';
6
+ import type { ChainAIConfig, ResponseCustomization } from '@chainai/core';
7
+ export interface ChainAIContextValue {
8
+ client: ChainAIClient | null;
9
+ isReady: boolean;
10
+ error: string | null;
11
+ customization: ResponseCustomization | null;
12
+ updateCustomization: (customization: Partial<ResponseCustomization>) => Promise<void>;
13
+ }
14
+ export interface ChainAIProviderProps {
15
+ config: ChainAIConfig;
16
+ children: ReactNode;
17
+ }
18
+ export declare const ChainAIProvider: React.FC<ChainAIProviderProps>;
19
+ export declare const useChainAI: () => ChainAIContextValue;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * ChainAIProvider - Context provider for Chain AI client
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.useChainAI = exports.ChainAIProvider = void 0;
40
+ const react_1 = __importStar(require("react"));
41
+ const core_1 = require("@chainai/core");
42
+ const ChainAIContext = (0, react_1.createContext)(undefined);
43
+ const ChainAIProvider = ({ config, children }) => {
44
+ const [client, setClient] = (0, react_1.useState)(null);
45
+ const [isReady, setIsReady] = (0, react_1.useState)(false);
46
+ const [error, setError] = (0, react_1.useState)(null);
47
+ const [customization, setCustomization] = (0, react_1.useState)(null);
48
+ (0, react_1.useEffect)(() => {
49
+ const initializeClient = async () => {
50
+ try {
51
+ const newClient = new core_1.ChainAIClient(config);
52
+ // Validate API key
53
+ const validation = await newClient.validateApiKey();
54
+ if (!validation.ok) {
55
+ setError(validation.error || 'API key validation failed');
56
+ return;
57
+ }
58
+ // Fetch customization
59
+ const custom = await newClient.getCustomization();
60
+ setCustomization(custom);
61
+ setClient(newClient);
62
+ setIsReady(true);
63
+ }
64
+ catch (err) {
65
+ setError(err instanceof Error ? err.message : 'Failed to initialize Chain AI client');
66
+ }
67
+ };
68
+ initializeClient();
69
+ }, [config]);
70
+ const updateCustomization = async (newCustomization) => {
71
+ if (!client) {
72
+ throw new Error('Client not initialized');
73
+ }
74
+ await client.updateCustomization(newCustomization);
75
+ const updated = await client.getCustomization();
76
+ setCustomization(updated);
77
+ };
78
+ const value = {
79
+ client,
80
+ isReady,
81
+ error,
82
+ customization,
83
+ updateCustomization,
84
+ };
85
+ return react_1.default.createElement(ChainAIContext.Provider, { value: value }, children);
86
+ };
87
+ exports.ChainAIProvider = ChainAIProvider;
88
+ const useChainAI = () => {
89
+ const context = (0, react_1.useContext)(ChainAIContext);
90
+ if (!context) {
91
+ throw new Error('useChainAI must be used within a ChainAIProvider');
92
+ }
93
+ return context;
94
+ };
95
+ exports.useChainAI = useChainAI;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * useChat hook - Manages chat messages and state
3
+ */
4
+ import type { Message } from '@chainai/core';
5
+ export interface UseChatReturn {
6
+ messages: Message[];
7
+ isLoading: boolean;
8
+ error: string | null;
9
+ sendMessage: (text: string, userContext?: any) => Promise<void>;
10
+ clearMessages: () => void;
11
+ }
12
+ export declare const useChat: (conversationId?: string) => UseChatReturn;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * useChat hook - Manages chat messages and state
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useChat = void 0;
7
+ const react_1 = require("react");
8
+ const ChainAIProvider_1 = require("../context/ChainAIProvider");
9
+ const useChat = (conversationId) => {
10
+ const { client, isReady } = (0, ChainAIProvider_1.useChainAI)();
11
+ const [messages, setMessages] = (0, react_1.useState)([]);
12
+ const [isLoading, setIsLoading] = (0, react_1.useState)(false);
13
+ const [error, setError] = (0, react_1.useState)(null);
14
+ const sendMessage = (0, react_1.useCallback)(async (text, userContext) => {
15
+ if (!client || !isReady) {
16
+ setError('Client not ready');
17
+ return;
18
+ }
19
+ // Add user message
20
+ const userMessage = {
21
+ id: Date.now().toString(),
22
+ role: 'user',
23
+ content: text,
24
+ timestamp: Date.now(),
25
+ };
26
+ setMessages((prev) => [...prev, userMessage]);
27
+ setIsLoading(true);
28
+ setError(null);
29
+ try {
30
+ let assistantResponse = '';
31
+ const assistantMessage = {
32
+ id: (Date.now() + 1).toString(),
33
+ role: 'assistant',
34
+ content: '',
35
+ timestamp: Date.now(),
36
+ };
37
+ setMessages((prev) => [...prev, assistantMessage]);
38
+ await client.streamChat({
39
+ text,
40
+ conversationId: conversationId || 'default',
41
+ userContext,
42
+ }, {
43
+ onChunk: (chunk) => {
44
+ assistantResponse += chunk;
45
+ setMessages((prev) => {
46
+ const updated = [...prev];
47
+ const lastMsg = updated[updated.length - 1];
48
+ if (lastMsg && lastMsg.role === 'assistant') {
49
+ lastMsg.content = assistantResponse;
50
+ }
51
+ return updated;
52
+ });
53
+ },
54
+ onDone: () => {
55
+ setIsLoading(false);
56
+ },
57
+ onError: (err) => {
58
+ setError(err);
59
+ setIsLoading(false);
60
+ },
61
+ });
62
+ }
63
+ catch (err) {
64
+ setError(err instanceof Error ? err.message : 'An error occurred');
65
+ setIsLoading(false);
66
+ }
67
+ }, [client, isReady, conversationId]);
68
+ const clearMessages = (0, react_1.useCallback)(() => {
69
+ setMessages([]);
70
+ setError(null);
71
+ }, []);
72
+ return {
73
+ messages,
74
+ isLoading,
75
+ error,
76
+ sendMessage,
77
+ clearMessages,
78
+ };
79
+ };
80
+ exports.useChat = useChat;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @chain-ai/react - React components for Chain AI
3
+ *
4
+ * Embeddable blockchain AI assistant components
5
+ */
6
+ export { ChainAI } from './components/ChainAI';
7
+ export type { ChainAIProps } from './components/ChainAI';
8
+ export { ChainAIWidget } from './components/ChainAIWidget';
9
+ export type { ChainAIWidgetProps, BrandingConfig, DimensionConfig } from './components/ChainAIWidget';
10
+ export { ChatMessage } from './components/ChatMessage';
11
+ export type { ChatMessageProps } from './components/ChatMessage';
12
+ export { ChatInput } from './components/ChatInput';
13
+ export type { ChatInputProps } from './components/ChatInput';
14
+ export { ChatHeader } from './components/ChatHeader';
15
+ export type { ChatHeaderProps } from './components/ChatHeader';
16
+ export { ActionPrompt } from './components/ActionPrompt';
17
+ export type { ActionPromptProps } from './components/ActionPrompt';
18
+ export { ChainAIProvider, useChainAI } from './context/ChainAIProvider';
19
+ export type { ChainAIContextValue, ChainAIProviderProps } from './context/ChainAIProvider';
20
+ export { useChat } from './hooks/useChat';
21
+ export type { UseChatReturn } from './hooks/useChat';
22
+ export { defaultTheme, darkTheme, lightTheme } from './styles/themes';
23
+ export type { Theme } from './styles/themes';
24
+ export type { ChainAIConfig, ResponseCustomization, ResponseStyle, ResponseLength, Message, } from '@chainai/core';